Skip to content

Instantly share code, notes, and snippets.

@alteredq
Created November 26, 2010 22:22
Show Gist options
  • Select an option

  • Save alteredq/717285 to your computer and use it in GitHub Desktop.

Select an option

Save alteredq/717285 to your computer and use it in GitHub Desktop.
Chromatic dispersion refraction hack
function generateFragmentShader( maxDirLights, maxPointLights ) {
var chunks = [
"#ifdef GL_ES",
"precision highp float;",
"#endif",
maxDirLights ? "#define MAX_DIR_LIGHTS " + maxDirLights : "",
maxPointLights ? "#define MAX_POINT_LIGHTS " + maxPointLights : "",
"uniform int material;", // 0 - Basic, 1 - Lambert, 2 - Phong, 3 - Depth, 4 - Normal, 5 - Cube
"uniform bool enableMap;",
"uniform bool enableCubeMap;",
"uniform bool mixEnvMap;",
"uniform samplerCube tCube;",
"uniform float mReflectivity;",
"uniform sampler2D tMap;",
"uniform vec4 mColor;",
"uniform float mOpacity;",
"uniform vec4 mAmbient;",
"uniform vec4 mSpecular;",
"uniform float mShininess;",
"uniform float m2Near;",
"uniform float mFarPlusNear;",
"uniform float mFarMinusNear;",
"uniform int pointLightNumber;",
"uniform int directionalLightNumber;",
maxDirLights ? "uniform mat4 viewMatrix;" : "",
maxDirLights ? "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];" : "",
"varying vec3 vNormal;",
"varying vec2 vUv;",
"varying vec3 vLightWeighting;",
maxPointLights ? "varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];" : "",
"varying vec3 vViewPosition;",
"varying vec3 vReflect[3];",
"uniform vec3 cameraPosition;",
"void main() {",
"vec4 mapColor = vec4( 1.0, 1.0, 1.0, 1.0 );",
"vec4 cubeColor = vec4( 1.0, 1.0, 1.0, 1.0 );",
// diffuse map
"if ( enableMap ) {",
"mapColor = texture2D( tMap, vUv );",
"}",
// cube map
"if ( enableCubeMap ) {",
// "cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );",
"cubeColor.r = textureCube( tCube, vec3( -vReflect[0].x, vReflect[0].yz ) ).r;",
"cubeColor.g = textureCube( tCube, vec3( -vReflect[1].x, vReflect[1].yz ) ).g;",
"cubeColor.b = textureCube( tCube, vec3( -vReflect[2].x, vReflect[2].yz ) ).b;",
"}",
// Cube
"if ( material == 5 ) { ",
"vec3 wPos = cameraPosition - vViewPosition;",
"gl_FragColor = textureCube( tCube, vec3( -wPos.x, wPos.yz ) );",
// Normals
"} else if ( material == 4 ) { ",
"gl_FragColor = vec4( 0.5*normalize( vNormal ) + vec3(0.5, 0.5, 0.5), mOpacity );",
// Depth
"} else if ( material == 3 ) { ",
// this breaks shader validation in Chrome 9.0.576.0 dev
// and also latest continuous build Chromium 9.0.583.0 (66089)
// (curiously it works in Chrome 9.0.576.0 canary build and Firefox 4b7)
//"float w = 1.0 - ( m2Near / ( mFarPlusNear - gl_FragCoord.z * mFarMinusNear ) );",
"float w = 0.5;",
"gl_FragColor = vec4( w, w, w, mOpacity );",
// Blinn-Phong
// based on o3d example
"} else if ( material == 2 ) { ",
"vec3 normal = normalize( vNormal );",
"vec3 viewPosition = normalize( vViewPosition );",
// point lights
maxPointLights ? "vec4 pointDiffuse = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
maxPointLights ? "vec4 pointSpecular = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
maxPointLights ? "for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {" : "",
maxPointLights ? "vec3 pointVector = normalize( vPointLightVector[ i ] );" : "",
maxPointLights ? "vec3 pointHalfVector = normalize( vPointLightVector[ i ] + vViewPosition );" : "",
maxPointLights ? "float pointDotNormalHalf = dot( normal, pointHalfVector );" : "",
maxPointLights ? "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );" : "",
// Ternary conditional is from the original o3d shader. Here it produces abrupt dark cutoff artefacts.
// Using just pow works ok in Chrome, but makes different artefact in Firefox 4.
// Zeroing on negative pointDotNormalHalf seems to work in both.
//"float specularCompPoint = dot( normal, pointVector ) < 0.0 || pointDotNormalHalf < 0.0 ? 0.0 : pow( pointDotNormalHalf, mShininess );",
//"float specularCompPoint = pow( pointDotNormalHalf, mShininess );",
//"float pointSpecularWeight = pointDotNormalHalf < 0.0 ? 0.0 : pow( pointDotNormalHalf, mShininess );",
// Ternary conditional inside for loop breaks Chrome shader linking.
// Must do it with if.
maxPointLights ? "float pointSpecularWeight = 0.0;" : "",
maxPointLights ? "if ( pointDotNormalHalf >= 0.0 )" : "",
maxPointLights ? "pointSpecularWeight = pow( pointDotNormalHalf, mShininess );" : "",
maxPointLights ? "pointDiffuse += mColor * pointDiffuseWeight;" : "",
maxPointLights ? "pointSpecular += mSpecular * pointSpecularWeight;" : "",
maxPointLights ? "}" : "",
// directional lights
maxDirLights ? "vec4 dirDiffuse = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
maxDirLights ? "vec4 dirSpecular = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
maxDirLights ? "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {" : "",
maxDirLights ? "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );" : "",
maxDirLights ? "vec3 dirVector = normalize( lDirection.xyz );" : "",
maxDirLights ? "vec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );" : "",
maxDirLights ? "float dirDotNormalHalf = dot( normal, dirHalfVector );" : "",
maxDirLights ? "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );" : "",
maxDirLights ? "float dirSpecularWeight = 0.0;" : "",
maxDirLights ? "if ( dirDotNormalHalf >= 0.0 )" : "",
maxDirLights ? "dirSpecularWeight = pow( dirDotNormalHalf, mShininess );" : "",
maxDirLights ? "dirDiffuse += mColor * dirDiffuseWeight;" : "",
maxDirLights ? "dirSpecular += mSpecular * dirSpecularWeight;" : "",
maxDirLights ? "}" : "",
// all lights contribution summation
"vec4 totalLight = mAmbient;",
maxDirLights ? "totalLight += dirDiffuse + dirSpecular;" : "",
maxPointLights ? "totalLight += pointDiffuse + pointSpecular;" : "",
// looks nicer with weighting
"if ( mixEnvMap ) {",
"gl_FragColor = vec4( mix( mapColor.rgb * totalLight.xyz * vLightWeighting, cubeColor.rgb, mReflectivity ), mapColor.a );",
"} else {",
"gl_FragColor = vec4( mapColor.rgb * cubeColor.rgb * totalLight.xyz * vLightWeighting, mapColor.a );",
"}",
// Lambert: diffuse lighting
"} else if ( material == 1 ) {",
"if ( mixEnvMap ) {",
"gl_FragColor = vec4( mix( mColor.rgb * mapColor.rgb * vLightWeighting, cubeColor.rgb, mReflectivity ), mColor.a * mapColor.a );",
"} else {",
"gl_FragColor = vec4( mColor.rgb * mapColor.rgb * cubeColor.rgb * vLightWeighting, mColor.a * mapColor.a );",
"}",
// Basic: unlit color / texture
"} else {",
"if ( mixEnvMap ) {",
"gl_FragColor = mix( mColor * mapColor, cubeColor, mReflectivity );",
"} else {",
"gl_FragColor = mColor * mapColor * cubeColor;",
"}",
"}",
"}" ];
return chunks.join("\n");
};
function generateVertexShader( maxDirLights, maxPointLights ) {
var chunks = [
maxDirLights ? "#define MAX_DIR_LIGHTS " + maxDirLights : "",
maxPointLights ? "#define MAX_POINT_LIGHTS " + maxPointLights : "",
"attribute vec3 position;",
"attribute vec3 normal;",
"attribute vec2 uv;",
"uniform vec3 cameraPosition;",
"uniform bool enableLighting;",
"uniform bool useRefract;",
"uniform int pointLightNumber;",
"uniform int directionalLightNumber;",
"uniform vec3 ambientLightColor;",
maxDirLights ? "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];" : "",
maxDirLights ? "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];" : "",
maxPointLights ? "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];" : "",
maxPointLights ? "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];" : "",
"uniform mat4 objMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat3 normalMatrix;",
"varying vec3 vNormal;",
"varying vec2 vUv;",
"varying vec3 vLightWeighting;",
maxPointLights ? "varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];" : "",
"varying vec3 vViewPosition;",
"varying vec3 vReflect[3];",
"uniform float mRefractionRatio;",
"void main(void) {",
// world space
"vec4 mPosition = objMatrix * vec4( position, 1.0 );",
"vViewPosition = cameraPosition - mPosition.xyz;",
// this doesn't work on Mac
//"vec3 nWorld = mat3(objMatrix) * normal;",
"vec3 nWorld = mat3( objMatrix[0].xyz, objMatrix[1].xyz, objMatrix[2].xyz ) * normal;",
// eye space
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
"vec3 transformedNormal = normalize( normalMatrix * normal );",
"if ( !enableLighting ) {",
"vLightWeighting = vec3( 1.0, 1.0, 1.0 );",
"} else {",
"vLightWeighting = ambientLightColor;",
// directional lights
maxDirLights ? "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {" : "",
maxDirLights ? "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );" : "",
maxDirLights ? "float directionalLightWeighting = max( dot( transformedNormal, normalize(lDirection.xyz ) ), 0.0 );" : "",
maxDirLights ? "vLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;" : "",
maxDirLights ? "}" : "",
// point lights
maxPointLights ? "for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {" : "",
maxPointLights ? "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );" : "",
maxPointLights ? "vPointLightVector[ i ] = normalize( lPosition.xyz - mvPosition.xyz );" : "",
maxPointLights ? "float pointLightWeighting = max( dot( transformedNormal, vPointLightVector[ i ] ), 0.0 );" : "",
maxPointLights ? "vLightWeighting += pointLightColor[ i ] * pointLightWeighting;" : "",
maxPointLights ? "}" : "",
"}",
"vNormal = transformedNormal;",
"vUv = uv;",
"if ( useRefract ) {",
"vReflect[0] = refract( normalize(mPosition.xyz - cameraPosition), normalize(nWorld.xyz), mRefractionRatio );",
"vReflect[1] = refract( normalize(mPosition.xyz - cameraPosition), normalize(nWorld.xyz), mRefractionRatio*0.9 );",
"vReflect[2] = refract( normalize(mPosition.xyz - cameraPosition), normalize(nWorld.xyz), mRefractionRatio*0.8 );",
"} else {",
"vReflect[0] = reflect( normalize(mPosition.xyz - cameraPosition), normalize(nWorld.xyz) );",
"vReflect[1] = reflect( normalize(mPosition.xyz - cameraPosition), normalize(nWorld.xyz) );",
"vReflect[2] = reflect( normalize(mPosition.xyz - cameraPosition), normalize(nWorld.xyz) );",
"}",
"gl_Position = projectionMatrix * mvPosition;",
"}" ];
return chunks.join("\n");
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment