diff --git a/tinyrender2/main.go b/tinyrender2/main.go index b9d147d..2136d40 100644 --- a/tinyrender2/main.go +++ b/tinyrender2/main.go @@ -56,9 +56,9 @@ func main() { //halfwidth := float32(fb.Width / 2) //halfheight := float32(fb.Height / 2) for range Repeat { - Triangle1(&fb, 0xFF0000, Vec2i{10, 70}, Vec2i{50, 160}, Vec2i{70, 80}) - Triangle1(&fb, 0xFFFFFF, Vec2i{180, 50}, Vec2i{150, 1}, Vec2i{70, 180}) - Triangle1(&fb, 0x00FF00, Vec2i{180, 150}, Vec2i{120, 160}, Vec2i{130, 180}) + Triangle2(&fb, 0xFF0000, Vec2i{10, 70}, Vec2i{50, 160}, Vec2i{70, 80}) + Triangle2(&fb, 0xFFFFFF, Vec2i{180, 50}, Vec2i{150, 1}, Vec2i{70, 180}) + Triangle2(&fb, 0x00FF00, Vec2i{180, 150}, Vec2i{120, 160}, Vec2i{130, 180}) } /* diff --git a/tinyrender2/obj.go b/tinyrender2/obj.go index a9e3a8c..14086ae 100644 --- a/tinyrender2/obj.go +++ b/tinyrender2/obj.go @@ -17,6 +17,10 @@ type Vec2i struct { X, Y int } +type Vec2f struct { + X, Y float32 +} + type Facef [3]Vec3f type ObjModel struct { @@ -24,6 +28,14 @@ type ObjModel struct { Faces []Facef } +func (vi *Vec2i) ToF() Vec2f { + return Vec2f{float32(vi.X), float32(vi.Y)} +} + +// func CrossProduct(v0, v1 Vec3f) Vec3f { +// +// } + // Parse an obj file at the given reader. Only handles v and f right now func ParseObj(reader io.Reader) (*ObjModel, error) { result := ObjModel{ diff --git a/tinyrender2/render.go b/tinyrender2/render.go index 65eb45e..2f22e0b 100644 --- a/tinyrender2/render.go +++ b/tinyrender2/render.go @@ -1,6 +1,7 @@ package main import ( + //"log" "math" ) @@ -98,3 +99,80 @@ func Triangle1(fb *Framebuffer, color uint, v0 Vec2i, v1 Vec2i, v2 Vec2i) { } } } + +// How does this work? Compare with your +// other barycentric function (in a different repo). In the original +// cpp code, they used an overloaded operator ^ to mean cross product +func Barycentric(v0, v1, v2, p Vec2i) Vec3f { + // WARN: Just not doing this one + u := Vec3f{} + if math.Abs(float64(u.Z)) < 1 { + return Vec3f{-1, 1, 1} + } + return Vec3f{1 - (u.X+u.Y)/u.Z, u.Y / u.Z, u.X / u.Z} +} + +// Figure out the minimum bounding box for a triangle defined by +// these vertices. Returns the top left and bottom right points, +// inclusive +func ComputeBoundingBox(v0, v1, v2 Vec2i) (Vec2i, Vec2i) { + return Vec2i{min(v0.X, v1.X, v2.X), min(v0.Y, v1.Y, v2.Y)}, + Vec2i{max(v0.X, v1.X, v2.X), max(v0.Y, v1.Y, v2.Y)} +} + +// 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 { + 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) { + return (v2.Y - v1.Y), -(v2.X - v1.X) +} + +func Triangle2(fb *Framebuffer, color uint, v0 Vec2i, v1 Vec2i, v2 Vec2i) { + boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2) + const expand = (2 << 12) + //log.Print(boundsTL, boundsBR) + v0f := v0.ToF() + v1f := v1.ToF() + v2f := v2.ToF() + // Where to start our scanning + pstart := Vec2f{float32(boundsTL.X) + 0.5, float32(boundsTL.Y) + 0.5} + // parea := EdgeFunction(v0f, v1f, v2f) + // invarea := 1 / parea + w0_y := int(expand * EdgeFunction(v1f, v2f, pstart)) + w1_y := int(expand * EdgeFunction(v2f, v0f, pstart)) + w2_y := int(expand * EdgeFunction(v0f, v1f, pstart)) + w0_xit, w0_yit := EdgeIncrement(v1f, v2f) + w1_xit, w1_yit := EdgeIncrement(v2f, v0f) + w2_xit, w2_yit := EdgeIncrement(v0f, v1f) + w0_xi := int(expand * w0_xit) + w0_yi := int(expand * w0_yit) + w1_xi := int(expand * w1_xit) + w1_yi := int(expand * w1_yit) + w2_xi := int(expand * w2_xit) + w2_yi := int(expand * w2_yit) + + for y := boundsTL.Y; y <= boundsBR.Y; y++ { + w0 := w0_y + w1 := w1_y + w2 := w2_y + for x := boundsTL.X; x <= boundsBR.X; x++ { + if w0 >= 0 && w1 >= 0 && w2 >= 0 { + fb.SetSafe(uint(x), uint(y), color) + // w0a := w0 * invarea + // w1a := w1 * invarea + // w2a := w2 * invarea + } + w0 += w0_xi + w1 += w1_xi + w2 += w2_xi + } + w0_y += w0_yi + w1_y += w1_yi + w2_y += w2_yi + } +}