Here is a comparison of the same mesh, with the same texture, rendered from the same point of view with and without shading.
The picture above, and the video below, both use a simple diffuse lighting calculation to shade the side of the earth which is facing away from the sun. This can be implemented as per vertex lighting, or per pixel lighting. Each method has pros and cons which I shall briefly discuss here. If I get anything wrong or leave something out please comment.
(Instead of using the diffuse value to shade the back side of the earth, I use it as a ratio in a multisample between a day and night time texture. Since the night time texture is already colored to show shade and darkness the result is the same but I also get lights from civilization on the dark side)
Per Vertex Lighting
- Diffuse value is calculated in the vertex shader.
- Faster since diffuse value is only calculated once per polygon and each pixel in the polygon has the same diffuse value (or is that 3 times per polygon, once per vertex, and the diffuse value is interpolated across the face of the poly?)
- Since the diffuse value is per vertex and not per pixel the value is not always correct and some shade popping occurs. Check out the video to see this.
attribute vec4 position;
attribute vec4 normal;
attribute vec2 uv0;
varying vec2 _uv0;
varying float _diffuse;
uniform mat4 modelViewProjectionMatrix;
uniform vec4 normalizedSunPosition;
void main()
{
//Texure coordinates are needed in fragment shader
_uv0 = uv0;
//Calculate diffuse value
vec4 nor = normalize(modelViewProjectionMatrix * normal);
_diffuse = max(dot(nor, normalizedSunPosition), 0.0);
//Translate vertex
gl_Position = modelViewProjectionMatrix * position;
}
Fragment Shader
varying lowp vec2 _uv0;
varying lowp float _diffuse;
uniform sampler2D dayTexture;
uniform sampler2D nightTexture;
void main()
{
gl_FragColor = (texture2D(nightTexture, _uv0) * (1.0 - _diffuse)) + (texture2D(dayTexture, _uv0) * _diffuse);
}
Per Pixel Shading
- Diffuse value is calculated in the fragment shader.
- Potentially slower as there are generally allot more pixels rendered than vertices and therefore allot more diffuse calculations.
- More realistic, smooth results.
attribute vec4 position;
attribute vec4 normal;
attribute vec2 uv0;
varying vec2 _uv0;
varying vec4 _normal;
uniform mat4 modelViewProjectionMatrix;
void main()
{
_uv0 = uv0;
_normal = normalize(modelViewProjectionMatrix * normal);
gl_Position = modelViewProjectionMatrix * position;
}
Fragment Shader
varying lowp vec2 _uv0;
varying lowp vec4 _normal;
uniform sampler2D dayTexture;
uniform sampler2D nightTexture;
uniform lowp vec4 normalizedSunPosition;
void main()
{
lowp float _diffuse = max(dot(_normal, normalizedSunPosition), 0.0);
gl_FragColor = (texture2D(nightTexture, _uv0) * (1.0 - _diffuse)) + (texture2D(dayTexture, _uv0) * _diffuse);
}
No comments:
Post a Comment