Jelajahi Sumber

Add a better motion blur

Panagiotis Christopoulos Charitos 1 tahun lalu
induk
melakukan
21d65575ae
80 mengubah file dengan 543 tambahan dan 103 penghapusan
  1. 4 4
      AnKi/Core/CoreTracer.cpp
  2. 1 2
      AnKi/Importer/GltfImporterAnimation.cpp
  3. 9 12
      AnKi/Renderer/FinalComposite.cpp
  4. 0 1
      AnKi/Renderer/FinalComposite.h
  5. 165 0
      AnKi/Renderer/MotionBlur.cpp
  6. 61 0
      AnKi/Renderer/MotionBlur.h
  7. 2 0
      AnKi/Renderer/Renderer.cpp
  8. 1 0
      AnKi/Renderer/RendererObject.def.h
  9. 1 2
      AnKi/Resource/AnimationResource.cpp
  10. 7 20
      AnKi/Shaders/FinalComposite.ankiprog
  11. 215 0
      AnKi/Shaders/MotionBlur.ankiprog
  12. 0 61
      AnKi/Shaders/MotionBlur.hlsl
  13. 1 0
      AnKi/Shaders/UiVisualizeImage.ankiprog
  14. 1 1
      Samples/Common/SampleApp.cpp
  15. TEMPAT SAMPAH
      Samples/Sponza/Assets/Background_Roughness.ankitex
  16. TEMPAT SAMPAH
      Samples/Sponza/Assets/Lion_Roughness.ankitex
  17. 28 0
      Samples/Sponza/Assets/MTL_monkey_381dce880f246211.ankimtl
  18. 13 0
      Samples/Sponza/Assets/Scene.lua
  19. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Ceiling_roughness_tga.ankitex
  20. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Column_b_roughness_tga.ankitex
  21. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Column_c_roughness_tga.ankitex
  22. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Curtain_Red_normal.ankitex
  23. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Curtain_Red_normal_tga_001.ankitex
  24. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Curtain_roughness_tga_001.ankitex
  25. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Details_metallic-Sponza_Details_roughness.ankitex
  26. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Details_normal.ankitex
  27. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Fabric_metallic-Sponza_Curtain_roughness.ankitex
  28. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_FlagPole_normal.ankitex
  29. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_FlagPole_roughness.ankitex
  30. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Floor_normal.ankitex
  31. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Floor_roughness.ankitex
  32. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Roof_normal.ankitex
  33. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Roof_roughness.ankitex
  34. TEMPAT SAMPAH
      Samples/Sponza/Assets/Sponza_Thorn_roughness.ankitex
  35. 26 0
      Samples/Sponza/Assets/SuzanneAction_a8e545711d9aeca3.ankianim
  36. 8 0
      Samples/Sponza/Assets/Suzanne_MTL_monkey_2913e2ee09fd26cb.ankimdl
  37. TEMPAT SAMPAH
      Samples/Sponza/Assets/Suzanne_e3526e1428c0763c.ankimesh
  38. TEMPAT SAMPAH
      Samples/Sponza/Assets/VaseHanging_normal_tga.ankitex
  39. TEMPAT SAMPAH
      Samples/Sponza/Assets/VaseHanging_roughness_tga.ankitex
  40. TEMPAT SAMPAH
      Samples/Sponza/Assets/VasePlant_normal.ankitex
  41. TEMPAT SAMPAH
      Samples/Sponza/Assets/VaseRound_normal.ankitex
  42. TEMPAT SAMPAH
      Samples/Sponza/Assets/VaseRound_roughness.ankitex
  43. TEMPAT SAMPAH
      Samples/Sponza/Assets/Vase_roughness.ankitex
  44. TEMPAT SAMPAH
      Samples/Sponza/Assets/background.ankitex
  45. TEMPAT SAMPAH
      Samples/Sponza/Assets/background_ddn.ankitex
  46. TEMPAT SAMPAH
      Samples/Sponza/Assets/chain_texture_tga.ankitex
  47. TEMPAT SAMPAH
      Samples/Sponza/Assets/lion.ankitex
  48. TEMPAT SAMPAH
      Samples/Sponza/Assets/lion_ddn.ankitex
  49. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_arch_ddn.ankitex
  50. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_arch_ddn_tga.ankitex
  51. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_arch_diff.ankitex
  52. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_arch_diff_tga.ankitex
  53. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_arch_spec.ankitex
  54. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_arch_spec_tga.ankitex
  55. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_bricks_a_ddn_tga.ankitex
  56. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_bricks_a_diff_tga.ankitex
  57. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_ceiling_a_diff_tga.ankitex
  58. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_column_a_ddn_tga.ankitex
  59. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_column_a_diff_tga.ankitex
  60. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_column_a_spec_tga.ankitex
  61. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_column_b_ddn_tga.ankitex
  62. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_column_b_diff_tga.ankitex
  63. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_column_c_ddn_tga.ankitex
  64. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_column_c_diff_tga.ankitex
  65. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_curtain_green_diff_tga.ankitex
  66. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_details_diff.ankitex
  67. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_fabric_blue_diff.ankitex
  68. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_fabric_diff.ankitex
  69. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_fabric_green_diff.ankitex
  70. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_flagpole_diff.ankitex
  71. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_floor_a_diff.ankitex
  72. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_roof_diff.ankitex
  73. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_thorn_ddn.ankitex
  74. TEMPAT SAMPAH
      Samples/Sponza/Assets/sponza_thorn_diff.ankitex
  75. TEMPAT SAMPAH
      Samples/Sponza/Assets/test.ankitex
  76. TEMPAT SAMPAH
      Samples/Sponza/Assets/vase_ddn.ankitex
  77. TEMPAT SAMPAH
      Samples/Sponza/Assets/vase_dif.ankitex
  78. TEMPAT SAMPAH
      Samples/Sponza/Assets/vase_hanging_tga.ankitex
  79. TEMPAT SAMPAH
      Samples/Sponza/Assets/vase_plant_tga.ankitex
  80. TEMPAT SAMPAH
      Samples/Sponza/Assets/vase_round_tga.ankitex

+ 4 - 4
AnKi/Core/CoreTracer.cpp

@@ -92,10 +92,10 @@ CoreTracer::~CoreTracer()
 Error CoreTracer::init(CString directory)
 {
 	Tracer::allocateSingleton();
-	if(Tracer::getSingleton().getEnabled() != g_tracingEnabledCVar.get())
+	if(Tracer::getSingleton().getEnabled() != g_tracingEnabledCVar)
 	{
 		// Change the value inside the if because setEnabled prints a message
-		Tracer::getSingleton().setEnabled(g_tracingEnabledCVar.get());
+		Tracer::getSingleton().setEnabled(g_tracingEnabledCVar);
 	}
 #	if ANKI_OS_ANDROID
 	if(Tracer::getSingleton().getStreamlineEnabled())
@@ -329,9 +329,9 @@ void CoreTracer::flushFrame(U64 frame)
 		},
 		&ctx);
 
-	if(Tracer::getSingleton().getEnabled() != g_tracingEnabledCVar.get())
+	if(Tracer::getSingleton().getEnabled() != g_tracingEnabledCVar)
 	{
-		Tracer::getSingleton().setEnabled(g_tracingEnabledCVar.get());
+		Tracer::getSingleton().setEnabled(g_tracingEnabledCVar);
 	}
 
 #	if ANKI_OS_ANDROID

+ 1 - 2
AnKi/Importer/GltfImporterAnimation.cpp

@@ -351,9 +351,8 @@ Error GltfImporter::writeAnimation(const cgltf_animation& anim)
 			continue;
 		}
 
-		// Only animate cameras for now
 		const cgltf_node& node = *channel.m_targetNode;
-		if(node.camera == nullptr || node.name == nullptr)
+		if(node.name == nullptr)
 		{
 			continue;
 		}

+ 9 - 12
AnKi/Renderer/FinalComposite.cpp

@@ -12,7 +12,7 @@
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/Dbg.h>
 #include <AnKi/Renderer/UiStage.h>
-#include <AnKi/Renderer/MotionVectors.h>
+#include <AnKi/Renderer/MotionBlur.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Util/CVarSet.h>
@@ -95,10 +95,9 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		pass.newTextureDependency(getRenderer().getDbg().getRt(), TextureUsageBit::kSrvPixel);
 	}
 
-	pass.newTextureDependency(getRenderer().getScale().getTonemappedRt(), TextureUsageBit::kSrvPixel);
+	pass.newTextureDependency((g_motionBlurSampleCountCVar != 0) ? getRenderer().getMotionBlur().getRt() : getRenderer().getScale().getTonemappedRt(),
+							  TextureUsageBit::kSrvPixel);
 	pass.newTextureDependency(getRenderer().getBloom().getBloomRt(), TextureUsageBit::kSrvPixel);
-	pass.newTextureDependency(getRenderer().getMotionVectors().getMotionVectorsRt(), TextureUsageBit::kSrvPixel);
-	pass.newTextureDependency(getRenderer().getGBuffer().getDepthRt(), TextureUsageBit::kSrvPixel);
 
 	Array<RenderTargetHandle, kMaxDebugRenderTargets> dbgRts;
 	ShaderProgramPtr debugProgram;
@@ -141,23 +140,21 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		// Bind stuff
 		if(!hasDebugRt)
 		{
-			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
-			cmdb.bindSampler(1, 0, getRenderer().getSamplers().m_trilinearClamp.get());
-			cmdb.bindSampler(2, 0, getRenderer().getSamplers().m_trilinearRepeat.get());
+			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
+			cmdb.bindSampler(1, 0, getRenderer().getSamplers().m_trilinearRepeat.get());
 
-			rgraphCtx.bindSrv(0, 0, getRenderer().getScale().getTonemappedRt());
+			rgraphCtx.bindSrv(
+				0, 0, (g_motionBlurSampleCountCVar != 0) ? getRenderer().getMotionBlur().getRt() : getRenderer().getScale().getTonemappedRt());
 
 			rgraphCtx.bindSrv(1, 0, getRenderer().getBloom().getBloomRt());
 			cmdb.bindSrv(2, 0, TextureView(&m_lut->getTexture(), TextureSubresourceDesc::all()));
-			rgraphCtx.bindSrv(3, 0, getRenderer().getMotionVectors().getMotionVectorsRt());
-			rgraphCtx.bindSrv(4, 0, getRenderer().getGBuffer().getDepthRt());
 
 			if(dbgEnabled)
 			{
-				rgraphCtx.bindSrv(5, 0, getRenderer().getDbg().getRt());
+				rgraphCtx.bindSrv(3, 0, getRenderer().getDbg().getRt());
 			}
 
-			const UVec4 pc(g_motionBlurSamplesCVar, floatBitsToUint(g_filmGrainStrengthCVar), getRenderer().getFrameCount() & kMaxU32, 0);
+			const UVec4 pc(floatBitsToUint(g_filmGrainStrengthCVar), getRenderer().getFrameCount() & kMaxU32, 0, 0);
 			cmdb.setFastConstants(&pc, sizeof(pc));
 		}
 		else

+ 0 - 1
AnKi/Renderer/FinalComposite.h

@@ -13,7 +13,6 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U32> g_motionBlurSamplesCVar("R", "MotionBlurSamples", 32, 0, 2048, "Max motion blur samples");
 inline NumericCVar<F32> g_filmGrainStrengthCVar("R", "FilmGrainStrength", 16.0f, 0.0f, 250.0f, "Film grain strength");
 
 /// Post-processing stage.

+ 165 - 0
AnKi/Renderer/MotionBlur.cpp

@@ -0,0 +1,165 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Renderer/MotionBlur.h>
+#include <AnKi/Renderer/Renderer.h>
+#include <AnKi/Renderer/MotionVectors.h>
+#include <AnKi/Renderer/TemporalAA.h>
+#include <AnKi/Renderer/GBuffer.h>
+#include <AnKi/Util/Tracer.h>
+
+namespace anki {
+
+Error MotionBlur::init()
+{
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/MotionBlur.ankiprogbin",
+								 {{"TILE_SIZE", MutatorValue(g_motionBlurTileSizeCVar)}, {"SAMPLE_COUNT", MutatorValue(g_motionBlurSampleCountCVar)}},
+								 m_prog, m_maxVelocityGrProg, "MaxTileVelocity"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/MotionBlur.ankiprogbin",
+								 {{"TILE_SIZE", MutatorValue(g_motionBlurTileSizeCVar)}, {"SAMPLE_COUNT", MutatorValue(g_motionBlurSampleCountCVar)}},
+								 m_prog, m_maxNeightbourVelocityGrProg, "MaxNeighbourTileVelocity"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/MotionBlur.ankiprogbin",
+								 {{"TILE_SIZE", MutatorValue(g_motionBlurTileSizeCVar)}, {"SAMPLE_COUNT", MutatorValue(g_motionBlurSampleCountCVar)}},
+								 m_prog, m_reconstructGrProg, "Reconstruct"));
+
+	const UVec2 tiledTexSize = (getRenderer().getPostProcessResolution() + g_motionBlurTileSizeCVar - 1) / g_motionBlurTileSizeCVar;
+	m_maxVelocityRtDesc =
+		getRenderer().create2DRenderTargetDescription(tiledTexSize.x(), tiledTexSize.y(), Format::kR16G16_Sfloat, "MaxTileVelocity");
+	m_maxVelocityRtDesc.bake();
+
+	m_maxNeighbourVelocityRtDesc =
+		getRenderer().create2DRenderTargetDescription(tiledTexSize.x(), tiledTexSize.y(), Format::kR16G16_Sfloat, "MaxNeighbourTileVelocity");
+	m_maxNeighbourVelocityRtDesc.bake();
+
+	m_finalRtDesc = getRenderer().create2DRenderTargetDescription(
+		getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y(),
+		(GrManager::getSingleton().getDeviceCapabilities().m_unalignedBbpTextureFormats) ? Format::kR8G8B8_Unorm : Format::kR8G8B8A8_Unorm,
+		"MotionBlur");
+	m_finalRtDesc.bake();
+
+	return Error::kNone;
+}
+
+void MotionBlur::populateRenderGraph(RenderingContext& ctx)
+{
+	ANKI_TRACE_SCOPED_EVENT(MotionBlur);
+	if(g_motionBlurSampleCountCVar == 0)
+	{
+		m_runCtx.m_rt = {};
+		return;
+	}
+
+	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
+
+	// MaxTileVelocity
+	const RenderTargetHandle maxVelRt = rgraph.newRenderTarget(m_maxVelocityRtDesc);
+	{
+		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("Motion blur min velocity");
+
+		pass.newTextureDependency(getRenderer().getMotionVectors().getMotionVectorsRt(), TextureUsageBit::kSrvCompute);
+		pass.newTextureDependency(maxVelRt, TextureUsageBit::kUavCompute);
+
+		pass.setWork([this, maxVelRt](RenderPassWorkContext& rgraphCtx) {
+			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+			cmdb.bindShaderProgram(m_maxVelocityGrProg.get());
+
+			rgraphCtx.bindSrv(0, 0, getRenderer().getMotionVectors().getMotionVectorsRt());
+			rgraphCtx.bindUav(0, 0, maxVelRt);
+
+			const UVec2 tiledTexSize = (getRenderer().getPostProcessResolution() + g_motionBlurTileSizeCVar - 1) / g_motionBlurTileSizeCVar;
+			cmdb.dispatchCompute(tiledTexSize.x(), tiledTexSize.y(), 1);
+		});
+	}
+
+	// MaxNeighbourTileVelocity
+	const RenderTargetHandle maxNeighbourVelRt = rgraph.newRenderTarget(m_maxNeighbourVelocityRtDesc);
+	{
+		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("Motion blur min neighbour vel");
+
+		pass.newTextureDependency(maxVelRt, TextureUsageBit::kSrvCompute);
+		pass.newTextureDependency(maxNeighbourVelRt, TextureUsageBit::kUavCompute);
+
+		pass.setWork([this, maxVelRt, maxNeighbourVelRt](RenderPassWorkContext& rgraphCtx) {
+			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+			cmdb.bindShaderProgram(m_maxNeightbourVelocityGrProg.get());
+
+			rgraphCtx.bindSrv(0, 0, maxVelRt);
+			rgraphCtx.bindUav(0, 0, maxNeighbourVelRt);
+
+			const UVec2 tiledTexSize = (getRenderer().getPostProcessResolution() + g_motionBlurTileSizeCVar - 1) / g_motionBlurTileSizeCVar;
+			cmdb.dispatchCompute(tiledTexSize.x(), tiledTexSize.y(), 1);
+		});
+	}
+
+	// Recustruct
+	{
+		m_runCtx.m_rt = rgraph.newRenderTarget(m_finalRtDesc);
+
+		TextureUsageBit readUsage, writeUsage;
+		RenderPassBase* ppass;
+		if(g_preferComputeCVar)
+		{
+			NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("Motion blur reconstruct");
+			ppass = &pass;
+			readUsage = TextureUsageBit::kSrvCompute;
+			writeUsage = TextureUsageBit::kUavCompute;
+		}
+		else
+		{
+			GraphicsRenderPass& pass = rgraph.newGraphicsRenderPass("Motion blur reconstruct");
+			pass.setRenderpassInfo({m_runCtx.m_rt});
+			ppass = &pass;
+			readUsage = TextureUsageBit::kSrvPixel;
+			writeUsage = TextureUsageBit::kRtvDsvWrite;
+		}
+
+		ppass->newTextureDependency(getRenderer().getTemporalAA().getTonemappedRt(), readUsage);
+		ppass->newTextureDependency(getRenderer().getGBuffer().getDepthRt(), readUsage);
+		ppass->newTextureDependency(maxNeighbourVelRt, readUsage);
+		ppass->newTextureDependency(getRenderer().getMotionVectors().getMotionVectorsRt(), readUsage);
+		ppass->newTextureDependency(m_runCtx.m_rt, writeUsage);
+
+		ppass->setWork([this, maxNeighbourVelRt, &ctx](RenderPassWorkContext& rgraphCtx) {
+			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+			cmdb.bindShaderProgram(m_reconstructGrProg.get());
+
+			rgraphCtx.bindSrv(0, 0, getRenderer().getTemporalAA().getTonemappedRt());
+			rgraphCtx.bindSrv(1, 0, getRenderer().getGBuffer().getDepthRt());
+			rgraphCtx.bindSrv(2, 0, maxNeighbourVelRt);
+			rgraphCtx.bindSrv(3, 0, getRenderer().getMotionVectors().getMotionVectorsRt());
+
+			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
+
+			class Constants
+			{
+			public:
+				Vec2 m_depthLinearizationParams;
+				U32 m_frame;
+				F32 m_far;
+			} consts;
+			consts.m_depthLinearizationParams.x() = (ctx.m_cameraNear - ctx.m_cameraFar) / ctx.m_cameraNear;
+			consts.m_depthLinearizationParams.y() = ctx.m_cameraFar / ctx.m_cameraNear;
+			consts.m_frame = getRenderer().getFrameCount() % 32;
+			consts.m_far = ctx.m_cameraFar;
+			cmdb.setFastConstants(&consts, sizeof(consts));
+
+			if(g_preferComputeCVar)
+			{
+				rgraphCtx.bindUav(0, 0, m_runCtx.m_rt);
+				dispatchPPCompute(cmdb, 8, 8, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
+			}
+			else
+			{
+				cmdb.setViewport(0, 0, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
+				drawQuad(cmdb);
+			}
+		});
+	}
+}
+
+} // end namespace anki

+ 61 - 0
AnKi/Renderer/MotionBlur.h

@@ -0,0 +1,61 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Renderer/RendererObject.h>
+
+namespace anki {
+
+/// @addtogroup renderer
+/// @{
+
+inline NumericCVar<U32> g_motionBlurTileSizeCVar("R", "MotionBlurTileSize", 32, 8, 64, "Motion blur tile size");
+inline NumericCVar<U32> g_motionBlurSampleCountCVar("R", "MotionBlurSampleCount", 16, 0, 64, "Motion blur sample count");
+
+/// Motion blur.
+class MotionBlur : public RendererObject
+{
+public:
+	MotionBlur()
+	{
+		registerDebugRenderTarget("MotionBlur");
+	}
+
+	Error init();
+
+	void populateRenderGraph(RenderingContext& ctx);
+
+	void getDebugRenderTarget([[maybe_unused]] CString rtName, Array<RenderTargetHandle, kMaxDebugRenderTargets>& handles,
+							  [[maybe_unused]] ShaderProgramPtr& optionalShaderProgram) const override
+	{
+		ANKI_ASSERT(rtName == "MotionBlur");
+		handles[0] = m_runCtx.m_rt;
+	}
+
+	RenderTargetHandle getRt() const
+	{
+		return m_runCtx.m_rt;
+	}
+
+private:
+	ShaderProgramResourcePtr m_prog;
+	ShaderProgramPtr m_maxVelocityGrProg;
+	ShaderProgramPtr m_maxNeightbourVelocityGrProg;
+	ShaderProgramPtr m_reconstructGrProg;
+
+	RenderTargetDesc m_maxVelocityRtDesc;
+	RenderTargetDesc m_maxNeighbourVelocityRtDesc;
+	RenderTargetDesc m_finalRtDesc;
+
+	class
+	{
+	public:
+		RenderTargetHandle m_rt;
+	} m_runCtx;
+};
+/// @}
+
+} // end namespace anki

+ 2 - 0
AnKi/Renderer/Renderer.cpp

@@ -45,6 +45,7 @@
 #include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/Sky.h>
+#include <AnKi/Renderer/MotionBlur.h>
 #include <AnKi/Renderer/Utils/Drawer.h>
 #include <AnKi/Renderer/Utils/GpuVisibility.h>
 #include <AnKi/Renderer/Utils/MipmapGenerator.h>
@@ -294,6 +295,7 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 	}
 	m_vrsSriGeneration->populateRenderGraph(ctx);
 	m_scale->populateRenderGraph(ctx);
+	m_motionBlur->populateRenderGraph(ctx);
 	m_bloom2->populateRenderGraph(ctx);
 	m_tonemapping->populateRenderGraph(ctx);
 	m_dbg->populateRenderGraph(ctx);

+ 1 - 0
AnKi/Renderer/RendererObject.def.h

@@ -34,6 +34,7 @@ ANKI_RENDERER_OBJECT_DEF(ClusterBinning, clusterBinning2, 1)
 ANKI_RENDERER_OBJECT_DEF(Ssao, ssao, 1)
 ANKI_RENDERER_OBJECT_DEF(Ssr, ssr, 1)
 ANKI_RENDERER_OBJECT_DEF(Sky, sky, 1)
+ANKI_RENDERER_OBJECT_DEF(MotionBlur, motionBlur, 1)
 
 // Util objects
 ANKI_RENDERER_OBJECT_DEF(RenderableDrawer, drawer, 1)

+ 1 - 2
AnKi/Resource/AnimationResource.cpp

@@ -126,7 +126,7 @@ Error AnimationResource::load(const ResourceFilename& filename, [[maybe_unused]]
 		}
 
 		// <scalingKeys>
-		ANKI_CHECK(chEl.getChildElementOptional("scalingKeys", keysEl));
+		ANKI_CHECK(chEl.getChildElementOptional("scaleKeys", keysEl));
 		if(keysEl)
 		{
 			ANKI_CHECK(keysEl.getChildElement("key", keyEl));
@@ -147,7 +147,6 @@ Error AnimationResource::load(const ResourceFilename& filename, [[maybe_unused]]
 				maxTime = std::max(maxTime, key.m_time);
 
 				// value
-				ANKI_CHECK(keyEl.getChildElement("value", el));
 				ANKI_CHECK(keyEl.getNumber(key.m_value));
 
 				// Check ident

+ 7 - 20
AnKi/Shaders/FinalComposite.ankiprog

@@ -13,26 +13,22 @@
 
 #if ANKI_PIXEL_SHADER
 #	include <AnKi/Shaders/Functions.hlsl>
-#	include <AnKi/Shaders/MotionBlur.hlsl>
 
-SamplerState g_nearestAnyClampSampler : register(s0);
-SamplerState g_linearAnyClampSampler : register(s1);
-SamplerState g_trilinearRepeatSampler : register(s2);
+SamplerState g_linearAnyClampSampler : register(s0);
+SamplerState g_trilinearRepeatSampler : register(s1);
 Texture2D<RVec4> g_lightShadingRt : register(t0);
 Texture2D<RVec4> g_ppsBloomLfRt : register(t1);
 Texture3D<RVec4> g_lut : register(t2);
-Texture2D g_motionVectorsRt : register(t3);
-Texture2D g_depthRt : register(t4);
 #	if DBG_ENABLED
-Texture2D<RVec4> g_dbgOutlineRt : register(t5);
+Texture2D<RVec4> g_dbgOutlineRt : register(t3);
 #	endif
 
 struct Constants
 {
-	U32 m_motionBlurSamples;
 	F32 m_filmGrainStrength;
 	U32 m_frameCount;
-	U32 m_padding;
+	U32 m_padding1;
+	U32 m_padding2;
 };
 ANKI_FAST_CONSTANTS(Constants, g_consts)
 
@@ -52,17 +48,8 @@ RVec3 colorGrading(RVec3 color)
 RVec4 main(VertOut input) : SV_TARGET0
 {
 	const Vec2 uv = input.m_uv;
-	RVec3 outColor;
-
-	if(g_consts.m_motionBlurSamples > 0u)
-	{
-		outColor =
-			motionBlur(g_motionVectorsRt, g_nearestAnyClampSampler, g_lightShadingRt, g_linearAnyClampSampler, uv, g_consts.m_motionBlurSamples);
-	}
-	else
-	{
-		outColor = g_lightShadingRt.SampleLevel(g_linearAnyClampSampler, uv, 0.0).rgb;
-	}
+	ANKI_MAYBE_UNUSED(uv);
+	RVec3 outColor = outColor = g_lightShadingRt.SampleLevel(g_linearAnyClampSampler, uv, 0.0).rgb;
 
 #	if BLOOM_ENABLED
 	const RVec3 bloom = g_ppsBloomLfRt.SampleLevel(g_linearAnyClampSampler, uv, 0.0).rgb;

+ 215 - 0
AnKi/Shaders/MotionBlur.ankiprog

@@ -0,0 +1,215 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// Motion blur based on "A Reconstruction Filter for Plausible Motion Blur"
+
+#pragma anki mutator SAMPLE_COUNT 8 16 32
+#pragma anki mutator TILE_SIZE 8 16 32
+
+#pragma anki technique MaxTileVelocity comp mutators TILE_SIZE
+#pragma anki technique MaxNeighbourTileVelocity comp mutators TILE_SIZE
+#pragma anki technique Reconstruct vert pixel comp
+
+#include <AnKi/Shaders/QuadVert.hlsl>
+
+Vec2 computeMaxVelocity(Vec2 a, Vec2 b)
+{
+	const F32 alen2 = dot(a, a);
+	const F32 blen2 = dot(b, b);
+	return (alen2 > blen2) ? a : b;
+}
+
+// ===========================================================================
+// MaxTileVelocity                                                           =
+// ===========================================================================
+#if ANKI_TECHNIQUE_MaxTileVelocity
+#	define NUMTHREADS 64
+
+Texture2D<Vec4> g_motionVectorsTex : register(t0);
+RWTexture2D<Vec4> g_maxVelocityTex : register(u0);
+
+groupshared Vec2 g_maxVelocities[NUMTHREADS];
+
+[numthreads(8, 8, 1)] void main(UVec2 svDispatchThreadId : SV_DispatchThreadID, U32 svGroupIndex : SV_GroupIndex, UVec2 svGroupId : SV_GroupID)
+{
+	// Gather the thread result
+	const U32 pixelsPerThread = TILE_SIZE / 8;
+	Vec2 maxV = 0.0;
+	for(U32 x = 0; x < pixelsPerThread; ++x)
+	{
+		for(U32 y = 0; y < pixelsPerThread; ++y)
+		{
+			const Vec2 v = g_motionVectorsTex[svDispatchThreadId * pixelsPerThread + UVec2(x, y)];
+			maxV = computeMaxVelocity(maxV, v);
+		}
+	}
+
+	// Parallel reduction
+	g_maxVelocities[svGroupIndex] = maxV;
+	GroupMemoryBarrierWithGroupSync();
+	[loop] for(U32 s = NUMTHREADS / 2u; s > 0u; s >>= 1u)
+	{
+		if(svGroupIndex < s)
+		{
+			g_maxVelocities[svGroupIndex] = computeMaxVelocity(g_maxVelocities[svGroupIndex], g_maxVelocities[svGroupIndex + s]);
+		}
+
+		GroupMemoryBarrierWithGroupSync();
+	}
+
+	// Write the result
+	g_maxVelocityTex[svGroupId] = Vec4(g_maxVelocities[0], 0.0, 0.0);
+}
+#endif // ANKI_TECHNIQUE_MaxTileVelocity
+
+// ===========================================================================
+// MaxNeighbourTileVelocity                                                  =
+// ===========================================================================
+#if ANKI_TECHNIQUE_MaxNeighbourTileVelocity
+Texture2D<Vec4> g_maxVelocityTex : register(t0);
+RWTexture2D<Vec4> g_maxNeighbourVelTex : register(u0);
+
+void sample(IVec2 svDispatchThreadId, IVec2 offset, inout Vec2 maxVel)
+{
+	const Vec2 v = g_maxVelocityTex[svDispatchThreadId + offset].xy;
+	maxVel = computeMaxVelocity(maxVel, v);
+}
+
+[numthreads(8, 8, 1)] void main(UVec2 svDispatchThreadId : SV_DispatchThreadID)
+{
+	Vec2 maxv = 0.0;
+	for(I32 i = -1; i <= 1; ++i)
+	{
+		for(I32 j = -1; j <= 1; ++j)
+		{
+			const Vec2 v = g_maxVelocityTex[svDispatchThreadId + IVec2(i, j)].xy;
+			maxv = computeMaxVelocity(maxv, v);
+		}
+	}
+
+	g_maxNeighbourVelTex[svDispatchThreadId] = Vec4(maxv, 0.0, 0.0);
+}
+#endif // MaxNeighbourTileVelocity
+
+// ===========================================================================
+// Reconstruct                                                               =
+// ===========================================================================
+#if ANKI_TECHNIQUE_Reconstruct && (ANKI_COMPUTE_SHADER || ANKI_PIXEL_SHADER)
+
+#	include <AnKi/Shaders/ImportanceSampling.hlsl>
+#	include <AnKi/Shaders/Functions.hlsl>
+
+Texture2D<Vec4> g_colorTex : register(t0);
+Texture2D<Vec4> g_depthTex : register(t1);
+Texture2D<Vec4> g_neighbourMaxTex : register(t2);
+Texture2D<Vec4> g_motionVectorsTex : register(t3);
+SamplerState g_linearAnyClampSampler : register(s0);
+
+#	if ANKI_COMPUTE_SHADER
+RWTexture2D<Vec4> g_blurredTex : register(u0);
+#	endif
+
+struct Constants
+{
+	Vec2 m_depthLinearizationParams;
+	U32 m_frame;
+	F32 m_far;
+};
+ANKI_FAST_CONSTANTS(Constants, g_consts);
+
+F32 cone(Vec2 x, Vec2 y, Vec2 u)
+{
+	return saturate(1.0 - length(x - y) / length(u));
+}
+
+F32 cylinder(Vec2 x, Vec2 y, Vec2 u)
+{
+	return 1.0 - smoothstep(0.95 * length(u), 1.05 * length(u), length(x - y));
+}
+
+F32 softDepthCompare(F32 za, F32 zb)
+{
+	return saturate(1.0 - (za - zb) / 0.01);
+}
+
+F32 readDepth(Vec2 uv)
+{
+	const F32 d = g_depthTex.SampleLevel(g_linearAnyClampSampler, uv, 0.0).x;
+	return -linearizeDepthOptimal(d, g_consts.m_depthLinearizationParams.x, g_consts.m_depthLinearizationParams.y) * g_consts.m_far;
+}
+
+#	if ANKI_COMPUTE_SHADER
+[numthreads(8, 8, 1)] void main(UVec2 svDispatchThreadId : SV_DispatchThreadID)
+{
+	Vec2 colorTexSize;
+	g_colorTex.GetDimensions(colorTexSize.x, colorTexSize.y);
+	const Vec2 uv = (Vec2(svDispatchThreadId) + 0.5) / colorTexSize;
+	const Vec2 x = Vec2(svDispatchThreadId) + 0.5;
+#	else
+Vec3 main(Vec2 uv : TEXCOORDS, Vec4 svPosition : SV_Position): SV_Target0
+{
+	Vec2 colorTexSize;
+	g_colorTex.GetDimensions(colorTexSize.x, colorTexSize.y);
+	const Vec2 x = svPosition.xy;
+#	endif
+
+	Vec3 outColor;
+	const Vec2 un = g_neighbourMaxTex.SampleLevel(g_linearAnyClampSampler, uv, 0.0).xy * colorTexSize;
+	const Vec3 cx = g_colorTex.SampleLevel(g_linearAnyClampSampler, uv, 0.0).xyz;
+
+	if(dot(un, un) < 0.5 * 0.5)
+	{
+		// Velocity less than 0.5 pixels. Skip blurring
+		outColor = cx;
+	}
+	else
+	{
+#	if ANKI_COMPUTE_SHADER
+		const Vec2 noise2 = spatioTemporalNoise(svDispatchThreadId, g_consts.m_frame);
+#	else
+		const Vec2 noise2 = spatioTemporalNoise(svPosition.xy, g_consts.m_frame);
+#	endif
+		const F32 j = noise2.x - 0.5;
+
+		const F32 zx = readDepth(uv);
+
+		const F32 vx = g_motionVectorsTex.SampleLevel(g_linearAnyClampSampler, uv, 0.0).xy * colorTexSize;
+		F32 weight = 1.0 / max(length(vx), 0.5);
+		outColor = cx * weight;
+
+		for(F32 i = 0.0; i < SAMPLE_COUNT; i += 1.0)
+		{
+			if(i == (SAMPLE_COUNT - 1) / 2)
+			{
+				continue;
+			}
+
+			const F32 t = lerp(-1.0, 1.0, (i + j + 1.0) / (SAMPLE_COUNT + 1));
+
+			const Vec2 y = x + un * t + 0.5;
+
+			const F32 zy = readDepth(y / colorTexSize);
+			const F32 f = softDepthCompare(zx, zy); // 1 means zy if forground
+			const F32 b = softDepthCompare(zy, zx); // 1 means zy if background
+
+			const Vec2 vy = g_motionVectorsTex.SampleLevel(g_linearAnyClampSampler, y / colorTexSize, 0.0).xy * colorTexSize;
+
+			const F32 a = f * cone(y, x, vy) + b * cone(x, y, vx) + cylinder(y, x, vy) * cylinder(x, y, vx) * 2.0;
+
+			weight += a;
+			outColor += a * g_colorTex.SampleLevel(g_linearAnyClampSampler, y / colorTexSize, 0.0).xyz;
+		}
+
+		outColor /= weight;
+	}
+
+#	if ANKI_COMPUTE_SHADER
+	g_blurredTex[svDispatchThreadId] = Vec4(outColor, 0.0);
+#	else
+	return outColor;
+#	endif
+}
+
+#endif // ANKI_TECHNIQUE_Reconstruct && (ANKI_COMPUTE_SHADER || ANKI_PIXEL_SHADER)

+ 0 - 61
AnKi/Shaders/MotionBlur.hlsl

@@ -1,61 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Shaders/Common.hlsl>
-
-// Perform motion blur.
-RVec3 motionBlur(Texture2D<Vec4> motionVectorsRt, SamplerState motionVectorsRtSampler, Texture2D<RVec4> toBlurRt, SamplerState toBlurRtSampler,
-				 Vec2 uv, U32 maxSamples)
-{
-	Vec2 toBlurRtSize;
-	toBlurRt.GetDimensions(toBlurRtSize.x, toBlurRtSize.y);
-
-	// Compute velocity. Get the max velocity around the curent sample to avoid outlines. TAA's result and the motion
-	// vectors RT do not quite overlap
-	Vec2 velocityMin = motionVectorsRt.SampleLevel(motionVectorsRtSampler, uv, 0.0).rg;
-	Vec2 velocityMax = velocityMin;
-
-	Vec2 v = motionVectorsRt.SampleLevel(motionVectorsRtSampler, uv, 0.0, IVec2(-2, -2)).rg;
-	velocityMin = min(velocityMin, v);
-	velocityMax = max(velocityMax, v);
-
-	v = motionVectorsRt.SampleLevel(motionVectorsRtSampler, uv, 0.0, IVec2(2, 2)).rg;
-	velocityMin = min(velocityMin, v);
-	velocityMax = max(velocityMax, v);
-
-	v = motionVectorsRt.SampleLevel(motionVectorsRtSampler, uv, 0.0, IVec2(-2, 2)).rg;
-	velocityMin = min(velocityMin, v);
-	velocityMax = max(velocityMax, v);
-
-	v = motionVectorsRt.SampleLevel(motionVectorsRtSampler, uv, 0.0, IVec2(2, -2)).rg;
-	velocityMin = min(velocityMin, v);
-	velocityMax = max(velocityMax, v);
-
-	const F32 mag0 = length(velocityMin);
-	const F32 mag1 = length(velocityMax);
-	const Vec2 velocity = (mag0 > mag1) ? velocityMin : velocityMax;
-
-	// Compute the sample count
-	const Vec2 slopes = abs(velocity);
-	const Vec2 sampleCount2D = slopes * toBlurRtSize;
-	F32 sampleCountf = max(sampleCount2D.x, sampleCount2D.y);
-	sampleCountf = clamp(sampleCountf, 1.0, F32(maxSamples));
-	sampleCountf = round(sampleCountf);
-
-	// Sample
-	const RF32 weight = 1.0 / sampleCountf;
-	RVec3 outColor = toBlurRt.SampleLevel(toBlurRtSampler, uv, 0.0).rgb * weight;
-	[loop] for(F32 s = 1.0; s < sampleCountf; s += 1.0)
-	{
-		const F32 f = s / sampleCountf;
-		const Vec2 sampleUv = uv + velocity * f;
-
-		outColor += toBlurRt.SampleLevel(toBlurRtSampler, sampleUv, 0.0).rgb * weight;
-	}
-
-	return outColor;
-}

+ 1 - 0
AnKi/Shaders/UiVisualizeImage.ankiprog

@@ -38,6 +38,7 @@ VertOut main(VertIn input)
 	VertOut output;
 
 	output.m_uv = input.m_uv;
+	output.m_uv.y = 1.0 - output.m_uv.y;
 	output.m_color = input.m_color;
 
 	const Vec2 pos = g_consts.m_transform.xy * input.m_position + g_consts.m_transform.zw;

+ 1 - 1
Samples/Common/SampleApp.cpp

@@ -107,7 +107,7 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::kL) == 1)
 	{
-		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "Bloom") ? "" : "Bloom");
+		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "MotionBlur") ? "" : "MotionBlur");
 	}
 
 	if(in.getKey(KeyCode::kH) == 1)

TEMPAT SAMPAH
Samples/Sponza/Assets/Background_Roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Lion_Roughness.ankitex


+ 28 - 0
Samples/Sponza/Assets/MTL_monkey_381dce880f246211.ankimtl

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- This file is auto generated by ImporterMaterial.cpp -->
+<material shadows="1">
+	<shaderProgram name="GBufferGeneric">
+		<mutation>
+			<mutator name="DIFFUSE_TEX" value="1"/>
+			<mutator name="SPECULAR_TEX" value="0"/>
+			<mutator name="ROUGHNESS_METALNESS_TEX" value="0"/>
+			<mutator name="NORMAL_TEX" value="0"/>
+			<mutator name="PARALLAX" value="0"/>
+			<mutator name="EMISSIVE_TEX" value="0"/>
+			<mutator name="ALPHA_TEST" value="0"/>
+		</mutation>
+	</shaderProgram>
+
+	<inputs>
+		
+		<input name="m_diffuseTex" value="Assets/test.ankitex"/>
+		<input name="m_diffuseScale" value="1.000000 1.000000 1.000000 1.000000"/>
+		<input name="m_specularScale" value="0.040000 0.040000 0.040000"/>
+		<input name="m_roughnessScale" value="0.500000"/>
+		<input name="m_metalnessScale" value="0.000000"/>
+		
+		<input name="m_emissionScale" value="0.000000 0.000000 0.000000"/>
+		<input name="m_subsurface" value="0.000000"/>
+		
+	</inputs>
+</material>

+ 13 - 0
Samples/Sponza/Assets/Scene.lua

@@ -2890,3 +2890,16 @@ rot:setAll(0.082121, 0.000000, -0.996622, 0.000000, 0.996622, 0.000000, 0.082121
 trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
+
+node = scene:newSceneNode("Suzanne")
+node:newModelComponent():loadModelResource("Assets/Suzanne_MTL_monkey_2913e2ee09fd26cb.ankimdl")
+trf = Transform.new()
+trf:setOrigin(Vec4.new(-15.349269, 1.508187, -2.281604, 0))
+rot = Mat3x4.new()
+rot:setAll(-0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, -1.000000, 0.000000, -0.000000, 0.000000)
+trf:setRotation(rot)
+trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
+node:setLocalTransform(trf)
+
+node = scene:tryFindSceneNode("Suzanne")
+getEventManager():newAnimationEvent("Assets/SuzanneAction_a8e545711d9aeca3.ankianim", "Suzanne", node)

TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Ceiling_roughness_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Column_b_roughness_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Column_c_roughness_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Curtain_Red_normal.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Curtain_Red_normal_tga_001.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Curtain_roughness_tga_001.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Details_metallic-Sponza_Details_roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Details_normal.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Fabric_metallic-Sponza_Curtain_roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_FlagPole_normal.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_FlagPole_roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Floor_normal.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Floor_roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Roof_normal.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Roof_roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Sponza_Thorn_roughness.ankitex


+ 26 - 0
Samples/Sponza/Assets/SuzanneAction_a8e545711d9aeca3.ankianim

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<animation>
+	<channels>
+		<channel name="Suzanne">
+			<positionKeys>
+				<key time="0.041667">-15.349269 1.508187 -2.281604</key>
+				<key time="0.375000">-15.349269 1.508187 -2.281604</key>
+			</positionKeys>
+			<rotationKeys>
+				<key time="0.041667">0.000000 0.707107 -0.000000 0.707107</key>
+				<key time="0.083333">0.095378 0.700645 -0.095378 0.700645</key>
+				<key time="0.125000">0.333838 0.623340 -0.333838 0.623340</key>
+				<key time="0.166667">0.593069 0.385057 -0.593069 0.385057</key>
+				<key time="0.208333">-0.707107 0.000000 0.707107 0.000000</key>
+				<key time="0.250000">-0.593593 0.384248 0.593594 0.384248</key>
+				<key time="0.291667">-0.336554 0.621877 0.336554 0.621877</key>
+				<key time="0.333333">-0.100534 0.699924 0.100534 0.699923</key>
+				<key time="0.375000">-0.006171 0.707080 0.006171 0.707080</key>
+			</rotationKeys>
+			<scaleKeys>
+				<key time="0.041667">1.000000</key>
+				<key time="0.375000">1.000000</key>
+			</scaleKeys>
+		</channel>
+	</channels>
+</animation>

+ 8 - 0
Samples/Sponza/Assets/Suzanne_MTL_monkey_2913e2ee09fd26cb.ankimdl

@@ -0,0 +1,8 @@
+<model>
+	<modelPatches>
+		<modelPatch>
+			<mesh>Assets/Suzanne_e3526e1428c0763c.ankimesh</mesh>
+			<material>Assets/MTL_monkey_381dce880f246211.ankimtl</material>
+		</modelPatch>
+	</modelPatches>
+</model>

TEMPAT SAMPAH
Samples/Sponza/Assets/Suzanne_e3526e1428c0763c.ankimesh


TEMPAT SAMPAH
Samples/Sponza/Assets/VaseHanging_normal_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/VaseHanging_roughness_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/VasePlant_normal.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/VaseRound_normal.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/VaseRound_roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/Vase_roughness.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/background.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/background_ddn.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/chain_texture_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/lion.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/lion_ddn.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_arch_ddn.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_arch_ddn_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_arch_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_arch_diff_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_arch_spec.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_arch_spec_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_bricks_a_ddn_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_bricks_a_diff_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_ceiling_a_diff_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_column_a_ddn_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_column_a_diff_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_column_a_spec_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_column_b_ddn_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_column_b_diff_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_column_c_ddn_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_column_c_diff_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_curtain_green_diff_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_details_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_fabric_blue_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_fabric_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_fabric_green_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_flagpole_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_floor_a_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_roof_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_thorn_ddn.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/sponza_thorn_diff.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/test.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/vase_ddn.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/vase_dif.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/vase_hanging_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/vase_plant_tga.ankitex


TEMPAT SAMPAH
Samples/Sponza/Assets/vase_round_tga.ankitex