Skip to content

Commit

Permalink
Fixed|Model Renderer: Eye position for specular lighting
Browse files Browse the repository at this point in the history
Previously only the eye direction was passed to the shader, but
for accurate results, the eye direction has to be calculated separately
for each vertex. Now only the eye position in local space is given
to the shader.

Also fixed specular lighting from light sources on the wrong side of
surfaces.
  • Loading branch information
skyjake committed Jul 31, 2015
1 parent 953b5b0 commit bf296be
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 21 deletions.
10 changes: 5 additions & 5 deletions doomsday/apps/client/include/render/modelrenderer.h
Expand Up @@ -80,12 +80,12 @@ class ModelRenderer
/**
* Sets up the transformation matrices.
*
* @param eyeDir Direction of the eye in local space (relative to object).
* @param modelToLocal Transformation from model space to the object's local space
* (object's local frame in world space).
* @param localToView Transformation from local space to projected view space.
* @param relativeEyePos Position of the eye in relation to object (in world space).
* @param modelToLocal Transformation from model space to the object's local space
* (object's local frame in world space).
* @param localToView Transformation from local space to projected view space.
*/
void setTransformation(de::Vector3f const &eyeDir,
void setTransformation(de::Vector3f const &relativeEyePos,
de::Matrix4f const &modelToLocal,
de::Matrix4f const &localToView);

Expand Down
Expand Up @@ -8,7 +8,7 @@ group model {
uniform highp mat4 uMvpMatrix;
uniform highp mat4 uBoneMatrices[64];
uniform highp vec3 uLightDirs[4];
uniform highp vec3 uEyeDir;
uniform highp vec3 uEyePos;

attribute highp vec4 aVertex;
attribute highp vec3 aNormal;
Expand Down Expand Up @@ -60,7 +60,7 @@ group model {
vLightDirs[3] = uLightDirs[3] * tangentSpace;

// Eye direction in tangent space.
vEyeDir = uEyeDir * tangentSpace;
vEyeDir = (uEyePos - modelPos.xyz/modelPos.w) * tangentSpace;

vUV = aBounds.xy + aUV * aBounds.zw;
vNormalUV = aBounds2.xy + aUV * aBounds2.zw;
Expand Down Expand Up @@ -100,15 +100,21 @@ group model {
{
return vec4(0.0); // too dim
}
if(dot(vLightDirs[index], normal) < 0.0)
{
return vec4(0.0); // light on the wrong side
}

highp vec3 reflected = reflect(-vLightDirs[index], normal);

// Check the specular texture for parameters.
highp vec4 specular = texture2D(uTex, vSpecularUV);
highp float shininess = max(1.0, specular.a * 7.0);

highp float d = dot(vEyeDir, reflected) *
highp float d = dot(normalize(vEyeDir), reflected) *
shininess - max(0.0, shininess - 1.0);
return max(d * uLightIntensities[index], vec4(0.0)) *
return max(0.0, d) *
uLightIntensities[index] *
vec4(specular.rgb * 2.0, 1.0);
}

Expand Down
26 changes: 14 additions & 12 deletions doomsday/apps/client/src/render/modelrenderer.cpp
Expand Up @@ -50,7 +50,7 @@ DENG2_PIMPL(ModelRenderer)
GLProgram program; /// @todo Specific models may want to use a custom program.
GLUniform uMvpMatrix { "uMvpMatrix", GLUniform::Mat4 };
GLUniform uTex { "uTex", GLUniform::Sampler2D };
GLUniform uEyeDir { "uEyeDir", GLUniform::Vec3 };
GLUniform uEyePos { "uEyePos", GLUniform::Vec3 };
GLUniform uAmbientLight { "uAmbientLight", GLUniform::Vec4 };
GLUniform uLightDirs { "uLightDirs", GLUniform::Vec3Array, MAX_LIGHTS };
GLUniform uLightIntensities { "uLightIntensities", GLUniform::Vec4Array, MAX_LIGHTS };
Expand All @@ -71,7 +71,7 @@ DENG2_PIMPL(ModelRenderer)
ClientApp::shaders().build(program, "model.skeletal.normal_specular_emission")
<< uMvpMatrix
<< uTex
<< uEyeDir
<< uEyePos
<< uAmbientLight
<< uLightDirs
<< uLightIntensities;
Expand Down Expand Up @@ -297,12 +297,13 @@ ModelRenderer::StateAnims const *ModelRenderer::animations(DotPath const &modelI
return 0;
}

void ModelRenderer::setTransformation(Vector3f const &eyeDir, Matrix4f const &modelToLocal,
void ModelRenderer::setTransformation(Vector3f const &relativeEyePos,
Matrix4f const &modelToLocal,
Matrix4f const &localToView)
{
d->uMvpMatrix = localToView * modelToLocal;
d->inverseLocal = modelToLocal.inverse();
d->uEyeDir = (d->inverseLocal * eyeDir).normalize();
d->uEyePos = d->inverseLocal * relativeEyePos;
}

void ModelRenderer::setAmbientLight(Vector3f const &ambientIntensity)
Expand Down Expand Up @@ -344,29 +345,30 @@ void ModelRenderer::render(vissprite_t const &spr)
*/

drawmodel2params_t const &p = spr.data.model2;
gl::Cull culling = gl::Back;

Matrix4f viewMat =
Viewer_Matrix() *
Matrix4f::scale(Vector3f(1.0f, 1.0f/1.2f, 1.0f)) * // Inverse aspect correction.
Matrix4f::translate((spr.pose.origin + spr.pose.srvo).xzy());
Vector3d const modelWorldOrigin = (spr.pose.origin + spr.pose.srvo).xzy();

Matrix4f localMat =
Matrix4f modelToLocal =
Matrix4f::rotate(-90 + (spr.pose.viewAligned? spr.pose.yawAngleOffset :
spr.pose.yaw),
Vector3f(0, 1, 0) /* vertical axis for yaw */);
Matrix4f localToView =
Viewer_Matrix() *
Matrix4f::translate(modelWorldOrigin) *
Matrix4f::scale(Vector3f(1.0f, 1.0f/1.2f, 1.0f)); // Inverse aspect correction.

gl::Cull culling = gl::Back;
if(p.object)
{
auto const &mobjData = THINKER_DATA(p.object->thinker, ClientMobjThinkerData);
localMat = localMat * mobjData.modelTransformation();
modelToLocal = modelToLocal * mobjData.modelTransformation();
culling = mobjData.modelCullFace();
}

GLState::push().setCull(culling);

// Set up a suitable matrix for the pose.
setTransformation(Rend_EyeOrigin() - spr.pose.mid().xzy(), localMat, viewMat);
setTransformation(Rend_EyeOrigin() - modelWorldOrigin, modelToLocal, localToView);

// Ambient color and lighting vectors.
setAmbientLight(spr.light.ambientColor * .8f);
Expand Down

0 comments on commit bf296be

Please sign in to comment.