Slightly faster
This commit is contained in:
parent
0683976241
commit
aac3191403
@ -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,7 +42,6 @@ func main() {
|
||||
|
||||
fb := NewFramebuffer(Width, Height)
|
||||
|
||||
/*
|
||||
log.Printf("Loading obj %s", ObjectFile)
|
||||
|
||||
of, err := os.Open(ObjectFile)
|
||||
@ -49,36 +49,43 @@ func main() {
|
||||
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
|
||||
// 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
|
||||
x[i] = int((f[i].X + 1) * halfwidth)
|
||||
y[i] = hi - int((f[i].Y+1)*halfheight)
|
||||
sc[i].X = int((f[i].X + 1) * halfwidth)
|
||||
sc[i].Y = 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])
|
||||
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())
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user