ソースを参照

parallax object mapping

ncannasse 7 年 前
コミット
72a0eca5fe
2 ファイル変更75 行追加0 行削除
  1. 24 0
      h3d/mat/PbrMaterial.hx
  2. 51 0
      h3d/shader/Parallax.hx

+ 24 - 0
h3d/mat/PbrMaterial.hx

@@ -21,6 +21,7 @@ typedef PbrProps = {
 	var culling : Bool;
 	@:optional var alphaKill : Bool;
 	@:optional var emissive : Float;
+	@:optional var parallax : Float;
 }
 
 class PbrMaterial extends Material {
@@ -141,6 +142,19 @@ class PbrMaterial extends Material {
 		}
 		if( tex != null ) tex.emissive = emit;
 		if( def != null ) def.emissive = emit;
+
+		// parallax
+		var ps = mainPass.getShader(h3d.shader.Parallax);
+		if( props.parallax > 0 ) {
+			if( ps == null ) {
+				ps = new h3d.shader.Parallax();
+				mainPass.addShader(ps);
+			}
+			ps.amount = props.parallax;
+			ps.heightMap = specularTexture;
+			ps.heightMapChannel = A;
+		} else if( ps != null )
+			mainPass.removeShader(ps);
 	}
 
 	override function get_specularTexture() {
@@ -173,6 +187,15 @@ class PbrMaterial extends Material {
 				mainPass.addShader(def);
 			}
 		}
+
+
+		// parallax
+		var ps = mainPass.getShader(h3d.shader.Parallax);
+		if( ps != null ) {
+			ps.heightMap = t;
+			ps.heightMapChannel = A;
+		}
+
 		return t;
 	}
 
@@ -206,6 +229,7 @@ class PbrMaterial extends Material {
 					</select>
 				</dd>
 				<dt>Emissive</dt><dd><input type="range" min="0" max="10" field="emissive"/></dd>
+				<dt>Parallax</dt><dd><input type="range" min="0" max="1" field="parallax"/></dd>
 				<dt>Shadows</dt><dd><input type="checkbox" field="shadows"/></dd>
 				<dt>Culled</dt><dd><input type="checkbox" field="culling"/></dd>
 				<dt>AlphaKill</dt><dd><input type="checkbox" field="alphaKill"/></dd>

+ 51 - 0
h3d/shader/Parallax.hx

@@ -0,0 +1,51 @@
+package h3d.shader;
+
+class Parallax extends hxsl.Shader {
+
+	static var SRC = {
+
+		@param var amount : Float;
+		@param var heightMap : Channel;
+		@:import BaseMesh;
+
+		@const var minLayers : Int = 6;
+		@const var maxLayers : Int = 24;
+
+		var vertexTransformedNormal : Vec3;
+		var transformedTangent : Vec4;
+		var calculatedUV : Vec2;
+
+		function vertex() {
+			vertexTransformedNormal = transformedNormal;
+		}
+
+		function fragment() {
+			var viewWS = (camera.position - transformedPosition).normalize();
+			var n = vertexTransformedNormal;
+			var tanX = transformedTangent.xyz.normalize();
+			var tanY = n.cross(tanX);
+			var viewNS = (vec3(viewWS.dot(tanX), viewWS.dot(tanY), viewWS.dot(n)) * global.modelViewInverse.mat3()).normalize();
+			if( maxLayers == 0 )
+				calculatedUV += viewNS.xy * heightMap.get(calculatedUV) * amount;
+			else {
+				var numLayers = mix(float(maxLayers), float(minLayers), abs(viewNS.z));
+				var layerDepth = 1 / numLayers;
+				var curLayerDepth = 0.;
+				var delta = (viewNS.xy / viewNS.z) * amount / numLayers;
+				var curUV = calculatedUV;
+				var curDepth = heightMap.get(curUV);
+			    while( curLayerDepth < curDepth ) {
+			        curUV += delta;
+			        curDepth = heightMap.get(curUV);
+			        curLayerDepth += layerDepth;
+				}
+				var prevUV = curUV - delta;
+				var after = curDepth - curLayerDepth;
+				var before = heightMap.get(prevUV) - curLayerDepth + layerDepth;
+				calculatedUV = mix(curUV, prevUV, after / (after - before));
+			}
+		}
+	}
+
+
+}