Browse Source

Temporal antialiasing using velocity on Skin meshes.

clementlandrin 5 months ago
parent
commit
5d01387907
6 changed files with 116 additions and 46 deletions
  1. 40 1
      h3d/scene/Skin.hx
  2. 9 6
      h3d/scene/pbr/Renderer.hx
  3. 16 4
      h3d/shader/Skin.hx
  4. 2 1
      h3d/shader/SkinBase.hx
  5. 29 19
      h3d/shader/SkinTangent.hx
  6. 20 15
      h3d/shader/pbr/Slides.hx

+ 40 - 1
h3d/scene/Skin.hx

@@ -269,7 +269,10 @@ class Skin extends MultiMaterial {
 	var jointsData : Array<JointData>; // Runtime data
 	var jointsData : Array<JointData>; // Runtime data
 
 
 	var currentPalette : Array<h3d.Matrix>;
 	var currentPalette : Array<h3d.Matrix>;
+	var prevPalette : Array<h3d.Matrix>;
 	var splitPalette : Array<Array<h3d.Matrix>>;
 	var splitPalette : Array<Array<h3d.Matrix>>;
+	var prevSplitPalette : Array<Array<h3d.Matrix>>;
+	var prevJointsFrame : Int = -1;
 	var forceJointsUpdateOnFrame : Int = -1;
 	var forceJointsUpdateOnFrame : Int = -1;
 	var jointsUpdated : Bool;
 	var jointsUpdated : Bool;
 	var paletteChanged : Bool;
 	var paletteChanged : Bool;
@@ -430,6 +433,8 @@ class Skin extends MultiMaterial {
 
 
 		jointsData = [];
 		jointsData = [];
 		currentPalette = [];
 		currentPalette = [];
+		prevPalette = null;
+		prevSplitPalette = null;
 		paletteChanged = true;
 		paletteChanged = true;
 		makeJointsData();
 		makeJointsData();
 		for( i in 0...skinData.boundJoints.length )
 		for( i in 0...skinData.boundJoints.length )
@@ -457,7 +462,19 @@ class Skin extends MultiMaterial {
 
 
 	@:noDebug
 	@:noDebug
 	function syncJoints() {
 	function syncJoints() {
-		if( !jointsUpdated && forceJointsUpdateOnFrame != hxd.Timer.frameCount ) return;
+		if( !jointsUpdated && forceJointsUpdateOnFrame != hxd.Timer.frameCount )
+			return;
+
+		if ( computeVelocity() ) {
+			syncPrevJoints();
+			skinShader.calcPrevPos = true;
+		} else {
+			prevSplitPalette = null;
+			prevPalette = null;
+			skinShader.calcPrevPos = false;
+		}
+
+		skinShader.calcPrevPos = computeVelocity();
 
 
 		for( j in skinData.allJoints )
 		for( j in skinData.allJoints )
 			jointsData[j.index].sync(this, j);
 			jointsData[j.index].sync(this, j);
@@ -467,6 +484,26 @@ class Skin extends MultiMaterial {
 		prevEnableRetargeting = enableRetargeting;
 		prevEnableRetargeting = enableRetargeting;
 	}
 	}
 
 
+	function syncPrevJoints() {
+		if ( prevJointsFrame == hxd.Timer.frameCount )
+			return;
+		prevJointsFrame = hxd.Timer.frameCount;
+		
+		if ( prevPalette == null ) {
+			prevPalette = [];
+			for ( _ in 0...currentPalette.length )
+				prevPalette.push(h3d.Matrix.I());
+			if ( splitPalette != null ) {
+				prevSplitPalette = [];
+				for ( a in skinData.splitJoints )
+					prevSplitPalette.push([for ( j in a.joints ) prevPalette[j.bindIndex]]);
+			}
+		}
+		for ( i => m in currentPalette )
+			prevPalette[i].load(m);
+		skinShader.prevBonesMatrixes = prevPalette;
+	}
+
 	override function emit( ctx : RenderContext ) {
 	override function emit( ctx : RenderContext ) {
 		calcScreenRatio(ctx);
 		calcScreenRatio(ctx);
 		syncJoints(); // In case sync was not called because of culling (eg fixedPosition)
 		syncJoints(); // In case sync was not called because of culling (eg fixedPosition)
@@ -511,6 +548,8 @@ class Skin extends MultiMaterial {
 		} else {
 		} else {
 			var i = ctx.drawPass.index;
 			var i = ctx.drawPass.index;
 			skinShader.bonesMatrixes = splitPalette[i];
 			skinShader.bonesMatrixes = splitPalette[i];
+			if ( prevSplitPalette != null )
+				skinShader.prevBonesMatrixes = prevSplitPalette[i];
 			primitive.selectMaterial(i, primitive.screenRatioToLod(curScreenRatio));
 			primitive.selectMaterial(i, primitive.screenRatioToLod(curScreenRatio));
 			ctx.uploadParams();
 			ctx.uploadParams();
 			primitive.render(ctx.engine);
 			primitive.render(ctx.engine);

+ 9 - 6
h3d/scene/pbr/Renderer.hx

@@ -760,6 +760,7 @@ class Renderer extends h3d.scene.Renderer {
 			slides.shader.shadowMapCube = shadowMap;
 			slides.shader.shadowMapCube = shadowMap;
 			slides.shader.shadowIsCube = shadowMap.flags.has(Cube);
 			slides.shader.shadowIsCube = shadowMap.flags.has(Cube);
 			slides.shader.shadowMapChannel = R;
 			slides.shader.shadowMapChannel = R;
+			slides.shader.velocity = textures.velocity;
 			pbrProps.isScreen = true;
 			pbrProps.isScreen = true;
 			slides.render();
 			slides.render();
 			if( !debugging ) {
 			if( !debugging ) {
@@ -792,20 +793,22 @@ class Renderer extends h3d.scene.Renderer {
 		var win = hxd.Window.getInstance();
 		var win = hxd.Window.getInstance();
 
 
 		if( e.kind == ERelease && e.button == 2 && hxd.Math.distance(e.relX-debugPushPos.x,e.relY-debugPushPos.y) < 10 ) {
 		if( e.kind == ERelease && e.button == 2 && hxd.Math.distance(e.relX-debugPushPos.x,e.relY-debugPushPos.y) < 10 ) {
-			var x = Std.int((e.relX / win.width) * 4);
-			var y = Std.int((e.relY / win.height) * 4);
+			var x = Std.int((e.relX / win.width) * 3);
+			var y = Std.int((e.relY / win.height) * 3);
 			if( slides.shader.mode != Full ) {
 			if( slides.shader.mode != Full ) {
 				slides.shader.mode = Full;
 				slides.shader.mode = Full;
 			} else {
 			} else {
 				var a : Array<h3d.shader.pbr.Slides.DebugMode>;
 				var a : Array<h3d.shader.pbr.Slides.DebugMode>;
-				if( y == 3 )
-					a = [Emmissive,Depth,AO,Shadow];
+				if( y == 0 )
+					a = [Albedo,Normal,Depth];
+				else if ( y == 1 ) 
+					a = [Metalness,Roughness,AO];
 				else
 				else
-					a = [Albedo,Normal,Roughness,Metalness];
+					a = [Emissive,Shadow,Velocity];
 				slides.shader.mode = a[x];
 				slides.shader.mode = a[x];
 			}
 			}
 		}
 		}
-		if( e.kind == EWheel && (slides.shader.mode == Shadow || (slides.shader.mode == Full && e.relX > win.width/4 && e.relY > win.height/4)) )
+		if( e.kind == EWheel && (slides.shader.mode == Shadow || (slides.shader.mode == Full && e.relX > win.width/3 && e.relY > win.height/3)) )
 			debugShadowMapIndex += e.wheelDelta > 0 ? 1 : -1;
 			debugShadowMapIndex += e.wheelDelta > 0 ? 1 : -1;
 	}
 	}
 
 

+ 16 - 4
h3d/shader/Skin.hx

@@ -43,24 +43,36 @@ class Skin extends SkinBase {
 			var indexes : Bytes4;
 			var indexes : Bytes4;
 		};
 		};
 
 
-		var transformedTangent : Vec4;
 		var previousTransformedPosition : Vec3;
 		var previousTransformedPosition : Vec3;
 
 
 		function vertex() {
 		function vertex() {
+			if ( calcPrevPos ) {
+				boneMatrixX = prevBonesMatrixes[int(input.indexes.x)];
+				boneMatrixY = prevBonesMatrixes[int(input.indexes.y)];
+				boneMatrixZ = prevBonesMatrixes[int(input.indexes.z)];
+				boneMatrixW = prevBonesMatrixes[int(input.indexes.w)];
+				skinWeights = vec4(input.weights, 0.0);
+				if ( fourBonesByVertex )
+					skinWeights.w = 1 - (input.weights.x + input.weights.y + input.weights.z);
+
+				previousTransformedPosition = applySkinPoint(relativePosition);
+			}
+
 			boneMatrixX = bonesMatrixes[int(input.indexes.x)];
 			boneMatrixX = bonesMatrixes[int(input.indexes.x)];
 			boneMatrixY = bonesMatrixes[int(input.indexes.y)];
 			boneMatrixY = bonesMatrixes[int(input.indexes.y)];
 			boneMatrixZ = bonesMatrixes[int(input.indexes.z)];
 			boneMatrixZ = bonesMatrixes[int(input.indexes.z)];
 			boneMatrixW = bonesMatrixes[int(input.indexes.w)];
 			boneMatrixW = bonesMatrixes[int(input.indexes.w)];
 			skinWeights = vec4(input.weights, 0.0);
 			skinWeights = vec4(input.weights, 0.0);
-			if(fourBonesByVertex) {
+			if ( fourBonesByVertex )
 				skinWeights.w = 1 - (input.weights.x + input.weights.y + input.weights.z);
 				skinWeights.w = 1 - (input.weights.x + input.weights.y + input.weights.z);
-			}
 
 
 			transformedPosition = applySkinPoint(relativePosition);
 			transformedPosition = applySkinPoint(relativePosition);
 			transformedNormal = applySkinVec(input.normal);
 			transformedNormal = applySkinVec(input.normal);
 
 
-			previousTransformedPosition = transformedPosition;
 			transformedNormal = normalize(transformedNormal);
 			transformedNormal = normalize(transformedNormal);
+
+			if ( !calcPrevPos )
+				previousTransformedPosition = transformedPosition;
 		}
 		}
 	};
 	};
 }
 }

+ 2 - 1
h3d/shader/SkinBase.hx

@@ -10,9 +10,10 @@ class SkinBase extends hxsl.Shader {
 
 
 		@const var MaxBones : Int;
 		@const var MaxBones : Int;
 		@const @param var fourBonesByVertex = false;
 		@const @param var fourBonesByVertex = false;
+		@const var calcPrevPos : Bool = false;
 
 
 		@ignore @param var bonesMatrixes : Array<Mat3x4,MaxBones>;
 		@ignore @param var bonesMatrixes : Array<Mat3x4,MaxBones>;
-
+		@ignore @param var prevBonesMatrixes : Array<Mat3x4,MaxBones>;
 	};
 	};
 
 
 	public function new() {
 	public function new() {

+ 29 - 19
h3d/shader/SkinTangent.hx

@@ -4,6 +4,8 @@ class SkinTangent extends SkinBase {
 
 
 	static var SRC = {
 	static var SRC = {
 
 
+		@:import h3d.shader.Skin.Utils;
+
 		@input var input : {
 		@input var input : {
 			var position : Vec3;
 			var position : Vec3;
 			var normal : Vec3;
 			var normal : Vec3;
@@ -13,30 +15,38 @@ class SkinTangent extends SkinBase {
 		};
 		};
 
 
 		var transformedTangent : Vec4;
 		var transformedTangent : Vec4;
+		var previousTransformedPosition : Vec3;
 
 
 		function vertex() {
 		function vertex() {
-			transformedPosition =
-				(relativePosition * bonesMatrixes[int(input.indexes.x)]) * input.weights.x +
-				(relativePosition * bonesMatrixes[int(input.indexes.y)]) * input.weights.y +
-				(relativePosition * bonesMatrixes[int(input.indexes.z)]) * input.weights.z;
-			transformedNormal = 
-				(input.normal * mat3(bonesMatrixes[int(input.indexes.x)])) * input.weights.x +
-				(input.normal * mat3(bonesMatrixes[int(input.indexes.y)])) * input.weights.y +
-				(input.normal * mat3(bonesMatrixes[int(input.indexes.z)])) * input.weights.z;
-			transformedTangent.xyz =
-				(input.tangent.xyz * mat3(bonesMatrixes[int(input.indexes.x)])) * input.weights.x +
-				(input.tangent.xyz * mat3(bonesMatrixes[int(input.indexes.y)])) * input.weights.y +
-				(input.tangent.xyz * mat3(bonesMatrixes[int(input.indexes.z)])) * input.weights.z;
-
-			if(fourBonesByVertex) {
-				var w4 = 1 - (input.weights.x + input.weights.y + input.weights.z);
-				transformedPosition += (relativePosition * bonesMatrixes[int(input.indexes.w)]) * w4;
-				transformedNormal += (input.normal * mat3(bonesMatrixes[int(input.indexes.z)])) * w4;
-				transformedTangent.xyz += (input.tangent.xyz * mat3(bonesMatrixes[int(input.indexes.w)])) * w4;
+			if ( calcPrevPos ) {
+				boneMatrixX = prevBonesMatrixes[int(input.indexes.x)];
+				boneMatrixY = prevBonesMatrixes[int(input.indexes.y)];
+				boneMatrixZ = prevBonesMatrixes[int(input.indexes.z)];
+				boneMatrixW = prevBonesMatrixes[int(input.indexes.w)];
+				skinWeights = vec4(input.weights, 0.0);
+				if ( fourBonesByVertex )
+					skinWeights.w = 1 - (input.weights.x + input.weights.y + input.weights.z);
+
+				previousTransformedPosition = applySkinPoint(relativePosition);
 			}
 			}
-			
+
+			boneMatrixX = bonesMatrixes[int(input.indexes.x)];
+			boneMatrixY = bonesMatrixes[int(input.indexes.y)];
+			boneMatrixZ = bonesMatrixes[int(input.indexes.z)];
+			boneMatrixW = bonesMatrixes[int(input.indexes.w)];
+			skinWeights = vec4(input.weights, 0.0);
+			if ( fourBonesByVertex )
+				skinWeights.w = 1 - (input.weights.x + input.weights.y + input.weights.z);
+
+			transformedPosition = applySkinPoint(relativePosition);
+			transformedNormal = applySkinVec(input.normal);
+			transformedTangent.xyz = applySkinVec(input.tangent.xyz);
+
 			transformedNormal = normalize(transformedNormal);
 			transformedNormal = normalize(transformedNormal);
 			transformedTangent.xyz = normalize(transformedTangent.xyz);
 			transformedTangent.xyz = normalize(transformedTangent.xyz);
+
+			if ( !calcPrevPos )
+				previousTransformedPosition = transformedPosition;
 		}
 		}
 
 
 	};
 	};

+ 20 - 15
h3d/shader/pbr/Slides.hx

@@ -4,12 +4,13 @@ enum abstract DebugMode(Int) {
 	var Full = 0;
 	var Full = 0;
 	var Albedo = 1;
 	var Albedo = 1;
 	var Normal = 2;
 	var Normal = 2;
-	var Roughness = 3;
+	var Depth = 3;
 	var Metalness = 4;
 	var Metalness = 4;
-	var Emmissive = 5;
-	var Depth = 6;
-	var AO = 7;
+	var Roughness = 5;
+	var AO = 6;
+	var Emissive = 7;
 	var Shadow = 8;
 	var Shadow = 8;
+	var Velocity = 9;
 }
 }
 
 
 class Slides extends ScreenShader {
 class Slides extends ScreenShader {
@@ -28,28 +29,30 @@ class Slides extends ScreenShader {
 
 
 		@param var shadowMap : Channel;
 		@param var shadowMap : Channel;
 		@param var shadowMapCube : SamplerCube;
 		@param var shadowMapCube : SamplerCube;
+		@param var velocity : Sampler2D;
 		@const var shadowIsCube : Bool;
 		@const var shadowIsCube : Bool;
 		@const var smode : Int;
 		@const var smode : Int;
 
 
 		function getColor(x:Float,y:Float) : Vec3 {
 		function getColor(x:Float,y:Float) : Vec3 {
 			var color : Vec3;
 			var color : Vec3;
-			if( y < 3 ) {
+			if( y < 1 ) {
 				if( x < 1 )
 				if( x < 1 )
 					color = albedo.sqrt();
 					color = albedo.sqrt();
 				else if( x < 2 )
 				else if( x < 2 )
 					color = packNormal(normal).rgb;
 					color = packNormal(normal).rgb;
-				else if( x < 3 )
-					color = roughness.xxx;
 				else
 				else
-					color = metalness.xxx;
-			} else {
+					color = depth.xxx;
+			} else if ( y < 2 )  {
 				if( x < 1 )
 				if( x < 1 )
-					color = vec3(emissive, custom1, custom2);
+					color = metalness.xxx;
 				else if( x < 2 )
 				else if( x < 2 )
-					color = depth.xxx;
+					color = roughness.xxx;
 				else if( x < 3 )
 				else if( x < 3 )
 					color = occlusion.xxx;
 					color = occlusion.xxx;
-				else {
+			} else {
+				if ( x < 1 )
+					color = vec3(emissive, custom1, custom2);
+				else if ( x < 2 ) {
 					var uv = vec2(x,y) - 3;
 					var uv = vec2(x,y) - 3;
 					if( shadowIsCube ) {
 					if( shadowIsCube ) {
 						var phi = (1 - uv.x)*3.1415*2;
 						var phi = (1 - uv.x)*3.1415*2;
@@ -58,6 +61,8 @@ class Slides extends ScreenShader {
 						color = shadowMapCube.get(dir).xxx;
 						color = shadowMapCube.get(dir).xxx;
 					} else
 					} else
 						color = shadowMap.get(uv).xxx;
 						color = shadowMap.get(uv).xxx;
+				} else {
+					color = packNormal(velocity.get(input.uv).xyz * 100.0).xyz;
 				}
 				}
 			}
 			}
 			return color;
 			return color;
@@ -65,12 +70,12 @@ class Slides extends ScreenShader {
 
 
 		function fragment() {
 		function fragment() {
 			var color : Vec3;
 			var color : Vec3;
-			var x = input.uv.x * 4;
-			var y = input.uv.y * 4;
+			var x = input.uv.x * 3;
+			var y = input.uv.y * 3;
 			if( smode == 0 )
 			if( smode == 0 )
 				color = getColor(x,y);
 				color = getColor(x,y);
 			else
 			else
-				color = getColor( (smode - 1)%4 + input.uv.x, int((smode - 1) / 4) * 3 + input.uv.y );
+				color = getColor( (smode - 1)%3 + input.uv.x, int((smode - 1) / 3) + input.uv.y );
 			pixelColor = vec4(color, 1.);
 			pixelColor = vec4(color, 1.);
 		}
 		}
 	};
 	};