Reputation: 15987
I'm drawing some static geometry (a sphere, a cube, etc.) together with some dynamic geometry (a rotating torus.)
I can see that there is a problem because specular lighting on the torus is static and the torus is rendered dark when the rotation angle changes...
I'm targeting OpenGL 2.1 (desktop), OpenGL ES2 (mobile) and WebGL1 (web). Here is a gist with the full code. There is also a WebGL demo.
The framework used is chronotext-cross. It provides a level of abstraction above GL. It should be straightforward to understand. In any case I can provide pointers, as the author.
The C++ code, abridged:
void Sketch::setup()
{
Box()
.setFrontFace(CCW)
.setColor(0.75f, 0.75f, 0.75f, 1)
.setSize(300, 5, 300)
.append(geometryBatch, Matrix().translate(-150, -5, -150));
Sphere()
.setFrontFace(CCW)
.setColor(0.25f, 1.0f, 0.0f, 1)
.setSectorCount(60)
.setStackCount(30)
.setRadius(40)
.append(geometryBatch, Matrix().translate(-75, -40, 100));
Torus()
.setFrontFace(CCW)
.setSliceCount(20)
.setLoopCount(60)
.setInnerRadius(12)
.setOuterRadius(48)
.append(torusBatch, Matrix());
}
void Sketch::resize()
{
camera
.setFov(45)
.setClip(0.1f, 1000.0f)
.setWindowSize(windowInfo.size);
}
void Sketch::draw()
{
camera.getViewMatrix()
.setIdentity()
.scale(1, -1, 1)
.translate(0, 0, -400)
.rotateX(-30 * D2R)
.rotateY(15 * D2R);
State state;
state
.setShader(shader)
.setShaderMatrix<MODEL>(Matrix())
.setShaderMatrix<VIEW>(camera.getViewMatrix())
.setShaderMatrix<PROJECTION>(camera.getProjectionMatrix())
.setShaderMatrix<NORMAL>(camera.getNormalMatrix())
.setShaderUniform("u_eye_position", camera.getEyePosition())
.setShaderUniform("u_light_position", camera.getEyePosition())
.setShaderUniform("u_shininess", 50.0f)
.apply();
geometryBatch.flush();
Matrix modelMatrix;
modelMatrix
.translate(75, -60, 100)
.rotateY(clock()->getTime());
state
.setShaderMatrix<MODEL>(modelMatrix)
.apply();
torusBatch.flush();
}
The vertex shader:
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec4 a_color;
attribute vec2 a_coord;
uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform mat3 u_normal_matrix;
uniform vec3 u_eye_position;
uniform vec3 u_light_position;
varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
varying vec3 v_surface_to_light;
varying vec3 v_surface_to_view;
void main() {
v_normal = u_normal_matrix * a_normal;
v_color = a_color;
v_coord = a_coord;
v_surface_to_light = (u_view_matrix * (vec4(u_light_position, 1.0) - a_position)).xyz;
v_surface_to_view = (u_view_matrix * (vec4(u_eye_position, 1.0) - a_position)).xyz;
gl_Position = u_projection_matrix * u_view_matrix * u_model_matrix * a_position;
}
The fragment shader:
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D u_sampler;
uniform float u_shininess;
varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
varying vec3 v_surface_to_light;
varying vec3 v_surface_to_view;
void main() {
vec3 normal = normalize(v_normal);
vec3 surfaceToLightDirection = normalize(v_surface_to_light);
vec3 surfaceToViewDirection = normalize(v_surface_to_view);
vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);
float specular = 0.0;
float light = dot(normal, surfaceToLightDirection);
if (light > 0.0) {
specular = pow(dot(normal, halfVector), u_shininess);
}
vec4 color = v_color * texture2D(u_sampler, v_coord);
gl_FragColor = vec4(color.rgb * light + specular, 1.0);
}
Upvotes: 1
Views: 331
Reputation: 15987
I found the solution: passing a new normal matrix (extracted from the model-view matrix) to the shader when drawing the dynamic mesh.
Matrix modelMatrix;
modelMatrix
.translate(75, -60, 100)
.rotateY(clock()->getTime());
Matrix modelViewMatrix = modelMatrix * camera.getViewMatrix();
state
.setShaderMatrix<MODEL>(modelMatrix)
.setShaderMatrix<NORMAL>(modelViewMatrix.getNormalMatrix())
.apply();
Upvotes: 1