From bbc73c4a68699eee084bb8c419f4629e25b08377 Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Fri, 2 Aug 2024 17:55:21 -0400 Subject: [PATCH] New renderer going great! --- renderer2/hrend/math.go | 9 ++-- renderer2/hrend/render.go | 11 +---- renderer2/main.go | 98 +++++++++++++++++++++++++++++++++------ 3 files changed, 90 insertions(+), 28 deletions(-) diff --git a/renderer2/hrend/math.go b/renderer2/hrend/math.go index b84d40a..d6ec19c 100644 --- a/renderer2/hrend/math.go +++ b/renderer2/hrend/math.go @@ -134,6 +134,12 @@ func (m *Mat44f) SetTranslation(x, y, z float32) { m.Set(2, 3, z) // Get farther away from the face (user) } +func (m *Mat44f) ScaleSelf(scale float32) { + m.Set(0, 0, m.Get(0, 0)*scale) + m.Set(1, 1, m.Get(1, 1)*scale) + m.Set(2, 2, m.Get(2, 2)*scale) +} + func (m *Mat44f) SetRotationX(radang float32) { m.SetIdentity() m[5] = float32(math.Cos(float64(radang))) @@ -168,9 +174,6 @@ func (m *Mat44f) SetCamera(loc *Vec3f, yaw float32, pitch float32, up *Vec3f) Ve Y: float32(math.Cos(float64(pitch))), } m.SetLookAt(loc, loc.Add(&lookvec), up) - //m.Set(0, 0, m.Get(0, 0)*scale) - //m.Set(1, 1, m.Get(1, 1)*scale) - //m.Set(2, 2, m.Get(2, 2)*scale) return lookvec } diff --git a/renderer2/hrend/render.go b/renderer2/hrend/render.go index 97ded37..d27da2b 100644 --- a/renderer2/hrend/render.go +++ b/renderer2/hrend/render.go @@ -50,7 +50,7 @@ func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) v2 := v2f.ToVec2i() r, g, b := Uint2Col(color) boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2) - if boundsBR.Y < 0 || boundsBR.X < 0 || boundsTL.X >= int(fb.Width) || boundsTL.Y >= int(fb.Height) { + if boundsBR.X < 0 || boundsBR.Y < 0 || boundsTL.X >= int(fb.Width) || boundsTL.Y >= int(fb.Height) { return } if boundsTL.Y < 0 { @@ -68,11 +68,6 @@ func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) // Where to start our scanning pstart := Vec2i{boundsTL.X, boundsTL.Y} parea := EdgeFunctioni(v0, v1, v2) - // if parea < 0 { - // v1, v2 = v2, v1 - // v1f, v2f = v2f, v1f - // parea = EdgeFunctioni(v0, v1, v2) - // } invarea := 1 / float32(parea) w0_y := EdgeFunctioni(v1, v2, pstart) w1_y := EdgeFunctioni(v2, v0, pstart) @@ -87,18 +82,14 @@ func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) w2 := w2_y for x := uint(boundsTL.X); x <= uint(boundsBR.X); x++ { if (w0 | w1 | w2) >= 0 { - //fb.Data[di] = color - //done = true w0a := float32(w0) * invarea w1a := float32(w1) * invarea w2a := float32(w2) * invarea pz := w0a*v0f.Z + w1a*v1f.Z + w2a*v2f.Z if pz < fb.ZBuffer[x+y*fb.Width] { - //log.Print(pz) fb.ZBuffer[x+y*fb.Width] = pz fb.Data.Set(x, y, r, g, b) } - // fb.Set(x, y, Col2Uint(byte(255*w0a), byte(255*w1a), byte(255*w2a))) } w0 += w0_xi w1 += w1_xi diff --git a/renderer2/main.go b/renderer2/main.go index 32dcae8..e8ac18d 100644 --- a/renderer2/main.go +++ b/renderer2/main.go @@ -3,11 +3,12 @@ package main import ( "flag" "fmt" - //"image" + "image" "image/color" "log" "math" "os" + "path/filepath" "renderer2/hrend" "runtime/pprof" // For performance profiling (unnecessary) "time" @@ -33,6 +34,47 @@ func must(err error) { } } +type ObjectDef struct { + Model *hrend.ObjModel + Texture hrend.Framebuffer // This needs to go somewhere else eventually! + Pos hrend.Vec3f + LookVec hrend.Vec3f + Scale float32 + //Transform hrend.Mat44f +} + +func NewObjectDef(model *hrend.ObjModel, texture hrend.Framebuffer) *ObjectDef { + result := ObjectDef{ + Model: model, + Texture: texture, + LookVec: hrend.Vec3f{X: 0, Y: 0, Z: -1}, + Scale: 1, + } + //result.Transform.SetIdentity() + return &result +} + +func loadObject(name string) (*hrend.ObjModel, hrend.Framebuffer) { + ofile := filepath.Join("../", name+".obj") + tfile := filepath.Join("../", name+".jpg") + log.Printf("Loading obj %s, texture %s", ofile, tfile) + + of, err := os.Open(ofile) + must(err) + defer of.Close() + o, err := hrend.ParseObj(of) + must(err) + + jf, err := os.Open(tfile) + must(err) + defer jf.Close() + timg, _, err := image.Decode(jf) + must(err) + texture := hrend.NewTexture(timg, 4) + + return o, texture +} + // func loadDefault() (*hrend.ObjModel, hrend.Framebuffer) { // log.Printf("Loading obj %s, texture %s", ObjectFile, TextureFile) // @@ -63,6 +105,7 @@ var zofs = flag.Float64("zofs", 0, "starting z-offset") var yofs = flag.Float64("yofs", 0.5, "starting y-offset") var fov = flag.Float64("fov", 90, "the horizontal fov") var fps = flag.Int("fps", 60, "fps to run (realtime only)") +var minlight = flag.Float64("minlight", 0.5, "Minimum light level") // var renderconfig = flag.String("renderconfig", "", "if set, rendering is written out") @@ -158,6 +201,21 @@ func main() { wtex := hrend.NewTexture(wtexraw, 1) world := FlatTerrain(10) + // Some static models we could put in the scene + modnames := []string{"head", "diablo"} + models := make([]*hrend.ObjModel, len(modnames)) + textures := make([]hrend.Framebuffer, len(modnames)) + for i, name := range modnames { + models[i], textures[i] = loadObject(name) + } + + // And the actual objects for the scene. We also put the world in there + objects := make([]*ObjectDef, 0) + objects = append(objects, NewObjectDef(world, wtex)) + objects = append(objects, NewObjectDef(models[1], textures[1])) + objects[1].Pos.Y += 1 + objects[1].Pos.Z -= 2 + // These don't really change var projection, viewport hrend.Mat44f projection.SetProjection(float32(*fov), float32(Width)/float32(Height), NearClip, FarClip) @@ -167,6 +225,8 @@ func main() { var newcamtrans hrend.Vec3f camtrans := hrend.Vec3f{X: float32(*xofs), Y: float32(*yofs), Z: float32(*zofs)} camup := hrend.Vec3f{X: 0, Y: 1, Z: 0} + lightang := -math.Pi / 4 // Angle offset from "straight down" + light := hrend.Vec3f{X: 0, Y: float32(-math.Cos(lightang)), Z: float32(math.Sin(lightang))} // In our system, 0 degree yaw is facing -Z, into the scene yaw := float32(0) @@ -191,21 +251,29 @@ func main() { } var sc [3]hrend.Vertex - for _, f := range world.Faces { - for i := range 3 { - sc[i] = f[i] - sc[i].Pos = screenmat.MultiplyPoint3(f[i].Pos) + var modelmat hrend.Mat44f + for _, o := range objects { + // Create the final matrix + modelmat.SetLookAt(&o.Pos, o.Pos.Add(&o.LookVec), &camup) + matrix3d := modelmat.Multiply(screenmat) + //matrix3d.ScaleSelf(o.Scale) + for _, f := range o.Model.Faces { + for i := range 3 { + sc[i] = f[i] + sc[i].Pos = matrix3d.MultiplyPoint3(f[i].Pos) + } + l1 := f[2].Pos.Sub(&f[0].Pos) + n := l1.CrossProduct(f[1].Pos.Sub(&f[0].Pos)) + n = n.Normalize() + // light = lookvec + intensity := n.MultSimp(&light) + if intensity < 0 { + intensity = 0 + } + intensity = (intensity + float32(*minlight)) / (1 + float32(*minlight)) + hrend.TriangleTextured(&rb, o.Texture, intensity, sc[0], sc[1], sc[2]) + //hrend.TriangleFlat(&rb, hrend.Col2Uint(byte(255*intensity), byte(255*intensity), byte(255*intensity)), sc[0].Pos, sc[1].Pos, sc[2].Pos) } - - // l1 := f[2].Pos.Sub(&f[0].Pos) - // n := l1.CrossProduct(f[1].Pos.Sub(&f[0].Pos)) - // n = n.Normalize() - // intensity := n.MultSimp(&lookvec) - // if intensity < 0 { - // intensity = 0 - // } - hrend.TriangleTextured(&rb, wtex, 1.0, sc[0], sc[1], sc[2]) - //hrend.TriangleFlat(&rb, hrend.Col2Uint(byte(255*intensity), byte(255*intensity), byte(255*intensity)), sc[0].Pos, sc[1].Pos, sc[2].Pos) } timer.Add(time.Since(start), 10)