-
Couldn't load subscription status.
- Fork 9
8. Basic shading
If you have reached this point, you are getting a pretty solid ground for programming more advanced 3D stuff. This is the last essential tutorial. We will implement a shading technique into shader programs. Let's use suzanne model for this, along with new texture. As usual, save them in 'Assets' folder.
Store additional constant locations for shaders.
viewMatrixID = pipeline.getConstantLocation("V");
modelMatrixID = pipeline.getConstantLocation("M");
lightID = pipeline.getConstantLocation("lightPos");Load suzanne model instead.
var obj = new ObjLoader(Assets.blobs.suzanne_obj);Set shader uniforms.
g.setMatrix(modelMatrixID, model);
g.setMatrix(viewMatrixID, view);
// Set light position to (4, 4, 4)
g.setFloat3(lightID, 4, 4, 4);Now that everything is prepared, we can extend the shaders. Vertex shader follows.
#version 450
// Input vertex data, different for all executions of this shader
in vec3 pos;
in vec2 uv;
in vec3 nor;
// Output data: will be interpolated for each fragment
out vec2 vUV;
out vec3 positionWorldspace;
out vec3 normalCameraspace;
out vec3 eyeDirectionCameraspace;
out vec3 lightDirectionCameraspace;
// Values that stay constant for the whole mesh
uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
uniform vec3 lightPos;
void main() {
// Output position of the vertex, in clip space: MVP * position
gl_Position = MVP * vec4(pos, 1.0);
// Position of the vertex, in worldspace : M * position
positionWorldspace = (M * vec4(pos, 1.0)).xyz;
// Vector that goes from the vertex to the camera, in camera space.
// In camera space, the camera is at the origin (0,0,0).
vec3 vertexPositionCameraspace = (V * M * vec4(pos, 1.0)).xyz;
eyeDirectionCameraspace = vec3(0.0, 0.0, 0.0) - vertexPositionCameraspace;
// Vector that goes from the vertex to the light, in camera space. M is ommited because it's identity.
vec3 lightPositionCameraspace = (V * vec4(lightPos, 1.0)).xyz;
lightDirectionCameraspace = lightPositionCameraspace + eyeDirectionCameraspace;
// Normal of the the vertex, in camera space
normalCameraspace = (V * M * vec4(nor, 0.0)).xyz; // Only correct if modelMatrix does not scale the model! Use its inverse transpose if not.
// UV of the vertex. No special space for this one.
vUV = uv;
}Fragment shader.
#version 450
// Interpolated values from the vertex shaders
in vec2 vUV;
in vec3 positionWorldspace;
in vec3 normalCameraspace;
in vec3 eyeDirectionCameraspace;
in vec3 lightDirectionCameraspace;
// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;
uniform vec3 lightPos;
out vec4 fragColor;
void main() {
// Light emission properties
// You probably want to put them as uniforms
vec3 lightColor = vec3(1.0,1.0,1.0);
float lightPower = 50.0;
// Material properties
vec3 materialDiffuseColor = texture(myTextureSampler, vUV).rgb;
vec3 materialAmbientColor = vec3(0.1, 0.1, 0.1) * materialDiffuseColor;
vec3 materialSpecularColor = vec3(0.3, 0.3, 0.3);
// Distance to the light
float distance = length(lightPos - positionWorldspace);
// Normal of the computed fragment, in camera space
vec3 n = normalize(normalCameraspace);
// Direction of the light (from the fragment to the light)
vec3 l = normalize(lightDirectionCameraspace);
// Cosine of the angle between the normal and the light direction,
// clamped above 0
// - light is at the vertical of the triangle -> 1
// - light is perpendicular to the triangle -> 0
// - light is behind the triangle -> 0
float cosTheta = clamp(dot(n, l), 0.0, 1.0);
// Eye vector (towards the camera)
vec3 E = normalize(eyeDirectionCameraspace);
// Direction in which the triangle reflects the light
vec3 R = (-l) - 2.0 * dot(n, (-l)) * n;
//vec3 R = reflect(-l,n); // TODO: waiting for krafix fix
// Cosine of the angle between the Eye vector and the Reflect vector,
// clamped to 0
// - Looking into the reflection -> 1
// - Looking elsewhere -> < 1
float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
fragColor = vec4(vec3(
// Ambient: simulates indirect lighting
materialAmbientColor +
// Diffuse: "color" of the object
materialDiffuseColor * lightColor * lightPower * cosTheta / (distance * distance) +
// Specular: reflective highlight, like a mirror
materialSpecularColor * lightColor * lightPower * pow(cosAlpha, 5.0) / (distance * distance)
), 1.0);
}You can access complete sources here.
The result looks fabulous! Congratulations - you now posses a knownledge to create something really cool. And if you do, make sure to show us at forums or #kha irc channel at irc.ktxsoftware.com.

