Slightly faster
This commit is contained in:
parent
0683976241
commit
aac3191403
@ -4,6 +4,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
// "math/rand"
|
||||||
"os"
|
"os"
|
||||||
"runtime/pprof" // For performance profiling (unnecessary)
|
"runtime/pprof" // For performance profiling (unnecessary)
|
||||||
)
|
)
|
||||||
@ -12,7 +13,7 @@ const (
|
|||||||
Width = 512
|
Width = 512
|
||||||
Height = 512
|
Height = 512
|
||||||
ObjectFile = "head.obj"
|
ObjectFile = "head.obj"
|
||||||
Repeat = 100_000
|
Repeat = 600
|
||||||
)
|
)
|
||||||
|
|
||||||
func must(err error) {
|
func must(err error) {
|
||||||
@ -41,44 +42,50 @@ func main() {
|
|||||||
|
|
||||||
fb := NewFramebuffer(Width, Height)
|
fb := NewFramebuffer(Width, Height)
|
||||||
|
|
||||||
/*
|
log.Printf("Loading obj %s", ObjectFile)
|
||||||
log.Printf("Loading obj %s", ObjectFile)
|
|
||||||
|
|
||||||
of, err := os.Open(ObjectFile)
|
of, err := os.Open(ObjectFile)
|
||||||
must(err)
|
must(err)
|
||||||
defer of.Close()
|
defer of.Close()
|
||||||
o, err := ParseObj(of)
|
o, err := ParseObj(of)
|
||||||
must(err)
|
must(err)
|
||||||
*/
|
|
||||||
|
|
||||||
log.Printf("Running render")
|
log.Printf("Running render")
|
||||||
|
|
||||||
//halfwidth := float32(fb.Width / 2)
|
light := Vec3f{0, 0, -1}
|
||||||
//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})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
// for range Repeat {
|
||||||
var x [3]int
|
// Triangle2(&fb, 0xFF0000, Vec2i{10, 70}, Vec2i{50, 160}, Vec2i{70, 80})
|
||||||
var y [3]int
|
// Triangle2(&fb, 0xFFFFFF, Vec2i{180, 50}, Vec2i{150, 1}, Vec2i{70, 180})
|
||||||
var hi = int(fb.Height - 1)
|
// Triangle2(&fb, 0x00FF00, Vec2i{180, 150}, Vec2i{120, 160}, Vec2i{130, 180})
|
||||||
for range Repeat {
|
// }
|
||||||
for _, f := range o.Faces {
|
|
||||||
// Precompute perspective for vertices to save time. Notice Z
|
halfwidth := float32(fb.Width / 2)
|
||||||
// is not considered: is this orthographic projection? Yeah probably...
|
halfheight := float32(fb.Height / 2)
|
||||||
for i := range 3 { // Triangles, bro
|
var sc [3]Vec2i
|
||||||
x[i] = int((f[i].X + 1) * halfwidth)
|
var hi = int(fb.Height - 1)
|
||||||
y[i] = hi - int((f[i].Y+1)*halfheight)
|
for range Repeat {
|
||||||
}
|
for _, f := range o.Faces {
|
||||||
Bresenham2(&fb, 0xFFFFFF, x[0], y[0], x[1], y[1])
|
// Precompute perspective for vertices to save time. Notice Z
|
||||||
Bresenham2(&fb, 0xFFFFFF, x[1], y[1], x[2], y[2])
|
// is not considered: is this orthographic projection? Yeah probably...
|
||||||
Bresenham2(&fb, 0xFFFFFF, x[2], y[2], x[0], y[0])
|
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")
|
log.Printf("Exporting ppm to stdout")
|
||||||
fmt.Print(fb.ExportPPM())
|
fmt.Print(fb.ExportPPM())
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,9 +33,34 @@ func (vi *Vec2i) ToF() Vec2f {
|
|||||||
return Vec2f{float32(vi.X), float32(vi.Y)}
|
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
|
// Parse an obj file at the given reader. Only handles v and f right now
|
||||||
func ParseObj(reader io.Reader) (*ObjModel, error) {
|
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)
|
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) {
|
func Triangle2(fb *Framebuffer, color uint, v0 Vec2i, v1 Vec2i, v2 Vec2i) {
|
||||||
boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2)
|
boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2)
|
||||||
if boundsTL.Y < 0 {
|
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)
|
boundsBR.X = int(fb.Width - 1)
|
||||||
}
|
}
|
||||||
// Where to start our scanning
|
// 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)
|
//log.Print(boundsTL, boundsBR)
|
||||||
v0f := v0.ToF()
|
// v0f := v0.ToF()
|
||||||
v1f := v1.ToF()
|
// v1f := v1.ToF()
|
||||||
v2f := v2.ToF()
|
// v2f := v2.ToF()
|
||||||
parea := EdgeFunction(v0f, v1f, v2f)
|
// parea := EdgeFunction(v0f, v1f, v2f)
|
||||||
invarea := 1 / parea
|
// invarea := 1 / parea
|
||||||
w0_y := EdgeFunction(v1f, v2f, pstart)
|
w0_y := EdgeFunctioni(v1, v2, pstart)
|
||||||
w1_y := EdgeFunction(v2f, v0f, pstart)
|
w1_y := EdgeFunctioni(v2, v0, pstart)
|
||||||
w2_y := EdgeFunction(v0f, v1f, pstart)
|
w2_y := EdgeFunctioni(v0, v1, pstart)
|
||||||
w0_xi, w0_yi := EdgeIncrement(v1f, v2f)
|
w0_xi, w0_yi := EdgeIncrementi(v1, v2)
|
||||||
w1_xi, w1_yi := EdgeIncrement(v2f, v0f)
|
w1_xi, w1_yi := EdgeIncrementi(v2, v0)
|
||||||
w2_xi, w2_yi := EdgeIncrement(v0f, v1f)
|
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++ {
|
for y := uint(boundsTL.Y); y <= uint(boundsBR.Y); y++ {
|
||||||
w0 := w0_y
|
w0 := w0_y
|
||||||
w1 := w1_y
|
w1 := w1_y
|
||||||
w2 := w2_y
|
w2 := w2_y
|
||||||
|
//di := dy
|
||||||
|
//done := false
|
||||||
for x := uint(boundsTL.X); x <= uint(boundsBR.X); x++ {
|
for x := uint(boundsTL.X); x <= uint(boundsBR.X); x++ {
|
||||||
if w0 >= 0 && w1 >= 0 && w2 >= 0 {
|
if (w0 | w1 | w2) >= 0 {
|
||||||
w0a := w0 * invarea
|
//fb.Data[di] = color
|
||||||
w1a := w1 * invarea
|
fb.Set(x, y, color)
|
||||||
w2a := w2 * invarea
|
//done = true
|
||||||
fb.Set(x, y, Col2Uint(byte(255*w0a), byte(255*w1a), byte(255*w2a)))
|
// 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
|
w0 += w0_xi
|
||||||
w1 += w1_xi
|
w1 += w1_xi
|
||||||
w2 += w2_xi
|
w2 += w2_xi
|
||||||
}
|
}
|
||||||
|
//dy += dyi
|
||||||
w0_y += w0_yi
|
w0_y += w0_yi
|
||||||
w1_y += w1_yi
|
w1_y += w1_yi
|
||||||
w2_y += w2_yi
|
w2_y += w2_yi
|
||||||
|
Loading…
Reference in New Issue
Block a user