commit 9cb807c52a03be40dd03fc91695b1efd4684638b
parent a3c25be3ed443829edb81e32c125b8ce4403cfea
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Wed, 20 Nov 2024 16:58:21 +0900
use reflect to upload uniforms
Diffstat:
2 files changed, 63 insertions(+), 18 deletions(-)
diff --git a/cmd/sample/main.go b/cmd/sample/main.go
@@ -75,8 +75,29 @@ func watchCursor(app *App) {
 	}
 }
 
-var teapot *tofu.Object
+type Uniform struct {
+	Sun
+}
 
+type Sun struct {
+	Dir      tofu.Vec3 `tofu:"sun.dir"`
+	Ambient  tofu.Vec3 `tofu:"sun.ambient"`
+	Diffuse  tofu.Vec3 `tofu:"sun.diffuse"`
+	Specular tofu.Vec3 `tofu:"sun.specular"`
+}
+
+var (
+	sunCol = tofu.Vec3{1, 1, 1}
+	sunDir = tofu.Vec3{-0.2, -1.0, -0.3}
+	sun    = Sun{
+		Dir:      sunDir,
+		Ambient:  sunCol.MulF(0.5),
+		Diffuse:  sunCol.MulF(0.3),
+		Specular: sunCol,
+	}
+)
+
+var teapot *tofu.Object
 var object = &tofu.Object{
 	Vertices: []tofu.Vec3{
 		tofu.Vec3{0.5, 0.5, -0.5},
@@ -116,6 +137,7 @@ var object = &tofu.Object{
 		{{4, 5, 0}, {5, 5, 1}, {6, 5, 2}},
 		{{4, 5, 0}, {6, 5, 2}, {7, 5, 3}},
 	},
+	Uniforms: Uniform{Sun: sun},
 }
 
 var cubePositions = []tofu.Vec3{
@@ -157,9 +179,6 @@ func (app *App) Update() error {
 	view := camera.View()
 	projection := tofu.Perspective(80*math.Pi/180, 800/600, 0.1, 100)
 
-	sunCol := tofu.Vec3{1, 1, 1}
-	sunDir := tofu.Vec3{-0.2, -1.0, -0.3}
-
 	lightCol := tofu.Vec3{1, 1, 1}
 	lightModel := tofu.Rotate(now, tofu.Vec3{0, 1, 0}).
 		Mul(tofu.Translate(tofu.Vec3{5, 4.5, 0})).
@@ -174,10 +193,6 @@ func (app *App) Update() error {
 	app.program.SetTexture("material.diffuse", app.texture)
 	app.program.SetTexture("material.specular", app.specularMap)
 	app.program.SetFloat32("material.shiness", 32)
-	app.program.SetVec3("sun.dir", sunDir)
-	app.program.SetVec3("sun.ambient", sunCol.MulF(0.5))
-	app.program.SetVec3("sun.diffuse", sunCol.MulF(0.3))
-	app.program.SetVec3("sun.specular", sunCol)
 	app.program.SetVec3("light.pos", lightPos)
 	app.program.SetVec3("light.dir", tofu.Vec3{0, 0, 0}.Sub(lightPos))
 	app.program.SetFloat32("light.cutOff", float32(math.Cos(25*math.Pi/180)))
@@ -192,7 +207,7 @@ func (app *App) Update() error {
 		model := tofu.Translate(p.Inverse())
 		//	Mul(tofu.Rotate(20*float32(i)+now, tofu.Vec3{math.Sqrt2 / 2, -math.Sqrt2 / 2, 0}))
 		app.program.SetMat4("model", model)
-		object.Draw()
+		object.Draw(app.program)
 	}
 	app.teapotProgram.Use()
 	app.teapotProgram.SetMat4("view", view)
@@ -202,28 +217,24 @@ func (app *App) Update() error {
 	app.teapotProgram.SetVec3("material.diffuse", tofu.Vec3{0.3, 0.4, 0.4})
 	app.teapotProgram.SetVec3("material.specular", tofu.Vec3{0.3, 0.4, 0.4})
 	app.teapotProgram.SetFloat32("material.shiness", 32)
-	app.teapotProgram.SetVec3("sun.dir", sunDir)
-	app.teapotProgram.SetVec3("sun.ambient", sunCol.MulF(0.5))
-	app.teapotProgram.SetVec3("sun.diffuse", sunCol.MulF(0.3))
-	app.teapotProgram.SetVec3("sun.specular", sunCol)
 	app.teapotProgram.SetVec3("light.pos", lightPos)
 	app.teapotProgram.SetVec3("light.dir", tofu.Vec3{0, 0, 0}.Sub(lightPos))
 	app.teapotProgram.SetFloat32("light.outerCutOff", float32(math.Cos(35*math.Pi/180)))
 	app.teapotProgram.SetFloat32("light.cutOff", float32(math.Cos(25*math.Pi/180)))
-	app.teapotProgram.SetVec3("light.ambient", lightCol.MulF(0.4))
-	app.teapotProgram.SetVec3("light.diffuse", lightCol.MulF(0.9))
+	app.teapotProgram.SetVec3("light.ambient", lightCol.MulF(0.9))
+	app.teapotProgram.SetVec3("light.diffuse", lightCol.MulF(0.1))
 	app.teapotProgram.SetVec3("light.specular", lightCol)
 	app.teapotProgram.SetFloat32("light.Kc", 1.0)
 	app.teapotProgram.SetFloat32("light.Kl", 0.0009)
 	app.teapotProgram.SetFloat32("light.Kq", 0.00032)
-	teapot.Draw()
+	teapot.Draw(app.teapotProgram)
 
 	app.lightProgram.Use()
 	app.program.SetMat4("view", view)
 	app.program.SetMat4("projection", projection)
 	app.program.SetMat4("model", lightModel)
 	app.lightProgram.SetVec3("lightCol", lightCol)
-	object.Draw()
+	object.Draw(app.lightProgram)
 
 	return nil
 }
@@ -261,6 +272,7 @@ func main() {
 		log.Fatal(err)
 	}
 	//	teapot.SetNormals()
+	teapot.Uniforms = sun
 	teapot.Load()
 
 	app.program, err = tofu.NewProgram(vpath, fpath)
diff --git a/object.go b/object.go
@@ -6,6 +6,7 @@ import (
 	"log"
 	"math"
 	"os"
+	"reflect"
 	"strconv"
 	"strings"
 
@@ -17,6 +18,7 @@ type Object struct {
 	TexCoords []Vec2
 	Normals   []Vec3
 	Faces     []Face
+	Uniforms  interface{}
 	vao       *VAO
 }
 
@@ -237,9 +239,40 @@ func (obj *Object) Load() {
 	obj.vao = newVAO(obj)
 }
 
-func (obj *Object) Draw() {
+func (obj *Object) setUniforms(prog *Program) {
+	if obj.Uniforms == nil {
+		return
+	}
+	setUniforms(obj.Uniforms, prog)
+}
+
+func setUniforms(uniforms interface{}, prog *Program) {
+	s := reflect.ValueOf(uniforms)
+	fields := reflect.VisibleFields(s.Type())
+	for i := 0; i < s.NumField(); i++ {
+		fv := s.Field(i)
+		ft := fields[i]
+		if fv.Kind() == reflect.Struct {
+			setUniforms(fv.Interface(), prog)
+			continue
+		}
+		tag, ok := ft.Tag.Lookup("tofu")
+		if !ok {
+			continue
+		}
+		switch ft.Type.String() {
+		case "tofu.Vec3":
+			log.Println(prog.SetVec3(tag, fv.Interface().(Vec3)))
+		default:
+			log.Printf("unknown uniform type: %s", ft.Type)
+		}
+	}
+}
+
+func (obj *Object) Draw(prog *Program) {
 	// TODO: performance?
 	obj.vao.bind()
+	obj.setUniforms(prog)
 	gl.DrawElements(gl.TRIANGLES,
 		int32(obj.stride()*3*len(obj.Faces)),
 		gl.UNSIGNED_INT, nil)