Browse Source

Adding parallax occlusion mapping

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
f251240a65

+ 83 - 0
shaders/MsCommonFrag.glsl

@@ -209,6 +209,89 @@ float readRFromTexture(in sampler2D tex, in highp vec2 texCoords)
 }
 #endif
 
+#define computeTextureCoordParalax_DEFINED
+vec2 computeTextureCoordParalax(in sampler2D heightMap,
+	in vec2 uv,
+	in vec3 posView,
+	in vec3 normal,
+	in vec4 tangent,
+	in float heightMapScale)
+{
+#if PASS == COLOR && LOD == 0
+	const uint MAX_SAMPLES = 25;
+	const uint MIN_SAMPLES = 3;
+	const float MAX_EFFECTIVE_DISTANCE = 10.0;
+
+	// Get that because we are sampling inside a loop
+	vec2 dPdx = dFdx(uv);
+	vec2 dPdy = dFdy(uv);
+
+	vec3 n = normal; // Assume that getNormal() is called
+	vec3 t = normalize(tangent.xyz);
+	vec3 b = cross(n, t) * tangent.w;
+	mat3 invTbn = transpose(mat3(t, b, n));
+
+	vec3 eyeTangentSpace = invTbn * posView;
+	vec3 normTangentSpace = invTbn * n;
+
+	float parallaxLimit = -length(eyeTangentSpace.xy) / eyeTangentSpace.z;
+	parallaxLimit *= heightMapScale;
+
+	vec2 offsetDir = normalize(eyeTangentSpace.xy);
+	vec2 maxOffset = offsetDir * parallaxLimit;
+
+	vec3 E = normalize(eyeTangentSpace);
+
+	float sampleCountf =
+		mix(MAX_SAMPLES, MIN_SAMPLES, 
+		min(dot(E, normTangentSpace), posView.z / -MAX_EFFECTIVE_DISTANCE));
+
+	float stepSize = 1.0 / sampleCountf;
+
+	float crntRayHeight = 1.0;
+	vec2 crntOffset = vec2(0.0);
+	vec2 lastOffset = vec2(0.0);
+
+	float lastSampledHeight = 1.0;
+	float crntSampledHeight = 1.0;
+
+	uint crntSample = 0;
+
+	uint sampleCount = uint(sampleCountf);
+	while(crntSample < sampleCount)
+	{
+		crntSampledHeight =
+			textureGrad(heightMap, uv + crntOffset, dPdx, dPdy).r;
+
+		if(crntSampledHeight > crntRayHeight)
+		{
+			float delta1 = crntSampledHeight - crntRayHeight;
+			float delta2 = (crntRayHeight + stepSize) - lastSampledHeight;
+			float ratio = delta1 / (delta1 + delta2);
+
+			crntOffset = mix(crntOffset, lastOffset, ratio);
+
+			crntSample = sampleCount + 1;
+		}
+		else
+		{
+			crntSample++;
+
+			crntRayHeight -= stepSize;
+
+			lastOffset = crntOffset;
+			crntOffset += stepSize * maxOffset;
+
+			lastSampledHeight = crntSampledHeight;
+		}
+	}
+
+	return uv + crntOffset;
+#else
+	return uv;
+#endif
+}
+
 // Write the data to FAIs
 #if PASS == COLOR
 #define writeRts_DEFINED

+ 1 - 0
src/resource/MaterialLoader.cpp

@@ -536,6 +536,7 @@ Error MaterialLoader::parseInputsTag(const XmlElement& programEl)
 
 		// Check if instanced
 		if(in.m_builtin == BuiltinMaterialVariableId::MVP_MATRIX
+			|| in.m_builtin == BuiltinMaterialVariableId::MV_MATRIX
 			|| in.m_builtin == BuiltinMaterialVariableId::NORMAL_MATRIX
 			|| in.m_builtin == BuiltinMaterialVariableId::BILLBOARD_MVP_MATRIX)
 		{

+ 62 - 1
tools/scene/ExporterMaterial.cpp

@@ -151,7 +151,7 @@ void Exporter::exportMaterial(const aiMaterial& mtl) const
 	std::string materialStr;
 	materialStr = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
 	materialStr += "\n<material>\n\t<programs>\n";
-	if(dispTex.empty())
+	if(/*dispTex.empty()*/ 1)
 	{
 		materialStr += simpleVertTemplate;
 	}
@@ -432,6 +432,67 @@ void Exporter::exportMaterial(const aiMaterial& mtl) const
 			replaceAllString(materialStr, "%metallicArg%", "metallic");
 	}
 
+	// Height to parallax
+	if(!dispTex.empty())
+	{
+		materialStr = replaceAllString(materialStr,
+			"%heightVertInput%",
+			"<input><type>mat4</type><name>anki_mv"
+			"</name><inShadow>0</inShadow></input>");
+
+		materialStr = replaceAllString(materialStr,
+			"%heightVertFunc%",
+			R"(<operation>
+					<id>2</id>
+					<returnType>void</returnType>
+					<function>writeVertPosViewSpace</function>
+					<arguments><argument>anki_mv</argument></arguments>
+				</operation>)");
+
+		materialStr = replaceAllString(materialStr,
+			"%heightInput%",
+			"<input><type>sampler2D</type><name>heightMap</name>"
+			"<value>"
+				+ m_texrpath
+				+ dispTex
+				+ "</value></input>\n"
+				  "\t\t\t\t<input><type>float</type><name>heightMapScale</name>"
+				  "<value>0.05</value><const>1</const></input>");
+
+		// At this point everyone will have to use out4 as tex coords
+		materialStr = replaceAllString(materialStr,
+			"<argument>out2</argument>",
+			"<argument>out4</argument>");
+
+		materialStr = replaceAllString(materialStr,
+			"%heightFunc%",
+			R"(<operation>
+					<id>3</id>
+					<returnType>vec3</returnType>
+					<function>getPositionViewSpace</function>
+				</operation>
+				<operation>
+					<id>4</id>
+					<returnType>vec2</returnType>
+					<function>computeTextureCoordParalax</function>
+					<arguments>
+						<argument>heightMap</argument>
+						<argument>out2</argument>
+						<argument>out3</argument>
+						<argument>out0</argument>
+						<argument>out1</argument>
+						<argument>heightMapScale</argument>
+					</arguments>
+				</operation>)");
+	}
+	else
+	{
+		materialStr = replaceAllString(materialStr, "%heightVertInput%", " ");
+		materialStr = replaceAllString(materialStr, "%heightVertFunc%", " ");
+		materialStr = replaceAllString(materialStr, "%heightInput%", " ");
+		materialStr = replaceAllString(materialStr, "%heightFunc%", " ");
+	}
+
 	// Continue
 	materialStr =
 		replaceAllString(materialStr, "%diffuseMap%", m_texrpath + diffTex);

+ 2 - 0
tools/scene/templates/diffNormSpecFrag.h

@@ -13,6 +13,7 @@ R"(		<program>
 				%subsurfaceInput%
 				%emissionInput%
 				%metallicInput%
+				%heightInput%
 			</inputs>
 
 			<operations>
@@ -31,6 +32,7 @@ R"(		<program>
 					<returnType>vec2</returnType>
 					<function>getTextureCoord</function>
 				</operation>
+				%heightFunc%
 				%diffuseColorFunc%
 				%normalFunc%
 				%specularColorFunc%

+ 2 - 0
tools/scene/templates/simpleVert.h

@@ -7,6 +7,7 @@ R"(		<program>
 			<inputs>
 				<input><type>mat4</type><name>anki_mvp</name></input>
 				<input><type>mat3</type><name>anki_n</name><inShadow>0</inShadow></input>
+				%heightVertInput%
 			</inputs>
 
 			<operations>
@@ -22,5 +23,6 @@ R"(		<program>
 					<function>writeNormalAndTangent</function>
 					<arguments><argument>anki_n</argument></arguments>
 				</operation>
+				%heightVertFunc%
 			</operations>
 		</program>)"