Actually working oh wow

This commit is contained in:
Carlos Sanchez 2024-07-31 01:02:05 -04:00
parent 123ebc83df
commit 4a399c7bb7
4 changed files with 139 additions and 27 deletions

View File

@ -42,22 +42,40 @@ func (m *Mat44f) SetIdentity() {
// instead of creating a new one all the time (garbage collection)
// Compute the projection matrix, filling the given matrix. FOV is in degrees
func (m *Mat44f) SetProjection(fov float32, near float32, far float32) {
func (m *Mat44f) SetProjection(fov float32, aspect float32, near float32, far float32) {
// Projection matrix is (ROW MAJOR!)
// S 0 0 0
// 0 S 0 0
// 0 0 -f/(f-n) -1
// 0 0 -fn/(f-n) 0
// where S (scale) is 1 / tan(fov / 2) (assuming fov is radians)
// NOTE: -1 there is actually -1/c, where c is distance from viewer to
// projection plane. We fix it at 1 for now but...
// // NOTE: -1 there is actually -1/c, where c is distance from viewer to
// // projection plane. We fix it at 1 for now but...
// m.ZeroFill()
// scale := float32(1 / math.Tan(float64(fov)*0.5*math.Pi/180))
// m.Set(0, 0, scale)
// m.Set(1, 1, scale)
// m.Set(2, 2, -far/(far-near))
// m.Set(3, 2, -1)
// m.Set(2, 3, -far*near/(far-near))
// OK apparently I suck, let's use somebody else's projection matrix:
m.ZeroFill()
scale := float32(1 / math.Tan(float64(fov)*0.5*math.Pi/180))
m.Set(0, 0, scale)
m.Set(1, 1, scale)
m.Set(2, 2, -far/(far-near))
DEG2RAD := math.Acos(-1.0) / 180.0
tangent := math.Tan(float64(fov/2.0) * DEG2RAD) // tangent of half fovY
top := near * float32(tangent) // half height of near plane
right := top * aspect // half width of near plane
// Column major maybe???
// n/r 0 0 0
// 0 n/t 0 0
// 0 0 -(f+n)/(f-n) -1
// 0 0 -(2fn)/(f-n) 0
m.Set(0, 0, near/right)
m.Set(1, 1, near/top)
m.Set(2, 2, -(far+near)/(far-near))
m.Set(3, 2, -1)
m.Set(2, 3, -far*near/(far-near))
m.Set(2, 3, -(2*far*near)/(far-near))
}
func (m *Mat44f) SetTranslation(x, y, z float32) {

View File

@ -42,6 +42,9 @@ func TriangleFlat(fb *RenderBuffer, color uint, v0f Vec3f, v1f Vec3f, v2f Vec3f)
v2 := v2f.ToVec2i()
r, g, b := Uint2Col(color)
boundsTL, boundsBR := ComputeBoundingBox(v0, v1, v2)
if boundsBR.Y < 0 || boundsBR.X < 0 || boundsTL.X >= int(fb.Width) || boundsTL.Y >= int(fb.Height) {
return
}
if boundsTL.Y < 0 {
boundsTL.Y = 0
}

View File

@ -2,11 +2,14 @@ package main
import (
"flag"
"fmt"
"image"
"log"
"math"
"os"
"renderer1/hrend"
"runtime/pprof" // For performance profiling (unnecessary)
"time"
_ "image/jpeg"
@ -20,7 +23,9 @@ const (
FarClip = 100
FOV = 90.0
ZOffset = -1.5
ObjectFile = "head.obj"
Movement = 1.0
Fps = 60
ObjectFile = "../head.obj"
TextureFile = "../head.jpg"
)
@ -73,38 +78,98 @@ func main() {
defer pprof.StopCPUProfile()
}
fb := NewRaylibBuffer(Width, Height)
rb := hrend.NewRenderbuffer(fb, Width, Height)
o, texture := loadDefault()
light := hrend.Vec3f{0, 0, -1}
var projection, worldToCamera, viewport hrend.Mat44f
rl.InitWindow(Width, Height, "Simple renderer with raylib")
defer rl.CloseWindow()
rl.SetTargetFPS(60)
rl.SetTargetFPS(Fps)
fb := NewRaylibBuffer(Width, Height)
defer rl.UnloadTexture(fb.Texture)
defer rl.UnloadImageColors(fb.Data)
defer rl.UnloadImage(fb.Image)
rb := hrend.NewRenderbuffer(fb, Width, Height)
o, texture := loadDefault()
light := hrend.Vec3f{
X: 0,
Y: 0,
Z: -1,
}
var thing hrend.Vec2i
log.Print(thing)
var projection, worldToCamera, viewport hrend.Mat44f
// These don't really change
projection.SetProjection(float32(FOV), float32(Width)/float32(Height), NearClip, FarClip)
viewport.SetViewportSimple(int(fb.Width), int(fb.Height), 1) //65535)
log.Printf("Starting raylib loop")
frameSum := 0.0
frameCount := 0
frameAverage := 0.0
xofs := float32(0.0)
yofs := float32(0.0)
zofs := float32(ZOffset)
for !rl.WindowShouldClose() {
rl.BeginDrawing()
start := time.Now()
if rl.IsKeyDown(rl.KeyD) {
xofs += Movement / Fps
}
if rl.IsKeyDown(rl.KeyA) {
xofs -= Movement / Fps
}
if rl.IsKeyDown(rl.KeyW) {
zofs += Movement / Fps
}
if rl.IsKeyDown(rl.KeyS) {
zofs -= Movement / Fps
}
if rl.IsKeyDown(rl.KeySpace) {
yofs -= Movement / Fps
}
if rl.IsKeyDown(rl.KeyLeftShift) {
yofs += Movement / Fps
}
// This might (thought not currently)
worldToCamera.SetTranslation(xofs, yofs, zofs)
screenmat := worldToCamera.Multiply(&projection)
screenmat = screenmat.Multiply(&viewport)
for i := 0; i < Width*Height; i++ {
fb.Data[i].R = 0
fb.Data[i].G = 0
fb.Data[i].B = 0
}
//rl.ImageDrawRectangle(fb.Image, 0, 0, Width, Height, rl.Black)
//rl.ImageClearBackground(fb.Image, rl.Black)
var sc [3]hrend.Vertex
rb.ResetZBuffer()
for _, f := range o.Faces {
// Precompute perspective for vertices to save time. Notice Z
// is not considered: is this orthographic projection? Yeah probably...
var fpt [3]hrend.Vec3f
maxz := float32(-math.MaxFloat32)
for i := range 3 { // Triangles, bro
sc[i] = f[i]
sc[i].Pos = screenmat.MultiplyPoint3(f[i].Pos)
fpt[i] = worldToCamera.MultiplyPoint3(f[i].Pos)
maxz = max(maxz, sc[i].Pos.Z)
}
if maxz < 0 || maxz > 1 {
//log.Printf("Clipping %f %f %f", sc[0].Pos.Z, sc[1].Pos.Z, sc[2].Pos.Z)
continue
}
l1 := fpt[2].Sub(fpt[0])
@ -113,12 +178,24 @@ func main() {
intensity := n.MultSimp(&light)
if intensity > 0 {
hrend.TriangleTextured(&rb, 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)
}
}
rl.UpdateTexture(fb.Texture, fb.Data)
frameSum += time.Since(start).Seconds()
frameCount += 1
if frameCount&0x7 == 0 {
frameAverage = frameSum / float64(frameCount)
frameSum = 0
frameCount = 0
}
rl.BeginDrawing()
rl.ClearBackground(rl.RayWhite)
rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LightGray)
rl.DrawTexture(fb.Texture, 0, 0, rl.White)
rl.DrawText(fmt.Sprintf("Frame: %fms", frameAverage*1000), 5, 5, 20, rl.Red)
rl.EndDrawing()
}
}

View File

@ -2,17 +2,31 @@ package main
import (
rl "github.com/gen2brain/raylib-go/raylib"
"log"
)
type RaylibBuffer struct {
Data []rl.Color
Image *rl.Image
Texture rl.Texture2D
Width uint
Height uint
}
func NewRaylibBuffer(width uint, height uint) *RaylibBuffer {
log.Printf("Creating new raylib framebuffer using texture + image")
//rl.NewTexture2D(1, Width, Height, 0, )
rlimage := rl.GenImageColor(Width, Height, rl.Black)
rl.ImageFormat(rlimage, rl.UncompressedR8g8b8a8)
log.Printf("Generated baseline image: %v", rlimage)
rltexture := rl.LoadTextureFromImage(rlimage)
log.Printf("Generated texture from image")
data := rl.LoadImageColors(rlimage)
log.Printf("Generated pixel data from image")
return &RaylibBuffer{
Data: make([]rl.Color, width*height),
Data: data,
Image: rlimage,
Texture: rltexture,
Width: width,
Height: height,
}