commit b2d0180669048d007691ba434db948042d6adbc7
parent e928a2c0591c263868bec114b939b1f6c684200d
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Wed, 27 Nov 2024 08:53:22 +0900
muptiple lights
Diffstat:
5 files changed, 147 insertions(+), 34 deletions(-)
diff --git a/cmd/sample/fragment.glsl b/cmd/sample/fragment.glsl
@@ -13,6 +13,15 @@ struct DirLight {
 	vec3 Specular;
 };
 
+struct PointLight {
+	vec3 Pos;
+	vec3 Ambient;
+	vec3 Diffuse;
+	vec3 Specular;
+
+	float Kc, Kl, Kq;
+};
+
 struct SpotLight {
 	vec3 Pos;
 	vec3 Dir;
@@ -23,6 +32,7 @@ struct SpotLight {
 	float Kc, Kl, Kq;
 	float CutOff, OuterCutOff;
 };
+
 in vec3 fnormal;
 in vec3 fpos;
 in vec2 texPos;
@@ -32,18 +42,46 @@ uniform vec3 objCol;
 uniform Material Cube;
 uniform DirLight Sun;
 uniform SpotLight Light;
+uniform PointLight PointLights[10];
 
 out vec4 fcol;
 
+vec3 calcPointLight(PointLight, Material, vec3);
 vec3 calcSpotLight(SpotLight, Material, vec3);
 vec3 calcDirLight(DirLight, Material, vec3);
 
 void main() {
 	fcol = vec4(0, 0, 0, 1);
 	fcol += vec4(calcSpotLight(Light, Cube, CamPos), 0);
-	fcol += vec4(calcDirLight(Sun, Cube, CamPos), 0);
+//	fcol += vec4(calcDirLight(Sun, Cube, CamPos), 0);
+	for (int i = 0; i < PointLights.length(); i++) {
+		fcol += vec4(calcPointLight(PointLights[i], Cube, CamPos), 0);
+	}
 }
 
+vec3 calcPointLight(PointLight l, Material m, vec3 camPos) {
+	vec3 ambient, diffuse, specular;
+	vec3 lightDir, viewDir, reflectDir;
+	float diff, spec, dist, attenuation;
+
+	dist = length(l.Pos - fpos);
+	attenuation = 1 / (l.Kc + l.Kl * dist + l.Kq * dist * dist);
+
+	ambient = vec3(texture(m.Diffuse, texPos)) * l.Ambient;
+
+	lightDir = normalize(l.Pos - fpos);
+	diff = max(dot(fnormal, lightDir), 0.0);
+	diffuse = diff * vec3(texture(m.Diffuse, texPos)) * l.Diffuse;
+
+	viewDir = normalize(camPos - fpos);
+	reflectDir = reflect(-lightDir, normalize(fnormal));
+	spec = pow(max(dot(viewDir, reflectDir), 0.0), m.Shiness);
+	specular = vec3(texture(m.Specular, texPos)) * spec * l.Specular;
+
+	return (ambient + diffuse + specular) * attenuation;
+}
+
+
 vec3 calcSpotLight(SpotLight l, Material m, vec3 camPos) {
 	vec3 ambient, diffuse, specular;
 	vec3 lightDir, viewDir, reflectDir;
diff --git a/cmd/sample/main.go b/cmd/sample/main.go
@@ -83,6 +83,14 @@ type SpotLight struct {
 	OuterCutOff float32
 }
 
+type PointLight struct {
+	Pos        tofu.Vec3
+	Ambient    tofu.Vec3
+	Diffuse    tofu.Vec3
+	Specular   tofu.Vec3
+	Kc, Kl, Kq float32
+}
+
 var (
 	sunCol = tofu.Vec3{1, 1, 1}
 	sun    = &DirLight{
@@ -102,6 +110,8 @@ var (
 		Kl:          0.0009,
 		Kq:          0.00032,
 	}
+	pointLights           = make([]PointLight, 10)
+	pointLightDiv float32 = 10.0
 )
 
 var teapot *tofu.Object
@@ -164,25 +174,19 @@ var light = &tofu.Object{
 		{0.0, 1.0, 0.0},
 		{0.0, 0.0, 1.0},
 	},
-	TexCoords: []tofu.Vec2{
-		tofu.Vec2{1.0, 1.0},
-		tofu.Vec2{1.0, 0.0},
-		tofu.Vec2{0.0, 0.0},
-		tofu.Vec2{0.0, 1.0},
-	},
 	Faces: []tofu.Face{
-		{{0, 0, 0}, {1, 0, 1}, {2, 0, 2}},
-		{{0, 0, 0}, {2, 0, 2}, {3, 0, 3}},
-		{{0, 1, 0}, {1, 1, 1}, {5, 1, 2}},
-		{{0, 1, 0}, {5, 1, 2}, {4, 1, 3}},
-		{{1, 2, 0}, {2, 2, 1}, {6, 2, 2}},
-		{{1, 2, 0}, {6, 2, 2}, {5, 2, 3}},
-		{{2, 3, 0}, {3, 3, 1}, {7, 3, 2}},
-		{{2, 3, 0}, {7, 3, 2}, {6, 3, 3}},
-		{{3, 4, 0}, {0, 4, 1}, {4, 4, 2}},
-		{{3, 4, 0}, {4, 4, 2}, {7, 4, 3}},
-		{{4, 5, 0}, {5, 5, 1}, {6, 5, 2}},
-		{{4, 5, 0}, {6, 5, 2}, {7, 5, 3}},
+		{{0, 0, tofu.NoIndex}, {1, 0, tofu.NoIndex}, {2, 0, tofu.NoIndex}},
+		{{0, 0, tofu.NoIndex}, {2, 0, tofu.NoIndex}, {3, 0, tofu.NoIndex}},
+		{{0, 1, tofu.NoIndex}, {1, 1, tofu.NoIndex}, {5, 1, tofu.NoIndex}},
+		{{0, 1, tofu.NoIndex}, {5, 1, tofu.NoIndex}, {4, 1, tofu.NoIndex}},
+		{{1, 2, tofu.NoIndex}, {2, 2, tofu.NoIndex}, {6, 2, tofu.NoIndex}},
+		{{1, 2, tofu.NoIndex}, {6, 2, tofu.NoIndex}, {5, 2, tofu.NoIndex}},
+		{{2, 3, tofu.NoIndex}, {3, 3, tofu.NoIndex}, {7, 3, tofu.NoIndex}},
+		{{2, 3, tofu.NoIndex}, {7, 3, tofu.NoIndex}, {6, 3, tofu.NoIndex}},
+		{{3, 4, tofu.NoIndex}, {0, 4, tofu.NoIndex}, {4, 4, tofu.NoIndex}},
+		{{3, 4, tofu.NoIndex}, {4, 4, tofu.NoIndex}, {7, 4, tofu.NoIndex}},
+		{{4, 5, tofu.NoIndex}, {5, 5, tofu.NoIndex}, {6, 5, tofu.NoIndex}},
+		{{4, 5, tofu.NoIndex}, {6, 5, tofu.NoIndex}, {7, 5, tofu.NoIndex}},
 	},
 }
 
@@ -221,11 +225,12 @@ var cubeUniforms = struct {
 	CamPos tofu.Vec3
 	Trans  Trans
 	Cube   MaterialTexture
-	Sun    *DirLight
-	Light  *SpotLight
+	//	Sun         *DirLight
+	Light       *SpotLight
+	PointLights []PointLight
 }{
-	Cube:  MaterialTexture{Shiness: 32},
-	Sun:   sun,
+	Cube: MaterialTexture{Shiness: 32},
+	//	Sun:   sun,
 	Light: spotLight,
 }
 
@@ -233,15 +238,16 @@ var teapotUniforms = struct {
 	CamPos tofu.Vec3
 	Trans  Trans
 	Teapot Material
-	Sun    *DirLight
-	Light  *SpotLight
+	//Sun         *DirLight
+	Light       *SpotLight
+	PointLights []PointLight
 }{
 	Teapot: Material{
 		Diffuse:  tofu.Vec3{0.3, 0.4, 0.4},
 		Specular: tofu.Vec3{0.3, 0.4, 0.4},
 		Shiness:  32,
 	},
-	Sun:   sun,
+	//Sun:   sun,
 	Light: spotLight,
 }
 
@@ -294,7 +300,7 @@ func (app *App) Update() error {
 			Mul(tofu.Rotate(now*app.cubeRotate[i].vel, app.cubeRotate[i].axis))
 		cubeUniforms.Trans.Model = model
 		if err := app.program.SetUniforms(); err != nil {
-			log.Println("setuniforms:", err)
+			log.Println("program.setuniforms:", err)
 		}
 		cube.Draw(app.program)
 	}
@@ -313,11 +319,20 @@ func (app *App) Update() error {
 	lightUniforms.Trans.View = view
 	lightUniforms.Trans.Projection = projection
 	lightUniforms.Trans.Model = lightModel
+	lightUniforms.LightCol = spotLightCol
 	if err := app.lightProgram.SetUniforms(); err != nil {
 		log.Printf("lightprogram.setuniforms(): %v", err)
 	}
-
 	light.Draw(app.lightProgram)
+	for _, pl := range pointLights {
+		lightUniforms.Trans.Model = tofu.Translate(pl.Pos).
+			Mul(tofu.Scale(0.3))
+		lightUniforms.LightCol = pl.Specular
+		if err := app.lightProgram.SetUniforms(); err != nil {
+			log.Printf("lightprogram.setuniforms(): %v", err)
+		}
+		light.Draw(app.lightProgram)
+	}
 
 	return nil
 }
@@ -396,7 +411,23 @@ func main() {
 	if err != nil {
 		log.Fatalf("NewTesture: %v", err)
 	}
-
+	for i, _ := range pointLights {
+		col := tofu.Vec3{rand.Float32(), rand.Float32(), rand.Float32()}
+		pointLights[i] = PointLight{
+			Pos: tofu.Vec3{
+				(rand.Float32() - 0.5) * pointLightDiv,
+				(rand.Float32() - 0.5) * pointLightDiv,
+				(rand.Float32() - 0.5) * pointLightDiv},
+			Ambient:  col.MulF(0.3),
+			Diffuse:  col.MulF(0.6),
+			Specular: col,
+			Kc:       1.0,
+			Kl:       0.009,
+			Kq:       0.0032,
+		}
+	}
+	cubeUniforms.PointLights = pointLights
+	teapotUniforms.PointLights = pointLights
 	camera = tofu.NewCamera()
 	camera.MoveTo(tofu.Vec3{0, 0, 3})
 	camera.LookAt(tofu.Vec3{0, 0, 0})
diff --git a/cmd/sample/teapot.glsl b/cmd/sample/teapot.glsl
@@ -12,7 +12,14 @@ struct DirLight {
 	vec3 Diffuse;
 	vec3 Specular;
 };
+struct PointLight {
+	vec3 Pos;
+	vec3 Ambient;
+	vec3 Diffuse;
+	vec3 Specular;
 
+	float Kc, Kl, Kq;
+};
 struct SpotLight {
 	vec3 Pos;
 	vec3 Dir;
@@ -32,16 +39,43 @@ uniform vec3 objCol;
 uniform Material Teapot;
 uniform DirLight Sun;
 uniform SpotLight Light;
+uniform PointLight PointLights[10];
 
 out vec4 fcol;
 
+vec3 calcPointLight(PointLight, Material, vec3);
 vec3 calcSpotLight(SpotLight, Material, vec3);
 vec3 calcDirLight(DirLight, Material, vec3);
 
 void main() {
 	fcol = vec4(0, 0, 0, 1);
 	fcol += vec4(calcSpotLight(Light, Teapot, CamPos), 0);
-	fcol += vec4(calcDirLight(Sun, Teapot, CamPos), 0);
+//	fcol += vec4(calcDirLight(Sun, Teapot, CamPos), 0);
+	for (int i = 0; i < PointLights.length(); i++) {
+		fcol += vec4(calcPointLight(PointLights[i], Teapot, CamPos), 0);
+	}
+}
+
+vec3 calcPointLight(PointLight l, Material m, vec3 camPos) {
+	vec3 ambient, diffuse, specular;
+	vec3 lightDir, viewDir, reflectDir;
+	float diff, spec, dist, attenuation;
+
+	dist = length(l.Pos - fpos);
+	attenuation = 1 / (l.Kc + l.Kl * dist + l.Kq * dist * dist);
+
+	ambient = m.Diffuse * l.Ambient;
+
+	lightDir = normalize(l.Pos - fpos);
+	diff = max(dot(fnormal, lightDir), 0.0);
+	diffuse = diff * m.Diffuse * l.Diffuse;
+
+	viewDir = normalize(camPos - fpos);
+	reflectDir = reflect(-lightDir, fnormal);
+	spec = pow(max(dot(viewDir, reflectDir), 0.0), m.Shiness);
+	specular = m.Specular * spec * l.Specular;
+
+	return (ambient + diffuse + specular) * attenuation;
 }
 
 vec3 calcSpotLight(SpotLight l, Material m, vec3 camPos) {
diff --git a/shader.go b/shader.go
@@ -33,7 +33,11 @@ func compileShader(path string, xtype uint32) (shaderID uint32, err error) {
 		l := gl.Str(strings.Repeat("\x00", int(logLength)))
 		gl.GetShaderInfoLog(shaderID, logLength, nil, l)
 		gl.DeleteShader(shaderID)
-		return 0, fmt.Errorf("%v", gl.GoStr(l)[2:])
+		errmsg := gl.GoStr(l)
+		if strings.HasPrefix(errmsg, "0:") {
+			errmsg = errmsg[2:]
+		}
+		return 0, fmt.Errorf("%v", errmsg)
 	}
 	return shaderID, nil
 }
@@ -135,12 +139,18 @@ func (p *Program) setUniforms(uniforms any, prefix string) error {
 				if err := p.setUniforms(fv.Interface(), tag); err != nil {
 					return err
 				}
-				continue
 			case reflect.Pointer:
 				if err := p.setUniforms(fv.Elem().Interface(), tag); err != nil {
 					return err
 				}
-				continue
+			case reflect.Slice:
+				for i := 0; i < fv.Len(); i++ {
+					item := fv.Index(i).Interface()
+					tagi := fmt.Sprintf("%s[%d]", tag, i)
+					if err := p.setUniforms(item, tagi); err != nil {
+						return err
+					}
+				}
 			default:
 				return fmt.Errorf("unknown uniform type: %s", ft.Type)
 			}
diff --git a/tofu.go b/tofu.go
@@ -94,7 +94,7 @@ func Run(app App) error {
 	}
 
 	for !window.ShouldClose() {
-		gl.ClearColor(1.0, 1.0, 0.918, 1.0)
+		gl.ClearColor(0.3, 0.3, 0, 1.0)
 		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
 		err := app.Update()
 		if err == Termination {