From 47b0428ed2e1194c3277ae484b9c0fb55840ad47 Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Fri, 2 Aug 2024 22:53:21 -0400 Subject: [PATCH] really really broken --- renderer2/generation.go | 4 +-- renderer2/hrend/math.go | 55 +++++++++++++++++++------------- renderer2/hrend/render.go | 66 +++++++++++++++++++++++++++++++++------ renderer2/main.go | 50 +++++++++++++++++++++-------- 4 files changed, 128 insertions(+), 47 deletions(-) diff --git a/renderer2/generation.go b/renderer2/generation.go index 923d981..873f90c 100644 --- a/renderer2/generation.go +++ b/renderer2/generation.go @@ -79,8 +79,8 @@ func Skybox() *hrend.ObjModel { v[7] = hrend.Vec3f{X: float32(-1), Y: float32(1), Z: float32(1)} // These are our 12 faces fv := [][3]int{ - {0, 1, 2}, // bottom - {2, 3, 0}, + {0, 2, 1}, // bottom + {1, 2, 3}, {4, 5, 6}, // top {6, 7, 4}, {0, 1, 5}, // south diff --git a/renderer2/hrend/math.go b/renderer2/hrend/math.go index d6ec19c..972aaf7 100644 --- a/renderer2/hrend/math.go +++ b/renderer2/hrend/math.go @@ -110,6 +110,15 @@ func (m *Mat44f) SetProjection(fov float32, aspect float32, near float32, far fl // OK apparently I suck, let's use somebody else's projection matrix: m.ZeroFill() + // fov = fov / 180 * math.Pi // Convert to radians + // e := float32(1 / math.Tan(float64(fov/2))) + + // m.Set(0, 0, e/aspect) + // m.Set(1, 1, e) + // m.Set(2, 2, (far+near)/(near-far)) + // m.Set(2, 3, 2*far*near/(near-far)) + // m.Set(3, 2, -1) // Might need to be swapped + DEG2RAD := math.Acos(-1.0) / 180.0 tangent := math.Tan(float64(fov/2.0) * DEG2RAD) // tangent of half fovY top := near * float32(tangent) // half height of near plane @@ -123,8 +132,31 @@ func (m *Mat44f) SetProjection(fov float32, aspect float32, near float32, far fl m.Set(0, 0, near/right) m.Set(1, 1, near/top) m.Set(2, 2, -(far+near)/(far-near)) + //m.Set(2, 2, -(far)/(far-near)) m.Set(3, 2, -1) m.Set(2, 3, -(2*far*near)/(far-near)) + //m.Set(2, 3, -(far*near)/(far-near)) +} + +func (m *Mat44f) SetViewport(tl Vec3f, br Vec3f) { //width, height, depth int) { + m.ZeroFill() + m.Set(0, 0, (br.X-tl.X)/2) + m.Set(1, 1, (tl.Y-br.Y)/2) // Inverted because screen funny + m.Set(2, 2, 1) //(br.Z-tl.Z)/2) + m.Set(3, 3, 1) + m.Set(0, 3, (br.X+tl.X)/2) + m.Set(1, 3, (br.Y+tl.Y)/2) + //m.Set(2, 3, (br.Z+tl.Z)/2) +} + +func (m *Mat44f) SetViewportSimple(width, height, depth int) { + var tl Vec3f // All zero + br := Vec3f{ + X: float32(width), + Y: float32(height), + Z: float32(depth), + } + m.SetViewport(tl, br) } func (m *Mat44f) SetTranslation(x, y, z float32) { @@ -198,27 +230,6 @@ func (m *Mat44f) SetLookAt(from *Vec3f, to *Vec3f, up *Vec3f) { m.Set(2, 3, from.Z) } -func (m *Mat44f) SetViewport(tl Vec3f, br Vec3f) { //width, height, depth int) { - m.ZeroFill() - m.Set(0, 0, (br.X-tl.X)/2) - m.Set(1, 1, (tl.Y-br.Y)/2) // Inverted because screen funny - m.Set(2, 2, (br.Z-tl.Z)/2) - m.Set(3, 3, 1) - m.Set(0, 3, (br.X+tl.X)/2) - m.Set(1, 3, (br.Y+tl.Y)/2) - m.Set(2, 3, (br.Z+tl.Z)/2) -} - -func (m *Mat44f) SetViewportSimple(width, height, depth int) { - var tl Vec3f // All zero - br := Vec3f{ - X: float32(width), - Y: float32(height), - Z: float32(depth), - } - m.SetViewport(tl, br) -} - // Multiply the given point by our vector. Remember this is row-major order func (m *Mat44f) MultiplyPoint3(p Vec3f) Vec3f { var out Vec3f @@ -316,7 +327,7 @@ func (v0 *Vec3f) MultSimp(v1 *Vec3f) float32 { return v0.X*v1.X + v0.Y*v1.Y + v0.Z*v1.Z } -func Clamp(v, minv, maxv float32) float32 { +func Clamp[t float32 | int](v, minv, maxv t) t { if v < minv { return minv } else if v > maxv { diff --git a/renderer2/hrend/render.go b/renderer2/hrend/render.go index d27da2b..374a13b 100644 --- a/renderer2/hrend/render.go +++ b/renderer2/hrend/render.go @@ -12,15 +12,20 @@ func ComputeBoundingBox(v0, v1, v2 Vec2i) (Vec2i, Vec2i) { Vec2i{max(v0.X, v1.X, v2.X), max(v0.Y, v1.Y, v2.Y)} } +func ComputeBoundingBoxF(v0, v1, v2 Vec3f) (Vec3f, Vec3f) { + return Vec3f{min(v0.X, v1.X, v2.X), min(v0.Y, v1.Y, v2.Y), min(v0.Z, v1.Z, v2.Z)}, + Vec3f{max(v0.X, v1.X, v2.X), max(v0.Y, v1.Y, v2.Y), max(v0.Z, v1.Z, v2.Z)} +} + // The generic edge function, returning positive if P is on the right side of // the line drawn between v1 and v2. This is counter clockwise -func EdgeFunction(v1, v2, p Vec2f) float32 { +func EdgeFunction(v1, v2, p Vec3f) float32 { return (p.X-v1.X)*(v2.Y-v1.Y) - (p.Y-v1.Y)*(v2.X-v1.X) } // This computes the x and y per-pixel increment for the line going // between v1 and v2 (also counter clockwise) -func EdgeIncrement(v1, v2 Vec2f) (float32, float32) { +func EdgeIncrement(v1, v2 Vec3f) (float32, float32) { return (v2.Y - v1.Y), -(v2.X - v1.X) } @@ -38,7 +43,7 @@ func EdgeIncrementi(v1, v2 Vec2i) (int, int) { func ZClip(v0f Vec3f, v1f Vec3f, v2f Vec3f) bool { maxz := max(v0f.Z, v1f.Z, v2f.Z) - return maxz < 0 || maxz > 1 + return maxz < -1 || maxz > 1 } func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) { @@ -102,21 +107,42 @@ func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f) } func TriangleTextured(fb *RenderBuffer, texture Framebuffer, intensity float32, v0v Vertex, v1v Vertex, v2v Vertex) { - if ZClip(v0v.Pos, v1v.Pos, v2v.Pos) { + // if ZClip(v0v.Pos, v1v.Pos, v2v.Pos) { + // return + // } + // min, max + boundsTLf, boundsBRf := ComputeBoundingBoxF(v0v.Pos, v1v.Pos, v2v.Pos) + // The triangle is fully out of bounds + if boundsBRf.Y < 0 || boundsBRf.X < 0 || boundsTLf.X >= float32(fb.Width) || boundsTLf.Y >= float32(fb.Height) { //|| + //boundsBRf.Z < 0 || boundsTLf.Z > 1 { + return + } + if boundsBRf.Z < 0 || boundsTLf.Z > 1 { + //log.Print(boundsTLf, boundsBRf) return } v0 := v0v.Pos.ToVec2i() v1 := v1v.Pos.ToVec2i() v2 := v2v.Pos.ToVec2i() - boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2) - if boundsBR.Y < 0 || boundsBR.X < 0 || boundsTL.X >= int(fb.Width) || boundsTL.Y >= int(fb.Height) { - return - } + //boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2) parea := EdgeFunctioni(v0, v1, v2) + // Disable back face culling + // if parea < 0 { + // v1, v2 = v2, v1 + // parea = EdgeFunctioni(v0, v1, v2) + // } if parea == 0 { return } - if boundsTL.Y < 0 { + boundsTL := Vec2i{ + X: int(max(boundsTLf.X, 0)), //0, float32(fb.Width))), + Y: int(max(boundsTLf.Y, 0)), //Clamp(boundsTLf.Y, 0, float32(fb.Height))), + } + boundsBR := Vec2i{ + X: int(min(boundsBRf.X, float32(fb.Width-1))), + Y: int(min(boundsBRf.Y, float32(fb.Height-1))), + } + /*if boundsTL.Y < 0 { boundsTL.Y = 0 } if boundsTL.X < 0 { @@ -127,7 +153,7 @@ func TriangleTextured(fb *RenderBuffer, texture Framebuffer, intensity float32, } if boundsBR.X >= int(fb.Width) { boundsBR.X = int(fb.Width - 1) - } + }*/ // Where to start our scanning pstart := Vec2i{boundsTL.X, boundsTL.Y} invarea := 1 / float32(parea) @@ -138,12 +164,32 @@ func TriangleTextured(fb *RenderBuffer, texture Framebuffer, intensity float32, w1_xi, w1_yi := EdgeIncrementi(v2, v0) w2_xi, w2_yi := EdgeIncrementi(v0, v1) + // //v0f := v0v.Pos + // parea := EdgeFunction(v0v.Pos, v1v.Pos, v2v.Pos) + // // Disable back face culling + // // if parea < 0 { + // // v1, v2 = v2, v1 + // // parea = EdgeFunctioni(v0, v1, v2) + // // } + // if parea == 0 { + // return + // } + // pstart := Vec3f{X: float32(boundsTL.X), Y: float32(boundsTL.Y)} + // invarea := 1 / float32(parea) + // w0_y := EdgeFunction(v1v.Pos, v2v.Pos, pstart) + // w1_y := EdgeFunction(v2v.Pos, v0v.Pos, pstart) + // w2_y := EdgeFunction(v0v.Pos, v1v.Pos, pstart) + // w0_xi, w0_yi := EdgeIncrement(v1v.Pos, v2v.Pos) + // w1_xi, w1_yi := EdgeIncrement(v2v.Pos, v0v.Pos) + // w2_xi, w2_yi := EdgeIncrement(v0v.Pos, v1v.Pos) + for y := uint(boundsTL.Y); y <= uint(boundsBR.Y); y++ { w0 := w0_y w1 := w1_y w2 := w2_y for x := uint(boundsTL.X); x <= uint(boundsBR.X); x++ { if (w0 | w1 | w2) >= 0 { + //if w0 >= 0 && w1 >= 0 && w2 >= 0 { w0a := float32(w0) * invarea w1a := float32(w1) * invarea w2a := float32(w2) * invarea diff --git a/renderer2/main.go b/renderer2/main.go index 501098e..ed74931 100644 --- a/renderer2/main.go +++ b/renderer2/main.go @@ -19,8 +19,8 @@ import ( ) const ( - NearClip = 0.01 - FarClip = 100 + NearClip = 0.0001 + FarClip = 10 Movement = 1.0 Rotation = 0.25 LookLock = math.Pi / 32 @@ -201,12 +201,12 @@ func main() { // Generate world wtexraw := Checkerboard([]color.Color{color.RGBA{R: 0, G: 255, B: 0, A: 255}, color.RGBA{R: 50, G: 150, B: 0, A: 255}}, 32) wtex := hrend.NewTexture(wtexraw, 1) - world := FlatTerrain(10) + world := FlatTerrain(1) // Generate skybox - skyraw := Gradient1px(color.RGBA{R: 100, G: 100, B: 255, A: 255}, color.RGBA{R: 255, G: 255, B: 255, A: 255}, 32) - skytex := hrend.NewTexture(skyraw, 1) - sky := Skybox() + // skyraw := Gradient1px(color.RGBA{R: 100, G: 100, B: 255, A: 255}, color.RGBA{R: 255, G: 255, B: 255, A: 255}, 32) + // skytex := hrend.NewTexture(skyraw, 1) + // sky := Skybox() // Some static models we could put in the scene modnames := []string{"head", "diablo"} @@ -219,13 +219,13 @@ func main() { // 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(sky, skytex)) // the actual skybox - skyobj := objects[len(objects)-1] - skyobj.Scale = 50 - skyobj.Lighting = false - objects = append(objects, NewObjectDef(models[1], textures[1])) - objects[len(objects)-1].Pos.Y += 1 - objects[len(objects)-1].Pos.Z -= 2 + // objects = append(objects, NewObjectDef(sky, skytex)) // the actual skybox + // skyobj := objects[len(objects)-1] + // skyobj.Scale = 50 + // skyobj.Lighting = false + // objects = append(objects, NewObjectDef(models[1], textures[1])) + // objects[len(objects)-1].Pos.Y += 1 + // objects[len(objects)-1].Pos.Z -= 2 // These don't really change var projection, viewport hrend.Mat44f @@ -261,9 +261,13 @@ func main() { } } + //var osc [3]hrend.Vec3f + //var om3d hrend.Mat44f var sc [3]hrend.Vertex var modelmat hrend.Mat44f var intensity float32 + var minz = float32(math.MaxFloat32) + var maxz = float32(-math.MaxFloat32) for _, o := range objects { // Create the final matrix modelmat.SetLookAt(&o.Pos, o.Pos.Add(&o.LookVec), &camup) @@ -274,7 +278,25 @@ func main() { for i := range 3 { sc[i] = f[i] sc[i].Pos = matrix3d.MultiplyPoint3(f[i].Pos) + minz = min(minz, sc[i].Pos.Z) + maxz = max(maxz, sc[i].Pos.Z) } + // for i := range 3 { + // if math.Signbit(float64(sc[i].Pos.X)) != math.Signbit(float64(osc[i].X)) || + // math.Signbit(float64(sc[i].Pos.Y)) != math.Signbit(float64(osc[i].Y)) { + // log.Print(sc[0].Pos, sc[1].Pos, sc[2].Pos) + // log.Print(matrix3d) + // break + // } + // } + log.Print(o.Model.Faces[0][0].Pos, o.Model.Faces[0][1].Pos, o.Model.Faces[0][2].Pos) + log.Print(sc[0].Pos, sc[1].Pos, sc[2].Pos) + log.Print(matrix3d) + // osc[0] = sc[0].Pos + // osc[1] = sc[1].Pos + // osc[2] = sc[2].Pos + //om3d = *matrix3d + //log.Print(sc[0].Pos, sc[1].Pos, sc[2].Pos, matrix3d) if o.Lighting { l1 := f[2].Pos.Sub(&f[0].Pos) n := l1.CrossProduct(f[1].Pos.Sub(&f[0].Pos)) @@ -289,9 +311,11 @@ func main() { intensity = 1.0 } hrend.TriangleTextured(&rb, o.Texture, intensity, sc[0], sc[1], sc[2]) + break //hrend.TriangleFlat(&rb, hrend.Col2Uint(byte(255*intensity), byte(255*intensity), byte(255*intensity)), sc[0].Pos, sc[1].Pos, sc[2].Pos) } } + //log.Print(minz, maxz) timer.Add(time.Since(start), 10) drawFunc()