Last active
December 14, 2015 21:55
-
-
Save andreasplesch/2e4a5ebd583ac7d33ce0 to your computer and use it in GitHub Desktop.
displacement texture along normal for commonsurfaceshader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name normalDisplacement | |
// @namespace aplesch | |
// @description normal displacement for CommonSurfaceShader | |
// @version 0.31 | |
// @grant none | |
// ==/UserScript== | |
/* | |
* X3DOM JavaScript Library | |
* http://www.x3dom.org | |
* | |
* (C)2009 Fraunhofer IGD, Darmstadt, Germany | |
* Dual licensed under the MIT and GPL | |
* | |
* Based on code originally provided by | |
* Philip Taylor: http://philip.html5.org | |
*/ | |
/** | |
* Generate the final Shader program | |
*/ | |
/* | |
x3dom.shader.DynamicShader = function(gl, properties) | |
{ | |
this.program = gl.createProgram(); | |
var vertexShader = this.generateVertexShader(gl, properties); | |
var fragmentShader = this.generateFragmentShader(gl, properties); | |
gl.attachShader(this.program, vertexShader); | |
gl.attachShader(this.program, fragmentShader); | |
// optional, but position should be at location 0 for performance reasons | |
gl.bindAttribLocation(this.program, 0, "position"); | |
gl.linkProgram(this.program); | |
return this.program; | |
}; | |
*/ | |
/** | |
* Generate the vertex shader | |
*/ | |
x3dom.shader.DynamicShader.prototype.generateVertexShader = function(gl, properties) | |
{ | |
var shader = ""; | |
/******************************************************************************* | |
* Generate dynamic attributes & uniforms & varyings | |
********************************************************************************/ | |
//Default Matrices | |
shader += "uniform mat4 modelViewMatrix;\n"; | |
shader += "uniform mat4 modelViewProjectionMatrix;\n"; | |
//Positions | |
if(properties.POSCOMPONENTS == 3) { | |
shader += "attribute vec3 position;\n"; | |
} else if(properties.POSCOMPONENTS == 4) { | |
shader += "attribute vec4 position;\n"; | |
} | |
//IG stuff | |
if(properties.IMAGEGEOMETRY) { | |
shader += "uniform vec3 IG_bboxMin;\n"; | |
shader += "uniform vec3 IG_bboxMax;\n"; | |
shader += "uniform float IG_coordTextureWidth;\n"; | |
shader += "uniform float IG_coordTextureHeight;\n"; | |
shader += "uniform vec2 IG_implicitMeshSize;\n"; | |
for( var i = 0; i < properties.IG_PRECISION; i++ ) { | |
shader += "uniform sampler2D IG_coords" + i + "\n;"; | |
} | |
if(properties.IG_INDEXED) { | |
shader += "uniform sampler2D IG_index;\n"; | |
shader += "uniform float IG_indexTextureWidth;\n"; | |
shader += "uniform float IG_indexTextureHeight;\n"; | |
} | |
} | |
//PG stuff | |
if (properties.POPGEOMETRY) { | |
shader += "uniform float PG_precisionLevel;\n"; | |
shader += "uniform float PG_powPrecision;\n"; | |
shader += "uniform vec3 PG_maxBBSize;\n"; | |
shader += "uniform vec3 PG_bbMin;\n"; | |
shader += "uniform vec3 PG_bbMaxModF;\n"; | |
shader += "uniform vec3 PG_bboxShiftVec;\n"; | |
shader += "uniform float PG_numAnchorVertices;\n"; | |
shader += "attribute float PG_vertexID;\n"; | |
} | |
//Normals | |
if(properties.LIGHTS) { | |
if(properties.NORMALMAP && properties.NORMALSPACE == "OBJECT") { | |
//do nothing | |
} else { | |
shader += "varying vec3 fragNormal;\n"; | |
shader += "uniform mat4 normalMatrix;\n"; | |
if(properties.IMAGEGEOMETRY) { | |
shader += "uniform sampler2D IG_normals;\n"; | |
} else { | |
if (properties.NORCOMPONENTS == 2) { | |
if (properties.POSCOMPONENTS != 4) { | |
shader += "attribute vec2 normal;\n"; | |
} | |
} else if (properties.NORCOMPONENTS == 3) { | |
shader += "attribute vec3 normal;\n"; | |
} | |
} | |
} | |
} | |
//Init Colors. In the vertex shader we do not compute any color so | |
//is is safe to ignore gamma here. | |
if(properties.VERTEXCOLOR) { | |
if(properties.IMAGEGEOMETRY) { | |
shader += "uniform sampler2D IG_colors;\n"; | |
if(properties.COLCOMPONENTS == 3) { | |
shader += "varying vec3 fragColor;\n"; | |
} else if(properties.COLCOMPONENTS == 4) { | |
shader += "varying vec4 fragColor;\n"; | |
} | |
} else { | |
if(properties.COLCOMPONENTS == 3) { | |
shader += "attribute vec3 color;\n"; | |
shader += "varying vec3 fragColor;\n"; | |
} else if(properties.COLCOMPONENTS == 4) { | |
shader += "attribute vec4 color;\n"; | |
shader += "varying vec4 fragColor;\n"; | |
} | |
} | |
} | |
//Textures | |
if(properties.TEXTURED || properties.CSSHADER) { | |
shader += "varying vec2 fragTexcoord;\n"; | |
if(!properties.SPHEREMAPPING) { | |
if(properties.IMAGEGEOMETRY) { | |
shader += "uniform sampler2D IG_texCoords;\n"; | |
} else if (!properties.IS_PARTICLE) { | |
shader += "attribute vec2 texcoord;\n"; | |
} | |
} | |
if(properties.TEXTRAFO){ | |
shader += "uniform mat4 texTrafoMatrix;\n"; | |
} | |
if(properties.NORMALMAP && properties.NORMALSPACE == "TANGENT" && !x3dom.caps.STD_DERIVATIVES) { | |
x3dom.debug.logWarning("Your System doesn't support the 'OES_STANDARD_DERIVATIVES' Extension. " + | |
"You must set tangents and binormals manually via the FloatVertexAttribute-Node " + | |
"to use normal maps"); | |
shader += "attribute vec3 tangent;\n"; | |
shader += "attribute vec3 binormal;\n"; | |
shader += "varying vec3 fragTangent;\n"; | |
shader += "varying vec3 fragBinormal;\n"; | |
} | |
if(properties.CUBEMAP) { | |
shader += "varying vec3 fragViewDir;\n"; | |
shader += "uniform mat4 viewMatrix;\n"; | |
} | |
if (properties.DISPLACEMENTMAP) { | |
shader += "uniform sampler2D displacementMap;\n"; | |
shader += "uniform float displacementFactor;\n"; | |
shader += "uniform float displacementWidth;\n"; | |
shader += "uniform float displacementHeight;\n"; | |
shader += "uniform float displacementAxis;\n"; | |
} | |
if (properties.DIFFPLACEMENTMAP) { | |
shader += "uniform sampler2D diffuseDisplacementMap;\n"; | |
shader += "uniform float displacementFactor;\n"; | |
shader += "uniform float displacementWidth;\n"; | |
shader += "uniform float displacementHeight;\n"; | |
shader += "uniform float displacementAxis;\n"; | |
} | |
if (properties.MULTIDIFFALPMAP || properties.MULTIVISMAP) { | |
shader += "attribute float id;\n"; | |
shader += "varying float fragID;\n"; | |
} | |
} | |
if (properties.IS_PARTICLE) { | |
shader += "attribute vec3 particleSize;\n"; | |
} | |
//Lights & Fog | |
if(properties.LIGHTS || properties.FOG || properties.CLIPPLANES){ | |
shader += "uniform vec3 eyePosition;\n"; | |
shader += "varying vec4 fragPosition;\n"; | |
if(properties.FOG) { | |
shader += "varying vec3 fragEyePosition;\n"; | |
} | |
} | |
//Bounding Boxes | |
if(properties.REQUIREBBOX) { | |
shader += "uniform vec3 bgCenter;\n"; | |
shader += "uniform vec3 bgSize;\n"; | |
shader += "uniform float bgPrecisionMax;\n"; | |
} | |
if(properties.REQUIREBBOXNOR) { | |
shader += "uniform float bgPrecisionNorMax;\n"; | |
} | |
if(properties.REQUIREBBOXCOL) { | |
shader += "uniform float bgPrecisionColMax;\n"; | |
} | |
if(properties.REQUIREBBOXTEX) { | |
shader += "uniform float bgPrecisionTexMax;\n"; | |
} | |
/******************************************************************************* | |
* Generate main function | |
********************************************************************************/ | |
shader += "void main(void) {\n"; | |
/******************************************************************************* | |
* Start of special Geometry switch | |
********************************************************************************/ | |
if(properties.IMAGEGEOMETRY) { | |
//Indices | |
if(properties.IG_INDEXED) { | |
shader += "vec2 halfPixel = vec2(0.5/IG_indexTextureWidth,0.5/IG_indexTextureHeight);\n"; | |
shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_indexTextureWidth), position.y*(IG_implicitMeshSize.y/IG_indexTextureHeight)) + halfPixel;\n"; | |
shader += "vec2 IG_indices = texture2D( IG_index, IG_texCoord ).rg;\n"; | |
shader += "halfPixel = vec2(0.5/IG_coordTextureWidth,0.5/IG_coordTextureHeight);\n"; | |
shader += "IG_texCoord = (IG_indices * 0.996108948) + halfPixel;\n"; | |
} else { | |
shader += "vec2 halfPixel = vec2(0.5/IG_coordTextureWidth, 0.5/IG_coordTextureHeight);\n"; | |
shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_coordTextureWidth), position.y*(IG_implicitMeshSize.y/IG_coordTextureHeight)) + halfPixel;\n"; | |
} | |
//Positions | |
shader += "vec3 temp = vec3(0.0, 0.0, 0.0);\n"; | |
shader += "vec3 vertPosition = vec3(0.0, 0.0, 0.0);\n"; | |
for(var i=0; i<properties.IG_PRECISION; i++) { | |
shader += "temp = 255.0 * texture2D( IG_coords" + i + ", IG_texCoord ).rgb;\n"; | |
shader += "vertPosition *= 256.0;\n"; | |
shader += "vertPosition += temp;\n"; | |
} | |
shader += "vertPosition /= (pow(2.0, 8.0 * " + properties.IG_PRECISION + ".0) - 1.0);\n"; | |
shader += "vertPosition = vertPosition * (IG_bboxMax - IG_bboxMin) + IG_bboxMin;\n"; | |
//Normals | |
if(properties.LIGHTS) { | |
shader += "vec3 vertNormal = texture2D( IG_normals, IG_texCoord ).rgb;\n"; | |
shader += "vertNormal = vertNormal * 2.0 - 1.0;\n"; | |
} | |
//Colors | |
if(properties.VERTEXCOLOR) { | |
if(properties.COLCOMPONENTS == 3) { | |
shader += "fragColor = texture2D( IG_colors, IG_texCoord ).rgb;\n"; | |
} else if(properties.COLCOMPONENTS == 4) { | |
shader += "fragColor = texture2D( IG_colors, IG_texCoord ).rgba;\n"; | |
} | |
} | |
//TexCoords | |
if(properties.TEXTURED || properties.CSSHADER) { | |
shader += "vec4 IG_doubleTexCoords = texture2D( IG_texCoords, IG_texCoord );\n"; | |
shader += "vec2 vertTexCoord;"; | |
shader += "vertTexCoord.r = (IG_doubleTexCoords.r * 0.996108948) + (IG_doubleTexCoords.b * 0.003891051);\n"; | |
shader += "vertTexCoord.g = (IG_doubleTexCoords.g * 0.996108948) + (IG_doubleTexCoords.a * 0.003891051);\n"; | |
} | |
} else { | |
//Positions | |
shader += "vec3 vertPosition = position.xyz;\n"; | |
if (properties.POPGEOMETRY) { | |
//compute offset using bounding box and test if vertPosition <= PG_bbMaxModF | |
shader += "vec3 offsetVec = step(vertPosition / bgPrecisionMax, PG_bbMaxModF) * PG_bboxShiftVec;\n"; | |
//coordinate truncation, computation of current maximum possible value | |
//PG_vertexID currently mimics use of gl_VertexID | |
shader += "if ((PG_precisionLevel <= 2.0) || PG_vertexID >= PG_numAnchorVertices) {\n"; | |
shader += " vertPosition = floor(vertPosition / PG_powPrecision) * PG_powPrecision;\n"; | |
shader += " vertPosition /= (65536.0 - PG_powPrecision);\n"; | |
shader += "}\n"; | |
shader += "else {\n"; | |
shader += " vertPosition /= bgPrecisionMax;\n"; | |
shader += "}\n"; | |
//translate coordinates, where PG_bbMin := floor(bbMin / size) | |
shader += "vertPosition = (vertPosition + offsetVec + PG_bbMin) * PG_maxBBSize;\n"; | |
} | |
else if(properties.REQUIREBBOX) { | |
shader += "vertPosition = bgCenter + bgSize * vertPosition / bgPrecisionMax;\n"; | |
} | |
//Normals | |
if(properties.LIGHTS) { | |
if(properties.NORCOMPONENTS == 2) { | |
if (properties.POSCOMPONENTS == 4) { | |
// (theta, phi) encoded in low/high byte of position.w | |
shader += "vec3 vertNormal = vec3(position.w / 256.0); \n"; | |
shader += "vertNormal.x = floor(vertNormal.x) / 255.0; \n"; | |
shader += "vertNormal.y = fract(vertNormal.y) * 1.00392156862745; \n"; //256.0 / 255.0 | |
} | |
else if (properties.REQUIREBBOXNOR) { | |
shader += "vec3 vertNormal = vec3(normal.xy, 0.0) / bgPrecisionNorMax;\n"; | |
} | |
shader += "vec2 thetaPhi = 3.14159265358979 * vec2(vertNormal.x, vertNormal.y*2.0-1.0); \n"; | |
shader += "vec4 sinCosThetaPhi = sin( vec4(thetaPhi, thetaPhi + 1.5707963267949) ); \n"; | |
shader += "vertNormal.x = sinCosThetaPhi.x * sinCosThetaPhi.w; \n"; | |
shader += "vertNormal.y = sinCosThetaPhi.x * sinCosThetaPhi.y; \n"; | |
shader += "vertNormal.z = sinCosThetaPhi.z; \n"; | |
} else { | |
if (properties.NORMALMAP && properties.NORMALSPACE == "OBJECT") { | |
//Nothing to do | |
} else { | |
shader += "vec3 vertNormal = normal;\n"; | |
if (properties.REQUIREBBOXNOR) { | |
shader += "vertNormal = vertNormal / bgPrecisionNorMax;\n"; | |
} | |
if (properties.POPGEOMETRY) { | |
shader += "vertNormal = 2.0*vertNormal - 1.0;\n"; | |
} | |
} | |
} | |
} | |
//Colors | |
if(properties.VERTEXCOLOR){ | |
shader += "fragColor = color;\n"; | |
if(properties.REQUIREBBOXCOL) { | |
shader += "fragColor = fragColor / bgPrecisionColMax;\n"; | |
} | |
} | |
//TexCoords | |
if( (properties.TEXTURED || properties.CSSHADER) && !properties.SPHEREMAPPING) { | |
if (properties.IS_PARTICLE) { | |
shader += "vec2 vertTexCoord = vec2(0.0);\n"; | |
} | |
else { | |
shader += "vec2 vertTexCoord = texcoord;\n"; | |
if (properties.REQUIREBBOXTEX) { | |
shader += "vertTexCoord = vertTexCoord / bgPrecisionTexMax;\n"; | |
} | |
} | |
} | |
} | |
/******************************************************************************* | |
* End of special Geometry switch | |
********************************************************************************/ | |
//Normals | |
if(properties.LIGHTS) { | |
if ((properties.DISPLACEMENTMAP || properties.DIFFPLACEMENTMAP) && !properties.NORMALMAP) { | |
//Map-Tile Size | |
shader += "float dx = 1.0 / displacementWidth;\n"; | |
shader += "float dy = 1.0 / displacementHeight;\n"; | |
//Get the 4 Vertex Neighbours | |
if (properties.DISPLACEMENTMAP) | |
{ | |
shader += "float s1 = texture2D(displacementMap, vec2(vertTexCoord.x - dx, 1.0 - vertTexCoord.y)).r;\n"; //left | |
shader += "float s2 = texture2D(displacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y - dy)).r;\n"; //bottom | |
shader += "float s3 = texture2D(displacementMap, vec2(vertTexCoord.x + dx, 1.0 - vertTexCoord.y)).r;\n"; //right | |
shader += "float s4 = texture2D(displacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y + dy)).r;\n"; //top | |
} | |
else if (properties.DIFFPLACEMENTMAP) | |
{ | |
shader += "float s1 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x - dx, 1.0 - vertTexCoord.y)).a;\n"; //left | |
shader += "float s2 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y - dy)).a;\n"; //bottom | |
shader += "float s3 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x + dx, 1.0 - vertTexCoord.y)).a;\n"; //right | |
shader += "float s4 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y + dy)).a;\n"; //top | |
} | |
//Coeffiecent for smooth/sharp Normals | |
shader += "float coef = displacementFactor;\n"; | |
//Calculate the Normal | |
shader += "vec3 calcNormal;\n"; | |
shader += "if (displacementAxis == 0.0) {\n"; //X | |
shader += "calcNormal = vec3((s1 - s3) * coef, -5.0, (s2 - s4) * coef);\n"; | |
shader += "} else if(displacementAxis == 1.0) {\n"; //Y | |
shader += "calcNormal = vec3((s1 - s3) * coef, -5.0, (s2 - s4) * coef);\n"; | |
shader += "} else {\n"; //Z | |
shader += "calcNormal = vec3((s1 - s3) * coef, -(s2 - s4) * coef, 5.0);\n"; | |
shader += "}\n"; | |
//normalized Normal | |
shader += "calcNormal = normalize(calcNormal);\n"; | |
shader += "fragNormal = (normalMatrix * vec4(calcNormal, 0.0)).xyz;\n"; | |
} | |
else if (properties.NORMALMAP && properties.NORMALSPACE == "OBJECT") { | |
//Nothing to do | |
} | |
else | |
{ | |
shader += "fragNormal = (normalMatrix * vec4(vertNormal, 0.0)).xyz;\n"; | |
} | |
} | |
//Textures | |
if(properties.TEXTURED || properties.CSSHADER){ | |
if(properties.CUBEMAP) { | |
shader += "fragViewDir = (viewMatrix[3].xyz);\n"; | |
} else if (properties.SPHEREMAPPING) { | |
shader += " fragTexcoord = 0.5 + fragNormal.xy / 2.0;\n"; | |
} else if(properties.TEXTRAFO) { | |
shader += " fragTexcoord = (texTrafoMatrix * vec4(vertTexCoord, 1.0, 1.0)).xy;\n"; | |
} else { | |
shader += " fragTexcoord = vertTexCoord;\n"; | |
// LOD LUT HACK ### | |
if (properties.POPGEOMETRY && x3dom.debug.usePrecisionLevelAsTexCoord === true) | |
// remap texCoords to texel middle with w = 16 and tc' := 1 / (2 * w) + tc * (w - 1) / w | |
shader += "fragTexcoord = vec2(0.03125 + 0.9375 * (PG_precisionLevel / 16.0), 1.0);"; | |
// LOD LUT HACK ### | |
} | |
if(properties.NORMALMAP && properties.NORMALSPACE == "TANGENT" && !x3dom.caps.STD_DERIVATIVES) { | |
shader += "fragTangent = (normalMatrix * vec4(tangent, 0.0)).xyz;\n"; | |
shader += "fragBinormal = (normalMatrix * vec4(binormal, 0.0)).xyz;\n"; | |
} | |
} | |
//Lights & Fog | |
if(properties.LIGHTS || properties.FOG || properties.CLIPPLANES){ | |
shader += "fragPosition = (modelViewMatrix * vec4(vertPosition, 1.0));\n"; | |
if (properties.FOG) { | |
shader += "fragEyePosition = eyePosition - fragPosition.xyz;\n"; | |
} | |
} | |
//Vertex ID's | |
if (properties.MULTIDIFFALPMAP) { | |
shader += "fragID = id;\n"; | |
} | |
//Displacement | |
if (properties.DISPLACEMENTMAP) { | |
shader += "vertPosition += normalize(vertNormal) * texture2D(displacementMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).r * displacementFactor;\n"; | |
} | |
else if (properties.DIFFPLACEMENTMAP) | |
{ | |
shader += "vertPosition += normalize(vertNormal) * texture2D(diffuseDisplacementMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).a * displacementFactor;\n"; | |
} | |
//Positions | |
shader += "gl_Position = modelViewProjectionMatrix * vec4(vertPosition, 1.0);\n"; | |
//Set point size | |
if (properties.IS_PARTICLE) { | |
shader += "float spriteDist = (gl_Position.w > 0.000001) ? gl_Position.w : 0.000001;\n"; | |
shader += "float pointSize = floor(length(particleSize) * 256.0 / spriteDist + 0.5);\n"; | |
shader += "gl_PointSize = clamp(pointSize, 2.0, 256.0);\n"; | |
} | |
else { | |
shader += "gl_PointSize = 2.0;\n"; | |
} | |
//END OF SHADER | |
shader += "}\n"; | |
var vertexShader = gl.createShader(gl.VERTEX_SHADER); | |
gl.shaderSource(vertexShader, shader); | |
gl.compileShader(vertexShader); | |
if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){ | |
x3dom.debug.logInfo("VERTEX:\n" + shader); | |
x3dom.debug.logError("VertexShader " + gl.getShaderInfoLog(vertexShader)); | |
} | |
return vertexShader; | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment