From ada95278690530fb97108e415bd75dc5c737b5fb Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Fri, 2 Aug 2024 18:59:18 -0400 Subject: [PATCH] Stupid sky --- renderer2/generation.go | 111 ++++++++++++++++++++++++++++++++++++++++ renderer2/main.go | 55 +++++++++++++------- 2 files changed, 147 insertions(+), 19 deletions(-) diff --git a/renderer2/generation.go b/renderer2/generation.go index 2dbfe9a..923d981 100644 --- a/renderer2/generation.go +++ b/renderer2/generation.go @@ -16,6 +16,117 @@ func Checkerboard(cols []color.Color, size int) image.Image { return result } +// Returns a sizexsize*3 texture where the top is the top color, +// bottom is bottom color, middle is gradient +func Gradient(bottom color.Color, top color.Color, size int) image.Image { + result := image.NewRGBA(image.Rect(0, 0, size, size*3)) + br, bg, bb, ba := bottom.RGBA() + tr, tg, tb, ta := top.RGBA() + for y := range size { + for x := range size { + lerp := float32(y) / float32(size-1) + result.Set(x, y, top) + result.Set(x, y+size, color.RGBA{ + R: byte(float32(tr>>8)*(1-lerp) + float32(br>>8)*lerp), + G: byte(float32(tg>>8)*(1-lerp) + float32(bg>>8)*lerp), + B: byte(float32(tb>>8)*(1-lerp) + float32(bb>>8)*lerp), + A: byte(float32(ta>>8)*(1-lerp) + float32(ba>>8)*lerp), + }) + result.Set(x, y+size*2, bottom) + } + } + return result +} + +// Returns a 1px wide gradient where top is top color, bottom is bottom color +func Gradient1px(bottom color.Color, top color.Color, size int) image.Image { + result := image.NewRGBA(image.Rect(0, 0, 1, size)) + br, bg, bb, ba := bottom.RGBA() + tr, tg, tb, ta := top.RGBA() + for y := range size { + lerp := float32(y) / float32(size-1) + result.Set(0, y, color.RGBA{ + R: byte(float32(tr>>8)*(1-lerp) + float32(br>>8)*lerp), + G: byte(float32(tg>>8)*(1-lerp) + float32(bg>>8)*lerp), + B: byte(float32(tb>>8)*(1-lerp) + float32(bb>>8)*lerp), + A: byte(float32(ta>>8)*(1-lerp) + float32(ba>>8)*lerp), + }) + } + return result +} + +// Skybox for now assumes a 1px gradient +func Skybox() *hrend.ObjModel { + v := make([]hrend.Vec3f, 8) + vt := make([]hrend.Vec3f, 2) + f := make([]hrend.Facef, 12) + // Assuming 1px gradient, these are the only two texture points you need + vt[0] = hrend.Vec3f{X: 0, Y: 0, Z: 0} + vt[1] = hrend.Vec3f{X: 0, Y: 1, Z: 0} + vvt := []hrend.Vec3f{ + vt[0], vt[0], vt[0], vt[0], vt[1], vt[1], vt[1], vt[1], + } + // Cube faces are weird, I guess just manually do them? ugh + // First 4 are the bottom vertices. We can make two faces out of these + v[0] = hrend.Vec3f{X: float32(-1), Y: float32(-1), Z: float32(-1)} + v[1] = hrend.Vec3f{X: float32(1), Y: float32(-1), Z: float32(-1)} + v[2] = hrend.Vec3f{X: float32(1), Y: float32(-1), Z: float32(1)} + v[3] = hrend.Vec3f{X: float32(-1), Y: float32(-1), Z: float32(1)} + // Now the top 4 vertices, same order as bottom + v[4] = hrend.Vec3f{X: float32(-1), Y: float32(1), Z: float32(-1)} + v[5] = hrend.Vec3f{X: float32(1), Y: float32(1), Z: float32(-1)} + v[6] = hrend.Vec3f{X: float32(1), Y: float32(1), Z: float32(1)} + 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}, + {4, 5, 6}, // top + {6, 7, 4}, + {0, 1, 5}, // south + {5, 4, 0}, + {1, 2, 6}, // east + {6, 5, 1}, + {2, 3, 7}, // North + {7, 6, 2}, + {3, 0, 4}, // west + {4, 7, 3}, + } + for i, face := range fv { + for j := range 3 { + f[i][j] = hrend.Vertex{Pos: v[face[j]], Tex: vvt[face[j]]} + } + } + // Now the bottom 2 faces + // f[0] = hrend.Facef{ + // hrend.Vertex{Pos: v[0], Tex: vt[0]}, + // hrend.Vertex{Pos: v[1], Tex: vt[0]}, + // hrend.Vertex{Pos: v[2], Tex: vt[0]}, + // } + // f[1] = hrend.Facef{ + // hrend.Vertex{Pos: v[2], Tex: vt[0]}, + // hrend.Vertex{Pos: v[3], Tex: vt[0]}, + // hrend.Vertex{Pos: v[0], Tex: vt[0]}, + // } + // // Top 2 faces + // f[3] = hrend.Facef{ + // hrend.Vertex{Pos: v[4], Tex: vt[1]}, + // hrend.Vertex{Pos: v[5], Tex: vt[1]}, + // hrend.Vertex{Pos: v[6], Tex: vt[1]}, + // } + // f[4] = hrend.Facef{ + // hrend.Vertex{Pos: v[6], Tex: vt[1]}, + // hrend.Vertex{Pos: v[7], Tex: vt[1]}, + // hrend.Vertex{Pos: v[4], Tex: vt[1]}, + // } + // Ugh and now the sides... so complicated + return &hrend.ObjModel{ + Vertices: v, + VTexture: vt, + Faces: f, + } +} + func FlatTerrain(size int) *hrend.ObjModel { result := hrend.ObjModel{ Vertices: make([]hrend.Vec3f, 0), diff --git a/renderer2/main.go b/renderer2/main.go index e8ac18d..501098e 100644 --- a/renderer2/main.go +++ b/renderer2/main.go @@ -35,20 +35,22 @@ 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 + Model *hrend.ObjModel + Texture hrend.Framebuffer // This needs to go somewhere else eventually! + Pos hrend.Vec3f + LookVec hrend.Vec3f + Scale float32 + Lighting bool //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, + Model: model, + Texture: texture, + LookVec: hrend.Vec3f{X: 0, Y: 0, Z: -1}, + Scale: 1, + Lighting: true, } //result.Transform.SetIdentity() return &result @@ -201,6 +203,11 @@ func main() { wtex := hrend.NewTexture(wtexraw, 1) world := FlatTerrain(10) + // 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() + // Some static models we could put in the scene modnames := []string{"head", "diablo"} models := make([]*hrend.ObjModel, len(modnames)) @@ -212,9 +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[1].Pos.Y += 1 - objects[1].Pos.Z -= 2 + objects[len(objects)-1].Pos.Y += 1 + objects[len(objects)-1].Pos.Z -= 2 // These don't really change var projection, viewport hrend.Mat44f @@ -252,9 +263,11 @@ func main() { var sc [3]hrend.Vertex var modelmat hrend.Mat44f + var intensity float32 for _, o := range objects { // Create the final matrix modelmat.SetLookAt(&o.Pos, o.Pos.Add(&o.LookVec), &camup) + modelmat.ScaleSelf(o.Scale) matrix3d := modelmat.Multiply(screenmat) //matrix3d.ScaleSelf(o.Scale) for _, f := range o.Model.Faces { @@ -262,15 +275,19 @@ func main() { 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 + if o.Lighting { + l1 := f[2].Pos.Sub(&f[0].Pos) + n := l1.CrossProduct(f[1].Pos.Sub(&f[0].Pos)) + n = n.Normalize() + // light = lookvec // use this for weird things + intensity = n.MultSimp(&light) + if intensity < 0 { + intensity = 0 + } + intensity = (intensity + float32(*minlight)) / (1 + float32(*minlight)) + } else { + intensity = 1.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) }