302 lines
7.8 KiB
Elm
302 lines
7.8 KiB
Elm
module Shaders exposing (..)
|
|
|
|
import WebGL
|
|
|
|
|
|
{-| This shader uses Spherical Environment Mapping (SEM).
|
|
Here are some relevant links:
|
|
|
|
- [very cool demo](https://www.clicktorelease.com/code/spherical-normal-mapping/#)
|
|
- <https://www.clicktorelease.com/blog/creating-spherical-environment-mapping-shader>
|
|
- <http://www.ozone3d.net/tutorials/glsl_texturing_p04.php>
|
|
|
|
-}
|
|
reflectionVert =
|
|
[glsl|
|
|
|
|
attribute vec3 position;
|
|
attribute vec3 normal;
|
|
uniform mat4 mvMat;
|
|
uniform mat4 camera;
|
|
varying vec3 vNormal;
|
|
|
|
void main()
|
|
{
|
|
vec4 vertex4 = mvMat * vec4(position, 1.0);
|
|
vNormal = vec3(mvMat * vec4(normal, 0.0));
|
|
vec3 nm_z = normalize(vec3(vertex4));
|
|
vec3 nm_x = cross(nm_z, vec3(0.0, 1.0, 0.0));
|
|
vec3 nm_y = cross(nm_x, nm_z);
|
|
vNormal = vec3(dot(vNormal, nm_x), dot(vNormal, nm_y), dot(vNormal, nm_z));
|
|
gl_Position = camera * vertex4;
|
|
}
|
|
|
|
|]
|
|
|
|
|
|
reflectionFrag =
|
|
[glsl|
|
|
precision mediump float;
|
|
|
|
uniform sampler2D texture;
|
|
|
|
varying vec3 vNormal;
|
|
|
|
void main()
|
|
{
|
|
vec2 texCoord = vec2(0.5 * vNormal.x + 0.5, - 0.5 * vNormal.y - 0.5);
|
|
vec4 fragColor = texture2D(texture, texCoord);
|
|
fragColor.a = 1.0;
|
|
|
|
gl_FragColor = fragColor;
|
|
}
|
|
|
|
|]
|
|
|
|
|
|
{-| normal mapping according to:
|
|
<http://www.gamasutra.com/blogs/RobertBasler/20131122/205462/Three_Normal_Mapping_Techniques_Explained_For_the_Mathematically_Uninclined.php?print=1>
|
|
-}
|
|
normalVert =
|
|
[glsl|
|
|
attribute vec3 position;
|
|
attribute vec3 normal;
|
|
attribute vec2 texCoord;
|
|
attribute vec4 tangent;
|
|
|
|
varying vec2 vTexCoord;
|
|
varying vec3 vLightDirection;
|
|
varying vec3 vViewDirection;
|
|
|
|
|
|
uniform mat4 modelViewProjectionMatrix;
|
|
uniform mat4 modelMatrix;
|
|
uniform vec3 lightPosition;
|
|
uniform vec3 viewPosition;
|
|
|
|
mat3 transpose(mat3 m) {
|
|
return mat3(m[0][0], m[1][0], m[2][0],
|
|
m[0][1], m[1][1], m[2][1],
|
|
m[0][2], m[1][2], m[2][2]);
|
|
}
|
|
|
|
|
|
void main()
|
|
{
|
|
vec4 pos = vec4(position, 1.0 );
|
|
vec3 posWorld = (modelMatrix * pos).xyz;
|
|
|
|
// Tangent, Bitangent, Normal space matrix TBN
|
|
// this isn't entirely correct, it should use the normal matrix
|
|
// In this special case it works out well,
|
|
// since my model matrix does not contain any rotation or translation.
|
|
// http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/
|
|
vec3 n = normalize((modelMatrix * vec4(normal, 0.0)).xyz);
|
|
vec3 t = normalize((modelMatrix * vec4(tangent.xyz, 0.0)).xyz);
|
|
vec3 b = normalize((modelMatrix * vec4((cross(normal, tangent.xyz) * tangent.w), 0.0)).xyz);
|
|
mat3 tbn = transpose(mat3(t, b, n));
|
|
vLightDirection = tbn*(lightPosition - posWorld);
|
|
vViewDirection = tbn*(viewPosition - posWorld);
|
|
vTexCoord = texCoord;
|
|
gl_Position = modelViewProjectionMatrix * pos;
|
|
}
|
|
|]
|
|
|
|
|
|
normalFrag =
|
|
[glsl|
|
|
precision mediump float;
|
|
|
|
uniform sampler2D textureDiff;
|
|
uniform sampler2D textureNorm;
|
|
|
|
varying vec2 vTexCoord;
|
|
varying vec3 vLightDirection;
|
|
varying vec3 vViewDirection;
|
|
|
|
void main() {
|
|
|
|
vec3 lightDir = normalize(vLightDirection);
|
|
|
|
// Local normal, in tangent space
|
|
vec3 pixelNormal = normalize(texture2D(textureNorm, vTexCoord).rgb*2.0 - 1.0);
|
|
float lambert = max(dot(pixelNormal, lightDir), 0.0);
|
|
|
|
|
|
// diffuse + lambert
|
|
vec3 lightIntensities = vec3(1.5, 1.0, 1.0);
|
|
vec3 diffuseColor = texture2D(textureDiff, vTexCoord).rgb;
|
|
vec3 diffuse = lambert * diffuseColor * lightIntensities;
|
|
|
|
// ambient
|
|
vec3 ambient = 0.3 * diffuseColor;
|
|
|
|
// specular
|
|
float shininess = 32.0;
|
|
vec3 viewDir = normalize(vViewDirection);
|
|
vec3 reflectDir = reflect(-lightDir, pixelNormal);
|
|
vec3 halfwayDir = normalize(lightDir + viewDir);
|
|
float spec = pow(max(dot(pixelNormal, halfwayDir), 0.0), shininess);
|
|
vec3 specular = vec3(0.2) * spec * lightIntensities;
|
|
|
|
// attenuation
|
|
float lightAttenuation = 0.3;
|
|
float attenuation = 1.0 / (1.0 + lightAttenuation * pow(length(vLightDirection), 2.0));
|
|
|
|
vec3 final_color = ambient + (diffuse + specular) * attenuation;
|
|
gl_FragColor = vec4(final_color, 1.0);
|
|
}
|
|
|]
|
|
|
|
|
|
{-| same as the normal mapping shader, but without deforming normals.
|
|
-}
|
|
noNormalVert =
|
|
[glsl|
|
|
attribute vec3 position;
|
|
attribute vec3 normal;
|
|
attribute vec2 texCoord;
|
|
|
|
varying vec2 vTexCoord;
|
|
varying vec3 vLightDirection;
|
|
varying vec3 vViewDirection;
|
|
varying vec3 vNormal;
|
|
|
|
uniform mat4 modelViewProjectionMatrix;
|
|
uniform mat4 modelMatrix;
|
|
uniform vec3 lightPosition;
|
|
uniform vec3 viewPosition;
|
|
|
|
void main()
|
|
{
|
|
vec4 pos = vec4(position, 1.0 );
|
|
vec3 posWorld = (modelMatrix * pos).xyz;
|
|
|
|
vLightDirection = lightPosition - posWorld;
|
|
vViewDirection = viewPosition - posWorld;
|
|
vTexCoord = texCoord;
|
|
// this is incorrect, it should use the normal matrix
|
|
vNormal = mat3(modelMatrix) * normal;
|
|
gl_Position = modelViewProjectionMatrix * pos;
|
|
}
|
|
|]
|
|
|
|
|
|
noNormalFrag =
|
|
[glsl|
|
|
precision mediump float;
|
|
|
|
uniform sampler2D textureDiff;
|
|
|
|
varying vec2 vTexCoord;
|
|
varying vec3 vLightDirection;
|
|
varying vec3 vViewDirection;
|
|
varying vec3 vNormal;
|
|
|
|
void main()
|
|
{
|
|
vec3 lightDir = normalize(vLightDirection);
|
|
|
|
// lambert
|
|
vec3 pixelNormal = normalize(vNormal);
|
|
float lambert = max(dot(pixelNormal, lightDir), 0.0);
|
|
|
|
// diffuse + lambert
|
|
vec3 lightIntensities = vec3(1.5, 1.0, 1.0);
|
|
vec3 diffuseColor = texture2D(textureDiff, vTexCoord).rgb;
|
|
vec3 diffuse = lambert * diffuseColor * lightIntensities;
|
|
|
|
// ambient
|
|
vec3 ambient = 0.3 * diffuseColor;
|
|
|
|
// specular
|
|
float shininess = 32.0;
|
|
vec3 viewDir = normalize(vViewDirection);
|
|
vec3 reflectDir = reflect(-lightDir, pixelNormal);
|
|
vec3 halfwayDir = normalize(lightDir + viewDir);
|
|
float spec = pow(max(dot(pixelNormal, halfwayDir), 0.0), shininess);
|
|
vec3 specular = vec3(0.2) * spec * lightIntensities;
|
|
|
|
// attenuation
|
|
float lightAttenuation = 0.3;
|
|
float attenuation = 1.0 / (1.0 + lightAttenuation * pow(length(vLightDirection), 2.0));
|
|
|
|
vec3 final_color = ambient + (diffuse + specular) * attenuation;
|
|
gl_FragColor = vec4(final_color, 1.0);
|
|
}
|
|
|]
|
|
|
|
|
|
{-| same as above, but without any textures.
|
|
-}
|
|
simpleVert =
|
|
[glsl|
|
|
attribute vec3 position;
|
|
attribute vec3 normal;
|
|
|
|
varying vec3 vLightDirection;
|
|
varying vec3 vViewDirection;
|
|
varying vec3 vNormal;
|
|
|
|
uniform mat4 modelViewProjectionMatrix;
|
|
uniform mat4 modelMatrix;
|
|
uniform vec3 lightPosition;
|
|
uniform vec3 viewPosition;
|
|
|
|
void main()
|
|
{
|
|
vec4 pos = vec4(position, 1.0 );
|
|
vec3 posWorld = (modelMatrix * pos).xyz;
|
|
|
|
vLightDirection = lightPosition - posWorld;
|
|
vViewDirection = viewPosition - posWorld;
|
|
// this is incorrect, it should use the normal matrix, like this:
|
|
// vNormal = mat3(normalMatrix) * normal;
|
|
// it works in this case, since the modelMatrix is the identity matrix
|
|
vNormal = normal;
|
|
gl_Position = modelViewProjectionMatrix * pos;
|
|
}
|
|
|]
|
|
|
|
|
|
simpleFrag =
|
|
[glsl|
|
|
precision mediump float;
|
|
|
|
varying vec3 vLightDirection;
|
|
varying vec3 vViewDirection;
|
|
varying vec3 vNormal;
|
|
|
|
void main()
|
|
{
|
|
vec3 lightDir = normalize(vLightDirection);
|
|
|
|
// lambert
|
|
vec3 pixelNormal = normalize(vNormal);
|
|
float lambert = max(dot(pixelNormal, lightDir), 0.0);
|
|
|
|
// diffuse + lambert
|
|
vec3 lightIntensities = vec3(1.5, 1.0, 1.0);
|
|
vec3 diffuseColor = vec3(0.3, 0.2, 0.95);
|
|
vec3 diffuse = lambert * diffuseColor * lightIntensities;
|
|
|
|
// ambient
|
|
vec3 ambient = 0.2 * diffuseColor;
|
|
|
|
// specular
|
|
float shininess = 32.0;
|
|
vec3 viewDir = normalize(vViewDirection);
|
|
vec3 reflectDir = reflect(-lightDir, pixelNormal);
|
|
vec3 halfwayDir = normalize(lightDir + viewDir);
|
|
float spec = pow(max(dot(pixelNormal, halfwayDir), 0.0), shininess);
|
|
vec3 specular = vec3(0.2) * spec * lightIntensities;
|
|
|
|
// attenuation
|
|
float lightAttenuation = 0.3;
|
|
float attenuation = 1.0 / (1.0 + lightAttenuation * pow(length(vLightDirection), 2.0));
|
|
|
|
vec3 final_color = ambient + (diffuse + specular) * attenuation;
|
|
gl_FragColor = vec4(final_color, 1.0);
|
|
}
|
|
|]
|