Trying actual world

This commit is contained in:
Carlos Sanchez 2024-08-02 16:50:14 -04:00
parent 37ec57a83f
commit 4ab6b365ee
6 changed files with 99 additions and 118 deletions

56
renderer2/generation.go Normal file
View File

@ -0,0 +1,56 @@
package main
import (
"image"
"image/color"
"renderer1/hrend"
)
func Checkerboard(cols []color.Color, size int) image.Image {
result := image.NewRGBA(image.Rect(0, 0, size, size))
for y := range size {
for x := range size {
result.Set(x, y, cols[(x+y)%len(cols)])
}
}
return result
}
func FlatTerrain(size int) *hrend.ObjModel {
result := hrend.ObjModel{
Vertices: make([]hrend.Vec3f, 0),
VTexture: make([]hrend.Vec3f, 4),
Faces: make([]hrend.Facef, 0),
}
// For the simple square terrain, there aren't a lot of texture coords...
result.VTexture[0] = hrend.Vec3f{X: 0, Y: 0, Z: 0}
result.VTexture[1] = hrend.Vec3f{X: 1, Y: 0, Z: 0}
result.VTexture[2] = hrend.Vec3f{X: 0, Y: 1, Z: 0}
result.VTexture[3] = hrend.Vec3f{X: 1, Y: 1, Z: 0}
// Generate all the simple vertices along the plane at y=0
for z := -size; z <= size; z++ {
for x := -size; x <= size; x++ {
result.Vertices = append(result.Vertices, hrend.Vec3f{X: float32(x), Y: 0, Z: float32(z)})
}
}
// Faces are slightly different; we generate two for every "cell" inside the vertices
for z := 0; z < size*2; z++ {
for x := 0; x < size*2; x++ {
topleft := x + z*size*2
topright := x + 1 + z*size*2
bottomleft := x + (z+1)*size*2
bottomright := x + 1 + (z+1)*size*2
// remember to wind counter-clockwise
result.Faces = append(result.Faces, hrend.Facef{
hrend.Vertex{Pos: result.Vertices[topleft], Tex: result.VTexture[0]},
hrend.Vertex{Pos: result.Vertices[bottomleft], Tex: result.VTexture[2]},
hrend.Vertex{Pos: result.Vertices[topright], Tex: result.VTexture[1]},
}, hrend.Facef{
hrend.Vertex{Pos: result.Vertices[topright], Tex: result.VTexture[1]},
hrend.Vertex{Pos: result.Vertices[bottomleft], Tex: result.VTexture[2]},
hrend.Vertex{Pos: result.Vertices[bottomright], Tex: result.VTexture[3]},
})
}
}
return &result
}

View File

@ -111,21 +111,21 @@ func NewRenderbuffer(d Framebuffer, width uint, height uint) RenderBuffer {
}
}
func NewTexture(texture image.Image, skip int) *SimpleFramebuffer {
func NewTexture(texture image.Image, stride int) *SimpleFramebuffer {
bounds := texture.Bounds()
width := bounds.Dx() / skip
height := bounds.Dy() / skip
width := bounds.Dx() / stride
height := bounds.Dy() / stride
result := NewSimpleFramebuffer(uint(width), uint(height))
wlog := math.Log2(float64(width))
hlog := math.Log2(float64(height))
if wlog != math.Floor(wlog) || hlog != math.Floor(hlog) {
panic("Texture must be power of two")
}
for y := bounds.Min.Y; y < bounds.Max.Y; y += skip {
for x := bounds.Min.X; x < bounds.Max.X; x += skip {
for y := bounds.Min.Y; y < bounds.Max.Y; y += stride {
for x := bounds.Min.X; x < bounds.Max.X; x += stride {
col := texture.At(x, y)
r, g, b, _ := col.RGBA()
result.Set(uint(x/skip), uint(y/skip), byte(r>>8), byte(g>>8), byte(b>>8))
result.Set(uint(x/stride), uint(y/stride), byte(r>>8), byte(g>>8), byte(b>>8))
}
}
return result

View File

@ -1,49 +0,0 @@
/*package hrend
import (
"image"
)
// Color is in RGB (alpha not used right now)
type ImageFramebuffer struct {
Data image.Image
Width uint
Height uint
}
// Sure hope this gets inlined...
func (fb *ImageFramebuffer) Set(x uint, y uint, r byte, g byte, b byte) {
if x >= fb.Width || y >= fb.Height {
return
}
image.New
fb.Data.
fb.Data[(x+y*fb.Width)*3] = r
fb.Data[(x+y*fb.Width)*3+1] = g
fb.Data[(x+y*fb.Width)*3+2] = b
}
func (fb *SimpleFramebuffer) Get(x uint, y uint) (byte, byte, byte) {
if x >= fb.Width || y >= fb.Height {
return 0, 0, 0
}
return fb.Data[(x+y*fb.Width)*3],
fb.Data[(x+y*fb.Width)*3+1],
fb.Data[(x+y*fb.Width)*3+2]
}
func (fb *SimpleFramebuffer) GetUv(u float32, v float32) (byte, byte, byte) {
x := uint(float32(fb.Width)*u) & (fb.Width - 1)
y := uint(float32(fb.Height)*(1-v)) & (fb.Height - 1)
return fb.Data[(x+y*fb.Width)*3],
fb.Data[(x+y*fb.Width)*3+1],
fb.Data[(x+y*fb.Width)*3+2]
}
func NewSimpleFramebuffer(width uint, height uint) *SimpleFramebuffer {
return &SimpleFramebuffer{
Data: make([]byte, width*height*3),
Width: width,
Height: height,
}
}*/

View File

@ -33,6 +33,7 @@ type ObjModel struct {
func ParseObj(reader io.Reader) (*ObjModel, error) {
result := ObjModel{
Vertices: make([]Vec3f, 0),
VTexture: make([]Vec3f, 0),
Faces: make([]Facef, 0),
}
breader := bufio.NewReader(reader)

View File

@ -3,7 +3,8 @@ package main
import (
"flag"
"fmt"
"image"
//"image"
"image/color"
"log"
"math"
"os"
@ -17,10 +18,11 @@ import (
)
const (
NearClip = 0.1
NearClip = 0.01
FarClip = 100
FOV = 90.0
ZOffset = 1.5
YOffset = 0.5
Movement = 1.0
Rotation = 0.25
LookLock = math.Pi / 32
@ -58,22 +60,15 @@ func must(err error) {
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var width = flag.Int("width", 640, "width of window or frame")
var height = flag.Int("width", 480, "height of window or frame")
// var renderconfig = flag.String("renderconfig", "", "if set, rendering is written out")
var renderout = flag.String("renderout", "", "If set, rendering is done to a file instead of realtime")
var renderinput = flag.String("renderinput", "", "If not realtime, the inputs are taken from here.")
// var renderconfig = flag.String("renderconfig", "", "if set, rendering is written out")
func IsRealtime() bool {
return *renderout == ""
}
// var dozbuf = flag.Bool("zbuffer", false, "Write zbuffer instead of image")
// var p6file = flag.String("p6file", "", "Output binary ppm to given file instead")
// var fov = flag.Float64("fov", 90, "Horizontal FOV in degrees")
// var xofs = flag.Float64("xofs", 0, "Offset image by x")
// var zofs = flag.Float64("zofs", -1.5, "Offset image by z (should be negative)")
// var repeat = flag.Int("repeat", 60, "Amount of times to repeat render")
// Do next inputs, whether they come from raylib or a file
func CameraInput(yaw, pitch float32) (float32, float32, hrend.Vec3f) {
@ -129,7 +124,9 @@ func main() {
Width := uint(*width)
Height := uint(*height)
var timer hrend.FrameTimer
var fb hrend.Framebuffer
var drawFunc func()
if IsRealtime() {
rl.InitWindow(int32(Width), int32(Height), "Simple renderer with raylib")
@ -141,32 +138,38 @@ func main() {
defer rl.UnloadImageColors(rfb.Data)
defer rl.UnloadImage(rfb.Image)
fb = rfb
drawFunc = func() {
rl.UpdateTexture(rfb.Texture, rfb.Data)
rl.BeginDrawing()
rl.ClearBackground(rl.RayWhite)
rl.DrawTexture(rfb.Texture, 0, 0, rl.White)
rl.DrawText(fmt.Sprintf("Frame: %.2fms", timer.LastAverage.Seconds()*1000), 5, 5, 20, rl.Red)
rl.EndDrawing()
}
} else {
}
rb := hrend.NewRenderbuffer(fb, Width, Height)
//o, texture := loadDefault()
var thing hrend.Vec2i
log.Print(thing)
var projection, viewport hrend.Mat44f
// Generate world
wtexraw := Checkerboard([]color.Color{color.RGBA{R: 255, G: 0, B: 0, A: 255}, color.RGBA{R: 0, G: 0, B: 255, A: 255}}, 32)
wtex := hrend.NewTexture(wtexraw, 1)
world := FlatTerrain(10)
// These don't really change
var projection, viewport hrend.Mat44f
projection.SetProjection(float32(FOV), float32(Width)/float32(Height), NearClip, FarClip)
viewport.SetViewportSimple(int(Width), int(Height), 1) //65535)
var timer hrend.FrameTimer
camtrans := hrend.Vec3f{X: 0, Y: 0, Z: ZOffset}
var camera hrend.Mat44f
var newcamtrans hrend.Vec3f
camtrans := hrend.Vec3f{X: 0, Y: YOffset, Z: ZOffset}
camup := hrend.Vec3f{X: 0, Y: 1, Z: 0}
// In our system, 0 degree yaw is facing -Z, into the scene
yaw := float32(0)
pitch := float32(math.Pi / 2) // Start looking flat
var camera hrend.Mat44f
log.Printf("Starting render loop")
for !rl.WindowShouldClose() {
@ -174,7 +177,7 @@ func main() {
yaw, pitch, newcamtrans = CameraInput(yaw, pitch)
camtrans = *camtrans.Add(&newcamtrans)
lookvec := camera.SetCamera(&camtrans, yaw, pitch, &camup)
_ = camera.SetCamera(&camtrans, yaw, pitch, &camup)
screenmat := camera.Inverse().Multiply(&projection)
screenmat = screenmat.Multiply(&viewport)
@ -186,37 +189,24 @@ func main() {
}
var sc [3]hrend.Vertex
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
for _, f := range world.Faces {
for i := range 3 {
sc[i] = f[i]
sc[i].Pos = screenmat.MultiplyPoint3(f[i].Pos)
}
l1 := f[2].Pos.Sub(&f[0].Pos)
n := l1.CrossProduct(f[1].Pos.Sub(&f[0].Pos))
n = n.Normalize()
intensity := n.MultSimp(&lookvec)
if intensity < 0 {
intensity = 0
}
hrend.TriangleTextured(&rb, texture, intensity, sc[0], sc[1], sc[2])
// l1 := f[2].Pos.Sub(&f[0].Pos)
// n := l1.CrossProduct(f[1].Pos.Sub(&f[0].Pos))
// n = n.Normalize()
// intensity := n.MultSimp(&lookvec)
// if intensity < 0 {
// intensity = 0
// }
hrend.TriangleTextured(&rb, wtex, 1.0, 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)
timer.Add(time.Since(start), 10)
if IsRealtime() {
rl.BeginDrawing()
rl.ClearBackground(rl.RayWhite)
rl.DrawTexture(fb.Texture, 0, 0, rl.White)
rl.DrawText(fmt.Sprintf("Frame: %.2fms", timer.LastAverage.Seconds()*1000), 5, 5, 20, rl.Red)
rl.EndDrawing()
} else {
}
drawFunc()
}
}

View File

@ -1,17 +0,0 @@
package main
import (
"image"
"image/color"
//"renderer1/hrend"
)
func Checkerboard(cols []color.Color, size int) image.Image {
result := image.NewRGBA(image.Rect(0, 0, size, size))
for y := range size {
for x := range size {
result.Set(x, y, cols[(x+y)%len(cols)])
}
}
return result
}