summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chickadee/graphics/model.scm5
-rw-r--r--chickadee/graphics/phong.scm29
-rw-r--r--data/shaders/phong-frag.glsl174
-rw-r--r--data/shaders/phong-vert.glsl6
4 files changed, 148 insertions, 66 deletions
diff --git a/chickadee/graphics/model.scm b/chickadee/graphics/model.scm
index 930687a..8636652 100644
--- a/chickadee/graphics/model.scm
+++ b/chickadee/graphics/model.scm
@@ -140,7 +140,10 @@
(shader-apply/phong (primitive-vertex-array primitive)
(primitive-material primitive)
(render-state-world-model-matrix state)
- (render-state-view-matrix state)))
+ (render-state-view-matrix state)
+ (render-state-camera-position state)
+ (render-state-lights state)
+ (render-state-ambient-light-color state)))
(define (draw-primitive/pbr primitive state)
(shader-apply/pbr (primitive-vertex-array primitive)
diff --git a/chickadee/graphics/phong.scm b/chickadee/graphics/phong.scm
index 372cdb6..f52f10b 100644
--- a/chickadee/graphics/phong.scm
+++ b/chickadee/graphics/phong.scm
@@ -26,6 +26,7 @@
#:use-module (chickadee math vector)
#:use-module (chickadee graphics color)
#:use-module (chickadee graphics engine)
+ #:use-module (chickadee graphics light)
#:use-module (chickadee graphics shader)
#:use-module (chickadee graphics texture)
#:use-module (srfi srfi-9)
@@ -87,27 +88,6 @@
;;;
-;;; Lights
-;;;
-
-(define-shader-type <directional-light>
- make-directional-light
- directional-light?
- (float-vec3 direction directional-light-direction)
- (float-vec3 ambient directional-light-ambient)
- (float-vec3 diffuse directional-light-diffuse)
- (float-vec3 specular directional-light-specular)
- (float shininess directional-light-shininess))
-
-(define default-directional-light
- (make-directional-light #:direction (vec3 0.0 0.0 -1.0)
- #:ambient (vec3 0.1 0.1 0.1)
- #:diffuse (vec3 1.0 1.0 1.0)
- #:specular (vec3 0.5 0.5 0.5)
- #:shininess 32.0))
-
-
-;;;
;;; Phong Shader
;;;
@@ -115,7 +95,8 @@
(load-shader (scope-datadir "shaders/phong-vert.glsl")
(scope-datadir "shaders/phong-frag.glsl")))
-(define (shader-apply/phong vertex-array material model-matrix view-matrix)
+(define (shader-apply/phong vertex-array material model-matrix view-matrix
+ camera-position lights ambient-light-color)
(let ((shader (graphics-variable-ref phong-shader)))
(with-graphics-state ((g:texture-0 (phong-material-ambient-map material))
(g:texture-1 (phong-material-diffuse-map material))
@@ -126,4 +107,6 @@
#:view view-matrix
#:projection (current-projection)
#:material material
- #:directional-light default-directional-light))))
+ ;; #:camera-position camera-position
+ #:ambient-light-color ambient-light-color
+ #:lights lights))))
diff --git a/data/shaders/phong-frag.glsl b/data/shaders/phong-frag.glsl
index ad324b3..84e9feb 100644
--- a/data/shaders/phong-frag.glsl
+++ b/data/shaders/phong-frag.glsl
@@ -15,17 +15,23 @@ struct Material {
bool useBumpMap;
};
-struct DirectionalLight {
+struct Light {
+ bool enabled;
+ int type;
+ vec3 position;
vec3 direction;
- vec3 ambient;
- vec3 diffuse;
- vec3 specular;
+ vec4 color;
+ float cutOff;
};
+#define MAX_LIGHTS 4
+
#ifdef GLSL120
+varying vec3 fragWorldPos;
varying vec3 fragNorm;
varying vec2 fragTex;
#else
+in vec3 fragWorldPos;
in vec3 fragNorm;
in vec2 fragTex;
#endif
@@ -35,55 +41,143 @@ out vec4 fragColor;
#endif
uniform Material material;
-uniform DirectionalLight directionalLight;
+uniform Light lights[MAX_LIGHTS];
+uniform vec3 cameraPosition;
+uniform vec4 ambientLightColor;
-void main() {
- vec3 baseAmbientColor;
- vec3 baseDiffuseColor;
- vec3 baseSpecularColor;
- if(material.useAmbientMap) {
-#ifdef GLSL330
- baseAmbientColor = texture(material.ambientMap, fragTex).xyz;
-#else
- baseAmbientColor = texture2D(material.ambientMap, fragTex).xyz;
+const float GAMMA = 2.2;
+
+#ifndef GLSL330
+// Compatibility shim for older GLSL versions.
+vec2 texture(sampler2D tex, vec2 coord) {
+ return texture2D(tex, coord);
+}
#endif
+
+float posDot(vec3 v1, vec3 v2) {
+ return max(dot(v1, v2), 0.0);
+}
+
+vec3 gammaCorrect(vec3 color) {
+ return pow(color, vec3(1.0 / GAMMA));
+}
+
+vec3 toneMap(vec3 color) {
+ return color / (color + vec3(1.0));
+}
+
+vec3 lightDirection(Light light) {
+ if(light.type == 0 || light.type == 2) { // point and spot lights
+ return normalize(light.position - fragWorldPos);
+ } else if(light.type == 1) { // directional light
+ return normalize(-light.direction);
+ }
+
+ return vec3(0.0); // should never be reached.
+}
+
+vec3 lightAttenuate(Light light) {
+ float distance = length(light.position - fragWorldPos);
+ float attenuation = 1.0 / (distance * distance);
+ return light.color.rgb * attenuation;
+}
+
+vec3 lightRadiance(Light light, vec3 direction) {
+ if(light.type == 0) { // point light
+ return lightAttenuate(light);
+ } else if(light.type == 1) { // directional light
+ return light.color.rgb;
+ } else if(light.type == 2) { // spot light
+ float theta = dot(direction, normalize(-light.direction));
+ // Spot lights only shine light in a specific conical area.
+ // They have no effect outside of that area.
+ if(theta > light.cutOff) {
+ // Feather out the light as it approaches the edge of its cone.
+ float intensity = (theta - light.cutOff) / (1.0 - light.cutOff);
+ return lightAttenuate(light) * intensity;
+ } else {
+ return vec3(0.0);
+ }
+ }
+
+ return vec3(0.0); // should never be reached.
+}
+
+vec3 materialAmbient() {
+ if(material.useAmbientMap) {
+ return texture(material.ambientMap, fragTex).rgb * material.ambient;
} else {
- baseAmbientColor = vec3(1.0, 1.0, 1.0);
+ return material.ambient;
}
+}
+
+vec3 materialDiffuse() {
if(material.useDiffuseMap) {
- // discard transparent fragments.
-#ifdef GLSL330
vec4 color = texture(material.diffuseMap, fragTex);
-#else
- vec4 color = texture2D(material.diffuseMap, fragTex);
-#endif
- if(color.a == 0.0) { discard; }
- baseDiffuseColor = color.xyz;
+ // discard transparent fragments.
+ if(color.a == 0.0) {
+ discard;
+ }
+ return color.rgb * material.diffuse;
} else {
- baseDiffuseColor = vec3(1.0, 1.0, 1.0);
+ return material.diffuse;
}
+}
+
+vec3 materialSpecular() {
if(material.useSpecularMap) {
-#ifdef GLSL330
- baseSpecularColor = texture(material.specularMap, fragTex).xyz;
-#else
- baseSpecularColor = texture2D(material.specularMap, fragTex).xyz;
-#endif
+ return texture(material.specularMap, fragTex).rgb * material.specular;
} else {
- baseSpecularColor = vec3(1.0, 1.0, 1.0);
+ return material.specular;
}
- vec3 ambientColor = material.ambient * baseAmbientColor * baseDiffuseColor;
- vec3 lightDir = normalize(-directionalLight.direction);
- float diffuseFactor = max(dot(lightDir, fragNorm), 0.0);
- vec3 diffuseColor = diffuseFactor * baseDiffuseColor * material.diffuse;
- vec3 reflectDir = reflect(-lightDir, fragNorm);
- float specularFactor = 0;
- if(material.shininess > 0) {
- specularFactor = pow(max(dot(lightDir, reflectDir), 0.0), material.shininess);
+}
+
+vec3 materialNormal() {
+ if(material.useBumpMap) {
+ return normalize(texture(material.bumpMap, fragTex).xyz * 2.0 - 1.0);
+ } else {
+ return fragNorm;
}
- vec3 specularColor = specularFactor * baseSpecularColor * material.specular;
+}
+
+void main() {
+ vec3 ambientOcclusion = materialAmbient();
+ vec3 baseDiffuseColor = materialDiffuse();
+ vec3 baseSpecularColor = materialSpecular();
+ vec3 normal = materialNormal();
+ vec3 color = vec3(0.0);
+
+ // Apply direct lighting.
+ for(int i = 0; i < MAX_LIGHTS; ++i) {
+ Light light = lights[i];
+
+ if(!light.enabled) {
+ continue;
+ }
+
+ vec3 lightDir = lightDirection(light);
+ vec3 radiance = lightRadiance(light, lightDir);
+ float diffuseFactor = posDot(lightDir, normal);
+ vec3 reflectDir = reflect(-lightDir, normal);
+ vec3 diffuseColor = baseDiffuseColor * diffuseFactor;
+ float specularFactor = 0;
+ if(material.shininess > 0) {
+ specularFactor = pow(posDot(lightDir, reflectDir), material.shininess);
+ }
+ vec3 specularColor = baseSpecularColor * specularFactor;
+ color += (diffuseColor + specularColor) * radiance;
+ }
+
+ // Apply ambient lighting.
+ vec3 ambientColor = baseDiffuseColor * ambientOcclusion * ambientLightColor.rgb;
+ color += ambientColor;
+
+ // Apply gamma correction and HDR tone mapping to get the final
+ // color.
+ vec4 finalColor = vec4(toneMap(gammaCorrect(color)), 1.0);
#ifdef GLSL330
- fragColor = vec4(ambientColor + diffuseColor + specularColor, 1.0);
+ fragColor = finalColor;
#else
- gl_FragColor = vec4(ambientColor + diffuseColor + specularColor, 1.0);
+ gl_FragColor = finalColor;
#endif
}
diff --git a/data/shaders/phong-vert.glsl b/data/shaders/phong-vert.glsl
index 51461fa..9b72eb3 100644
--- a/data/shaders/phong-vert.glsl
+++ b/data/shaders/phong-vert.glsl
@@ -15,9 +15,11 @@ attribute vec3 normal;
#endif
#ifdef GLSL120
+varying vec3 fragWorldPos;
varying vec3 fragNorm;
varying vec2 fragTex;
#else
+out vec3 fragWorldPos;
out vec3 fragNorm;
out vec2 fragTex;
#endif
@@ -27,8 +29,8 @@ uniform mat4 view;
uniform mat4 projection;
void main() {
- gl_Position = projection * view * model * vec4(position, 1.0);
- // TODO: Calculate normal matrix on CPU
+ fragWorldPos = vec3(model * vec4(position, 1.0));
fragNorm = normalize(model * vec4(normal, 1.0)).xyz;
fragTex = texcoord;
+ gl_Position = projection * view * vec4(fragWorldPos, 1.0);
}