Sfoglia il codice sorgente

Added support for velocity buffer and jitter camera.

TothBenoit 1 anno fa
parent
commit
df14fdac42

+ 6 - 0
h3d/Camera.hx

@@ -43,6 +43,9 @@ class Camera {
 
 	public var frustum(default, null) : h3d.col.Frustum;
 
+	public var jitterOffsetX : Float = 0.;
+	public var jitterOffsetY : Float = 0.;
+
 	var minv : Matrix;
 	var mcamInv : Matrix;
 	var mprojInv : Matrix;
@@ -426,6 +429,9 @@ class Camera {
 		m._32 += viewY * m._34;
 		m._42 += viewY * m._44;
 
+		m._31 += jitterOffsetX;
+		m._32 += jitterOffsetY;
+
 		// our z is negative in that case
 		if( rightHanded ) {
 			m._33 *= -1;

+ 1 - 0
h3d/pass/Output.hx

@@ -83,6 +83,7 @@ class Output {
 		var buf = ctx.shaderBuffers, prevShader = null;
 		for( p in passes ) {
 			#if sceneprof h3d.impl.SceneProf.mark(p.obj); #end
+			ctx.globalPreviousModelView = p.obj.prevAbsPos ?? p.obj.absPos;
 			ctx.globalModelView = p.obj.absPos;
 			if( p.shader.hasGlobal(ctx.globalModelViewInverse_id.toInt()) )
 				ctx.globalModelViewInverse = p.obj.getInvPos();

+ 8 - 3
h3d/scene/MeshBatch.hx

@@ -136,6 +136,7 @@ class MeshBatch extends MultiMaterial {
 
 	static var modelViewID = hxsl.Globals.allocID("global.modelView");
 	static var modelViewInverseID = hxsl.Globals.allocID("global.modelViewInverse");
+	static var previousModelViewID = hxsl.Globals.allocID("global.previousModelView");
 	static var MAX_BUFFER_ELEMENTS = 4096;
 	static var MAX_STORAGE_BUFFER_ELEMENTS = 128 * 1024 * 1024 >> 2;
 
@@ -403,10 +404,11 @@ class MeshBatch extends MultiMaterial {
 				buf[pos++] = m._44;
 			}
 			if( p.perObjectGlobal != null ) {
-				if( p.perObjectGlobal.gid == modelViewID ) {
+				switch ( p.perObjectGlobal.gid ) {
+				case p.perObjectGlobal.gid == modelViewID :
 					batch.modelViewPos = pos - startPos;
 					addMatrix(worldPosition != null ? worldPosition : absPos);
-				} else if( p.perObjectGlobal.gid == modelViewInverseID ) {
+				case p.perObjectGlobal.gid == modelViewInverseID :
 					if( worldPosition == null )
 						addMatrix(getInvPos());
 					else {
@@ -417,8 +419,11 @@ class MeshBatch extends MultiMaterial {
 						}
 						addMatrix(invWorldPosition);
 					}
-				} else
+				case p.perObjectGlobal.gid == previousModelViewID :
+					addMatrix( worldPosition != null ? worldPosition : absPos );
+				default:
 					throw "Unsupported global param "+p.perObjectGlobal.path;
+				}
 				p = p.next;
 				continue;
 			}

+ 19 - 0
h3d/scene/Object.hx

@@ -182,6 +182,8 @@ class Object {
 	var cullingColliderInherited(get, set) : Bool;
 
 	var absPos : h3d.Matrix;
+	var prevAbsPos : h3d.Matrix;
+	var nextPrevAbsPos : h3d.Matrix;
 	var invPos : h3d.Matrix;
 	var qRot : h3d.Quat;
 	var posChanged(get,set) : Bool;
@@ -706,8 +708,23 @@ class Object {
 	function sync( ctx : RenderContext ) {
 	}
 
+	function computePrevAbsPos() {
+		if ( prevAbsPos == null )
+			return;
+		prevAbsPos.load(nextPrevAbsPos);
+		nextPrevAbsPos.load(absPos);
+	}
+
 	function syncRec( ctx : RenderContext ) {
 		#if sceneprof h3d.impl.SceneProf.mark(this); #end
+		if ( !ctx.computeVelocity ) {
+			prevAbsPos = null;
+			nextPrevAbsPos = null;
+		} else if ( prevAbsPos == null ) {
+			prevAbsPos = absPos.clone();
+			nextPrevAbsPos = absPos.clone();
+		}
+
 		if( currentAnimation != null ) {
 			var old = parent;
 			var dt = ctx.elapsedTime;
@@ -741,6 +758,7 @@ class Object {
 			if( flags.has(FFixedPositionSynced) && !changed && !ctx.wasContextLost ) {
 				ctx.visibleFlag = old;
 				ctx.cullingCollider = prevCollider;
+				computePrevAbsPos();
 				return;
 			}
 			flags.set(FFixedPositionSynced, true);
@@ -767,6 +785,7 @@ class Object {
 		}
 		ctx.visibleFlag = old;
 		ctx.cullingCollider = prevCollider;
+		computePrevAbsPos();
 	}
 
 	function syncPos() {

+ 9 - 0
h3d/scene/RenderContext.hx

@@ -17,6 +17,7 @@ class RenderContext extends h3d.impl.RenderContext {
 	public var drawPass : h3d.pass.PassObject;
 	public var pbrLightPass : h3d.mat.Pass;
 	public var computingStatic : Bool;
+	public var computeVelocity : Bool;
 
 	public var lightSystem : h3d.scene.LightSystem;
 	public var extraShaders : hxsl.ShaderList;
@@ -35,10 +36,13 @@ class RenderContext extends h3d.impl.RenderContext {
 	@global("camera.projFlip") var cameraProjFlip : Float;
 	@global("camera.viewProj") var cameraViewProj : h3d.Matrix;
 	@global("camera.inverseViewProj") var cameraInverseViewProj : h3d.Matrix;
+	@global("camera.previousViewProj") var cameraPreviousViewProj : h3d.Matrix;
+	@global("camera.jitterOffsets") var cameraJitterOffsets : h3d.Vector4;
 	@global("global.time") var globalTime : Float;
 	@global("global.pixelSize") var pixelSize : h3d.Vector;
 	@global("global.modelView") var globalModelView : h3d.Matrix;
 	@global("global.modelViewInverse") var globalModelViewInverse : h3d.Matrix;
+	@global("global.previousModelView") var globalPreviousModelView : h3d.Matrix;
 
 	var allocPool : h3d.pass.PassObject;
 	var allocFirst : h3d.pass.PassObject;
@@ -69,6 +73,8 @@ class RenderContext extends h3d.impl.RenderContext {
 		cameraProj = cam.mproj;
 		cameraPos = cam.pos;
 		cameraProjDiag = new h3d.Vector4(cam.mproj._11,cam.mproj._22,cam.mproj._33,cam.mproj._44);
+		if ( cameraPreviousViewProj == null )
+			cameraPreviousViewProj = cam.m.clone();
 		cameraViewProj = cam.m;
 		cameraInverseViewProj = camera.getInverseViewProj();
 	}
@@ -260,6 +266,9 @@ class RenderContext extends h3d.impl.RenderContext {
 		lights = null;
 
 		cameraFrustumUploaded = false;
+		
+		cameraPreviousViewProj.load(cameraViewProj);
+		computeVelocity = false;
 
 		clearCurrent();
 	}

+ 13 - 3
h3d/scene/pbr/Renderer.hx

@@ -88,6 +88,7 @@ class Renderer extends h3d.scene.Renderer {
 		depth : (null:h3d.mat.Texture),
 		hdr : (null:h3d.mat.Texture),
 		ldr : (null:h3d.mat.Texture),
+		velocity : (null:h3d.mat.Texture),
 	};
 
 	public var skyMode : SkyMode = Hide;
@@ -112,7 +113,8 @@ class Renderer extends h3d.scene.Renderer {
 		#else
 		Vec4([Value("output.metalness"), Value("output.roughness"), Value("output.emissive"), ALPHA]),
 		#end
-		Vec4([Value("output.depth"),Const(0), Const(0), ALPHA /* ? */])
+		Vec4([Value("output.depth"),Const(0), Const(0), ALPHA /* ? */]),
+		Vec4([Value("output.velocity", 2), Const(0), Const(0)])
 	]);
 	var decalsOutput = new h3d.pass.Output("decals",[
 		Vec4([Swiz(Value("output.color"),[X,Y,Z]), Value("output.albedoStrength",1)]),
@@ -137,6 +139,11 @@ class Renderer extends h3d.scene.Renderer {
 		Value("output.color"),
 		Vec4([Value("output.depth"),Const(0),Const(0),h3d.scene.pbr.Renderer.ALPHA])
 	]);
+	var colorDepthVelocityOutput = new h3d.pass.Output("colorDepthVelocityOutput",[
+		Value("output.color"),
+		Vec4([Value("output.depth"),Const(0),Const(0),h3d.scene.pbr.Renderer.ALPHA]),
+		Vec4([Value("output.velocity", 2), Const(0), Const(0)])
+	]);
 
 	public function new(?env) {
 		super();
@@ -153,6 +160,7 @@ class Renderer extends h3d.scene.Renderer {
 		allPasses.push(defaultPass);
 		allPasses.push(decalsOutput);
 		allPasses.push(colorDepthOutput);
+		allPasses.push(colorDepthVelocityOutput);
 		allPasses.push(emissiveDecalsOutput);
 		allPasses.push(new h3d.pass.Shadows(null));
 		refreshProps();
@@ -467,6 +475,7 @@ class Renderer extends h3d.scene.Renderer {
 		textures.depth = allocTarget("depth", true, 1., R32F);
 		textures.hdr = allocTarget("hdrOutput", true, 1, #if MRT_low RGB10A2 #else RGBA16F #end);
 		textures.ldr = allocTarget("ldrOutput");
+		textures.velocity = allocTarget("velocity", true, 1., RG16F );
 	}
 
 	public function getPbrDepth() {
@@ -480,6 +489,7 @@ class Renderer extends h3d.scene.Renderer {
 		ctx.setGlobal("occlusionMap", { texture : textures.pbr, channel : hxsl.Channel.B });
 		ctx.setGlobal("hdrMap", textures.hdr);
 		ctx.setGlobal("ldrMap", textures.ldr);
+		ctx.setGlobal("velocity", textures.velocity);
 		ctx.setGlobal("global.time", ctx.time);
 		ctx.setGlobal("camera.position", ctx.camera.pos);
 		ctx.setGlobal("camera.inverseViewProj", ctx.camera.getInverseViewProj());
@@ -602,8 +612,8 @@ class Renderer extends h3d.scene.Renderer {
 
 	function getPbrRenderTargets( depth : Bool ) {
 		if ( depth )
-			return [textures.albedo, textures.normal, textures.pbr #if !MRT_low , textures.other #end, getPbrDepth()];
-		return [textures.albedo, textures.normal, textures.pbr #if !MRT_low , textures.other #end];
+			return [textures.albedo, textures.normal, textures.pbr #if !MRT_low , textures.other #end, getPbrDepth(), textures.velocity];
+		return [textures.albedo, textures.normal, textures.pbr #if !MRT_low , textures.other #end, textures.velocity];
 	}
 
 	override function render() {

+ 18 - 1
h3d/shader/BaseMesh.hx

@@ -11,10 +11,12 @@ class BaseMesh extends hxsl.Shader {
 			var projFlip : Float;
 			var projDiag : Vec3;
 			var viewProj : Mat4;
+			var previousViewProj : Mat4;
 			var inverseViewProj : Mat4;
 			var zNear : Float;
 			var zFar : Float;
 			@var var dir : Vec3;
+			var jitterOffsets : Vec4;
 		};
 
 		@global var global : {
@@ -22,6 +24,7 @@ class BaseMesh extends hxsl.Shader {
 			var pixelSize : Vec2;
 			@perObject var modelView : Mat4;
 			@perObject var modelViewInverse : Mat4;
+			@perObject var previousModelView : Mat4;
 		};
 
 		@input var input : {
@@ -35,19 +38,25 @@ class BaseMesh extends hxsl.Shader {
 			var depth : Float;
 			var normal : Vec3;
 			var worldDist : Float;
+			var velocity : Vec2;
 		};
 
 		var relativePosition : Vec3;
 		var transformedPosition : Vec3;
+		var previousTransformedPosition : Vec3;
 		var pixelTransformedPosition : Vec3;
 		var transformedNormal : Vec3;
 		var projectedPosition : Vec4;
+		var previousProjectedPosition : Vec4;
 		var pixelColor : Vec4;
 		var depth : Float;
+		var ndcPosition : Vec2;
+		var previousNdcPosition : Vec2;
 		var screenUV : Vec2;
 		var specPower : Float;
 		var specColor : Vec3;
 		var worldDist : Float;
+		var pixelVelocity : Vec2;
 
 		@param var color : Vec4;
 		@range(0,100) @param var specularPower : Float;
@@ -59,6 +68,8 @@ class BaseMesh extends hxsl.Shader {
 			relativePosition = input.position;
 			transformedPosition = relativePosition * global.modelView.mat3x4();
 			projectedPosition = vec4(transformedPosition, 1) * camera.viewProj;
+			previousTransformedPosition = relativePosition * global.previousModelView.mat3x4();
+			previousProjectedPosition = vec4(previousTransformedPosition, 1) * camera.previousViewProj;
 			transformedNormal = (input.normal * global.modelView.mat3()).normalize();
 			camera.dir = (camera.position - transformedPosition).normalize();
 			pixelColor = color;
@@ -72,10 +83,15 @@ class BaseMesh extends hxsl.Shader {
 		function __init__fragment() {
 			transformedNormal = transformedNormal.normalize();
 			// same as __init__, but will force calculus inside fragment shader, which limits varyings
-			screenUV = screenToUv(projectedPosition.xy / projectedPosition.w);
+			ndcPosition = projectedPosition.xy / projectedPosition.w;
+			previousNdcPosition = previousProjectedPosition.xy / previousProjectedPosition.w;
+			screenUV = screenToUv(ndcPosition);
 			depth = projectedPosition.z / projectedPosition.w; // in case it's used in vertex : we don't want to interpolate in screen space
 			specPower = specularPower;
 			specColor = specularColor * specularAmount;
+			ndcPosition -= camera.jitterOffsets.xy;
+			previousNdcPosition -= camera.jitterOffsets.zw;
+			pixelVelocity = ( previousNdcPosition - ndcPosition ) * vec2(0.5, -0.5);
 		}
 
 		function vertex() {
@@ -88,6 +104,7 @@ class BaseMesh extends hxsl.Shader {
 			output.depth = depth;
 			output.normal = #if MRT_low packNormal(transformedNormal).rgb #else transformedNormal #end;
 			output.worldDist = worldDist;
+			output.velocity = pixelVelocity;
 		}
 
 	};

+ 2 - 0
h3d/shader/Skin.hx

@@ -12,6 +12,7 @@ class Skin extends SkinBase {
 		};
 
 		var transformedTangent : Vec4;
+		var previousTransformedPosition : Vec3;
 
 		function vertex() {
 			transformedPosition =
@@ -29,6 +30,7 @@ class Skin extends SkinBase {
 				transformedNormal += (input.normal * mat3(bonesMatrixes[int(input.indexes.z)])) * w4;
 			}
 			
+			previousTransformedPosition = transformedPosition;
 			transformedNormal = normalize(transformedNormal);
 		}