High-Level Shading Language code sample This sample in
High-Level Shading Language is a method of determining the diffuse and specular light from a point light. The light structure, position in space of the surface, view direction vector and the normal of the surface are passed through. A Lighting structure is returned; The below also needs to clamp certain dot products to zero in the case of negative answers. Without that, light heading away from the camera is treated the same way as light heading towards it. For the specular calculation, an incorrect "halo" of light glancing off the edges of an object and away from the camera might appear as bright as the light directly being reflected towards the camera. struct Lighting { float3 Diffuse; float3 Specular; }; struct PointLight { float3 position; float3 diffuseColor; float diffusePower; float3 specularColor; float specularPower; }; Lighting GetPointLight(PointLight light, float3 pos3D, float3 viewDir, float3 normal) { Lighting OUT; if (light.diffusePower > 0) { float3 lightDir = light.position - pos3D; //3D position in space of the surface float distance = length(lightDir); lightDir = lightDir / distance; // = normalize(lightDir); distance = distance * distance; //Intensity of the diffuse light. Saturate to keep within the 0-1 range. float NdotL = dot(normal, lightDir); float diffuseIntensity = saturate(NdotL); // Calculate the diffuse light factoring in light color, power and the attenuation OUT.Diffuse = diffuseIntensity * light.diffuseColor * light.diffusePower / distance; //Calculate the half vector between the light vector and the view vector. float3 H = normalize(lightDir + viewDir); //Intensity of the specular light float NdotH = dot(normal, H); float specularIntensity = pow(saturate(NdotH), specularHardness); //Sum up the specular light factoring OUT.Specular = specularIntensity * light.specularColor * light.specularPower / distance; } return OUT; }
OpenGL Shading Language code sample This sample in the
OpenGL Shading Language consists of two code files, or
shaders. The first one is a so-called
vertex shader and implements
Phong shading, which is used to interpolate the surface normal between vertices. The second shader is a so-called
fragment shader and implements the Blinn–Phong shading model in order to determine the diffuse and specular light from a point light source.
Vertex shader This
vertex shader implements
Phong shading: attribute vec3 inputPosition; attribute vec3 inputNormal; uniform mat4 projection, modelview, normalMat; varying vec3 normalInterp; varying vec3 vertPos; void main() { gl_Position = projection * modelview * vec4(inputPosition, 1.0); // modelview is an affine transformation, so w should be 1.0 vec4 vertPos4 = modelview * vec4(inputPosition, 1.0); vertPos = vec3(vertPos4).xyz; normalInterp = vec3(normalMat * vec4(inputNormal, 0.0)); }
Fragment shader This fragment shader implements the Blinn–Phong shading model and
gamma correction: precision mediump float; in vec3 normalInterp; in vec3 vertPos; uniform int mode; const vec3 lightPos = vec3(1.0, 1.0, 1.0); const vec3 lightColor = vec3(1.0, 1.0, 1.0); const float lightPower = 40.0; const vec3 ambientColor = vec3(0.1, 0.0, 0.0); const vec3 diffuseColor = vec3(0.5, 0.0, 0.0); const vec3 specColor = vec3(1.0, 1.0, 1.0); const float shininess = 16.0; const float screenGamma = 2.2; // Assume the monitor is calibrated to the sRGB color space void main() { vec3 normal = normalize(normalInterp); vec3 lightDir = lightPos - vertPos; float distance = dot(lightDir, lightDir); lightDir = normalize(lightDir); float lambertian = max(dot(lightDir, normal), 0.0); float specular = 0.0; if (lambertian > 0.0) { vec3 viewDir = normalize(-vertPos); // this is blinn phong vec3 halfDir = normalize(lightDir + viewDir); float specAngle = max(dot(halfDir, normal), 0.0); specular = pow(specAngle, shininess); // this is phong (for comparison) if (mode == 2) { vec3 reflectDir = reflect(-lightDir, normal); specAngle = max(dot(reflectDir, viewDir), 0.0); // note that the exponent is different here specular = pow(specAngle, shininess/4.0); } } vec3 colorLinear = ambientColor + diffuseColor * lambertian * lightColor * lightPower / distance + specColor * specular * lightColor * lightPower / distance; // apply gamma correction (assume ambientColor, diffuseColor and specColor // have been linearized, i.e. have no gamma correction in them) vec3 colorGammaCorrected = pow(colorLinear, vec3(1.0 / screenGamma)); // use the gamma corrected color in the fragment gl_FragColor = vec4(colorGammaCorrected, 1.0); } The colors , and are not supposed to be
gamma corrected. If they are colors obtained from gamma-corrected image files (
JPEG,
PNG, etc.), they need to be linearized before working with them, which is done by scaling the channel values to the range and raising them to the gamma value of the image, which for images in the
sRGB color space can be assumed to be about 2.2 (even though for this specific color space, a simple power relation is just an approximation of the actual
transformation). Modern graphics
APIs have the ability to perform this gamma correction automatically when sampling from a
texture or writing to a
framebuffer. == See also ==