Slightly faster

This commit is contained in:
Carlos Sanchez 2024-07-27 01:16:49 -04:00
parent 0683976241
commit aac3191403
3 changed files with 109 additions and 53 deletions

View File

@ -4,6 +4,7 @@ import (
"flag"
"fmt"
"log"
// "math/rand"
"os"
"runtime/pprof" // For performance profiling (unnecessary)
)
@ -12,7 +13,7 @@ const (
Width = 512
Height = 512
ObjectFile = "head.obj"
Repeat = 100_000
Repeat = 600
)
func must(err error) {
@ -41,44 +42,50 @@ func main() {
fb := NewFramebuffer(Width, Height)
/*
log.Printf("Loading obj %s", ObjectFile)
log.Printf("Loading obj %s", ObjectFile)
of, err := os.Open(ObjectFile)
must(err)
defer of.Close()
o, err := ParseObj(of)
must(err)
*/
of, err := os.Open(ObjectFile)
must(err)
defer of.Close()
o, err := ParseObj(of)
must(err)
log.Printf("Running render")
//halfwidth := float32(fb.Width / 2)
//halfheight := float32(fb.Height / 2)
for range Repeat {
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})
}
light := Vec3f{0, 0, -1}
/*
var x [3]int
var y [3]int
var hi = int(fb.Height - 1)
for range Repeat {
for _, f := range o.Faces {
// Precompute perspective for vertices to save time. Notice Z
// is not considered: is this orthographic projection? Yeah probably...
for i := range 3 { // Triangles, bro
x[i] = int((f[i].X + 1) * halfwidth)
y[i] = hi - int((f[i].Y+1)*halfheight)
}
Bresenham2(&fb, 0xFFFFFF, x[0], y[0], x[1], y[1])
Bresenham2(&fb, 0xFFFFFF, x[1], y[1], x[2], y[2])
Bresenham2(&fb, 0xFFFFFF, x[2], y[2], x[0], y[0])
// for range Repeat {
// 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})
// }
halfwidth := float32(fb.Width / 2)
halfheight := float32(fb.Height / 2)
var sc [3]Vec2i
var hi = int(fb.Height - 1)
for range Repeat {
for _, f := range o.Faces {
// Precompute perspective for vertices to save time. Notice Z
// is not considered: is this orthographic projection? Yeah probably...
for i := range 3 { // Triangles, bro
sc[i].X = int((f[i].X + 1) * halfwidth)
sc[i].Y = hi - int((f[i].Y+1)*halfheight)
}
l1 := f[2].Sub(f[0])
n := l1.CrossProduct(f[1].Sub(f[0]))
n = n.Normalize()
intensity := n.MultSimp(&light)
if intensity > 0 {
Triangle2(&fb, Col2Uint(byte(255*intensity), byte(255*intensity), byte(255*intensity)), sc[0], sc[1], sc[2])
//Triangle2(&fb, 0xFFFFFF, sc[0], sc[1], sc[2])
}
// Vec2i{10, 70}, Vec2i{50, 160}, Vec2i{70, 80})
// Bresenham2(&fb, 0xFFFFFF, x[0], y[0], x[1], y[1])
// Bresenham2(&fb, 0xFFFFFF, x[1], y[1], x[2], y[2])
// Bresenham2(&fb, 0xFFFFFF, x[2], y[2], x[0], y[0])
}
*/
}
log.Printf("Exporting ppm to stdout")
fmt.Print(fb.ExportPPM())

View File

@ -6,6 +6,7 @@ import (
"fmt"
"io"
"log"
"math"
"strings"
)
@ -32,9 +33,34 @@ func (vi *Vec2i) ToF() Vec2f {
return Vec2f{float32(vi.X), float32(vi.Y)}
}
// func CrossProduct(v0, v1 Vec3f) Vec3f {
//
// }
func (v0 *Vec3f) Sub(v1 Vec3f) Vec3f {
return Vec3f{
X: v0.X - v1.X,
Y: v0.Y - v1.Y,
Z: v0.Z - v1.Z,
}
}
func (v0 *Vec3f) CrossProduct(v1 Vec3f) Vec3f {
return Vec3f{
X: v0.Y*v1.Z - v0.Z*v1.Y,
Y: v0.Z*v1.X - v0.X*v1.Z,
Z: v0.X*v1.Y - v0.Y*v1.X,
}
}
func (v *Vec3f) Normalize() Vec3f {
l := float32(math.Sqrt(float64(v.MultSimp(v))))
return Vec3f{
X: v.X / l,
Y: v.Y / l,
Z: v.Z / l,
}
}
func (v0 *Vec3f) MultSimp(v1 *Vec3f) float32 {
return v0.X*v1.X + v0.Y*v1.Y + v0.Z*v1.Z
}
// Parse an obj file at the given reader. Only handles v and f right now
func ParseObj(reader io.Reader) (*ObjModel, error) {

View File

@ -135,6 +135,18 @@ func EdgeIncrement(v1, v2 Vec2f) (float32, float32) {
return (v2.Y - v1.Y), -(v2.X - v1.X)
}
// 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 EdgeFunctioni(v1, v2, p Vec2i) int {
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 EdgeIncrementi(v1, v2 Vec2i) (int, int) {
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)
if boundsTL.Y < 0 {
@ -150,35 +162,46 @@ func Triangle2(fb *Framebuffer, color uint, v0 Vec2i, v1 Vec2i, v2 Vec2i) {
boundsBR.X = int(fb.Width - 1)
}
// Where to start our scanning
pstart := Vec2f{float32(boundsTL.X) + 0.5, float32(boundsTL.Y) + 0.5}
pstart := Vec2i{boundsTL.X, boundsTL.Y}
//log.Print(boundsTL, boundsBR)
v0f := v0.ToF()
v1f := v1.ToF()
v2f := v2.ToF()
parea := EdgeFunction(v0f, v1f, v2f)
invarea := 1 / parea
w0_y := EdgeFunction(v1f, v2f, pstart)
w1_y := EdgeFunction(v2f, v0f, pstart)
w2_y := EdgeFunction(v0f, v1f, pstart)
w0_xi, w0_yi := EdgeIncrement(v1f, v2f)
w1_xi, w1_yi := EdgeIncrement(v2f, v0f)
w2_xi, w2_yi := EdgeIncrement(v0f, v1f)
// v0f := v0.ToF()
// v1f := v1.ToF()
// v2f := v2.ToF()
// parea := EdgeFunction(v0f, v1f, v2f)
// invarea := 1 / parea
w0_y := EdgeFunctioni(v1, v2, pstart)
w1_y := EdgeFunctioni(v2, v0, pstart)
w2_y := EdgeFunctioni(v0, v1, pstart)
w0_xi, w0_yi := EdgeIncrementi(v1, v2)
w1_xi, w1_yi := EdgeIncrementi(v2, v0)
w2_xi, w2_yi := EdgeIncrementi(v0, v1)
//dyi := int(fb.Width)
//dy := boundsTL.X + dyi*boundsTL.Y
for y := uint(boundsTL.Y); y <= uint(boundsBR.Y); y++ {
w0 := w0_y
w1 := w1_y
w2 := w2_y
//di := dy
//done := false
for x := uint(boundsTL.X); x <= uint(boundsBR.X); x++ {
if w0 >= 0 && w1 >= 0 && w2 >= 0 {
w0a := w0 * invarea
w1a := w1 * invarea
w2a := w2 * invarea
fb.Set(x, y, Col2Uint(byte(255*w0a), byte(255*w1a), byte(255*w2a)))
}
if (w0 | w1 | w2) >= 0 {
//fb.Data[di] = color
fb.Set(x, y, color)
//done = true
// w0a := w0 * invarea
// w1a := w1 * invarea
// w2a := w2 * invarea
// fb.Set(x, y, Col2Uint(byte(255*w0a), byte(255*w1a), byte(255*w2a)))
} /*else if done {
break
}*/
//di += 1
w0 += w0_xi
w1 += w1_xi
w2 += w2_xi
}
//dy += dyi
w0_y += w0_yi
w1_y += w1_yi
w2_y += w2_yi