diff --git a/Editor/Editor_UWP.vcxproj b/Editor/Editor_UWP.vcxproj index 0fcb5835f..1ea96c25b 100644 --- a/Editor/Editor_UWP.vcxproj +++ b/Editor/Editor_UWP.vcxproj @@ -105,6 +105,7 @@ %(AdditionalDependencies) $(SolutionDir)BUILD\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64;../$(Platform)/$(Configuration) false + UseLinkTimeCodeGeneration stdafx.h diff --git a/Editor/Editor_Windows.vcxproj b/Editor/Editor_Windows.vcxproj index bc8f798a0..33ab7da19 100644 --- a/Editor/Editor_Windows.vcxproj +++ b/Editor/Editor_Windows.vcxproj @@ -110,6 +110,7 @@ true true $(SolutionDir)BUILD\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + UseLinkTimeCodeGeneration 5.0 diff --git a/Editor/HairParticleWindow.cpp b/Editor/HairParticleWindow.cpp index 3d87f2ab6..dfbc96502 100644 --- a/Editor/HairParticleWindow.cpp +++ b/Editor/HairParticleWindow.cpp @@ -278,6 +278,7 @@ void HairParticleWindow::UpdateData() std::string ss; ss += "To use hair particle system, first you must select a surface mesh to spawn particles on.\n\n"; + ss += "Position format: " + std::string(wi::graphics::GetFormatString(hair->position_format)) + "\n"; ss += "Memory usage: " + wi::helper::GetMemorySizeText(hair->GetMemorySizeInBytes()) + "\n"; infoLabel.SetText(ss); diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index b29797dc6..1a75307fc 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -12,7 +12,7 @@ void MeshWindow::Create(EditorComponent* _editor) { editor = _editor; wi::gui::Window::Create(ICON_MESH " Mesh", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE); - SetSize(XMFLOAT2(580, 780)); + SetSize(XMFLOAT2(580, 800)); closeButton.SetTooltip("Delete MeshComponent"); OnClose([=](wi::gui::EventArgs args) { @@ -157,6 +157,24 @@ void MeshWindow::Create(EditorComponent* _editor) }); AddWidget(&bvhCheckBox); + quantizeCheckBox.Create("Quantization Disabled: "); + quantizeCheckBox.SetTooltip("Disable quantization of vertex positions if you notice inaccuracy errors with UNORM position formats."); + quantizeCheckBox.SetSize(XMFLOAT2(hei, hei)); + quantizeCheckBox.SetPos(XMFLOAT2(x, y += step)); + quantizeCheckBox.OnClick([&](wi::gui::EventArgs args) { + MeshComponent* mesh = editor->GetCurrentScene().meshes.GetComponent(entity); + if (mesh != nullptr) + { + mesh->SetQuantizedPositionsDisabled(args.bValue); + mesh->CreateRenderData(); + if (!mesh->BLASes.empty()) + { + mesh->CreateRaytracingRenderData(); + } + } + }); + AddWidget(&quantizeCheckBox); + impostorCreateButton.Create("Create Impostor"); impostorCreateButton.SetTooltip("Create an impostor image of the mesh. The mesh will be replaced by this image when far away, to render faster."); impostorCreateButton.SetSize(XMFLOAT2(wid, hei)); @@ -848,6 +866,7 @@ void MeshWindow::SetEntity(Entity entity, int subset) ss += "Vertex count: " + std::to_string(mesh->vertex_positions.size()) + "\n"; ss += "Index count: " + std::to_string(mesh->indices.size()) + "\n"; ss += "Index format: " + std::string(wi::graphics::GetIndexBufferFormatString(mesh->GetIndexFormat())) + "\n"; + ss += "Position format: " + std::string(wi::graphics::GetFormatString(mesh->position_format)) + "\n"; ss += "Subset count: " + std::to_string(mesh->subsets.size()) + " (" + std::to_string(mesh->GetLODCount()) + " LODs)\n"; if (!mesh->morph_targets.empty()) { @@ -878,7 +897,8 @@ void MeshWindow::SetEntity(Entity entity, int subset) if (mesh->so_pre.IsValid()) ss += "\tprevious_position;\n"; if (mesh->vb_bon.IsValid()) ss += "\tbone;\n"; if (mesh->vb_tan.IsValid()) ss += "\ttangent;\n"; - if (mesh->so_pos_nor_wind.IsValid()) ss += "\tstreamout_position_normal_wind;\n"; + if (mesh->so_pos.IsValid()) ss += "\tstreamout_position;\n"; + if (mesh->so_nor.IsValid()) ss += "\tstreamout_normals;\n"; if (mesh->so_tan.IsValid()) ss += "\tstreamout_tangents;\n"; meshInfoLabel.SetText(ss); @@ -923,6 +943,7 @@ void MeshWindow::SetEntity(Entity entity, int subset) doubleSidedCheckBox.SetCheck(mesh->IsDoubleSided()); doubleSidedShadowCheckBox.SetCheck(mesh->IsDoubleSidedShadow()); bvhCheckBox.SetCheck(mesh->bvh.IsValid()); + quantizeCheckBox.SetCheck(mesh->IsQuantizedPositionsDisabled()); const ImpostorComponent* impostor = scene.impostors.GetComponent(entity); if (impostor != nullptr) @@ -1013,6 +1034,7 @@ void MeshWindow::ResizeLayout() add_right(doubleSidedCheckBox); add_right(doubleSidedShadowCheckBox); add_right(bvhCheckBox); + add_right(quantizeCheckBox); add_fullwidth(impostorCreateButton); add(impostorDistanceSlider); add(tessellationFactorSlider); diff --git a/Editor/MeshWindow.h b/Editor/MeshWindow.h index e354252f5..490717814 100644 --- a/Editor/MeshWindow.h +++ b/Editor/MeshWindow.h @@ -18,6 +18,7 @@ public: wi::gui::CheckBox doubleSidedCheckBox; wi::gui::CheckBox doubleSidedShadowCheckBox; wi::gui::CheckBox bvhCheckBox; + wi::gui::CheckBox quantizeCheckBox; wi::gui::Button impostorCreateButton; wi::gui::Slider impostorDistanceSlider; wi::gui::Slider tessellationFactorSlider; diff --git a/Editor/PaintToolWindow.cpp b/Editor/PaintToolWindow.cpp index 3db611cfb..ed74a1de9 100644 --- a/Editor/PaintToolWindow.cpp +++ b/Editor/PaintToolWindow.cpp @@ -927,7 +927,7 @@ void PaintToolWindow::Update(float dt) break; SoftBodyPhysicsComponent* softbody = scene.softbodies.GetComponent(object->meshID); - if (softbody == nullptr || softbody->vertex_positions_simulation.empty()) + if (softbody == nullptr || !softbody->HasVertices()) break; // Painting: @@ -971,18 +971,18 @@ void PaintToolWindow::Update(float dt) const float weight1 = softbody->weights[physicsIndex1]; const float weight2 = softbody->weights[physicsIndex2]; wi::renderer::RenderableTriangle tri; - if (softbody->vertex_positions_simulation.empty()) + if (softbody->HasVertices()) + { + tri.positionA = softbody->vertex_positions_simulation[graphicsIndex0].GetPOS(); + tri.positionB = softbody->vertex_positions_simulation[graphicsIndex1].GetPOS(); + tri.positionC = softbody->vertex_positions_simulation[graphicsIndex2].GetPOS(); + } + else { XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex0]), W)); XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex1]), W)); XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex2]), W)); } - else - { - tri.positionA = softbody->vertex_positions_simulation[graphicsIndex0].pos; - tri.positionB = softbody->vertex_positions_simulation[graphicsIndex1].pos; - tri.positionC = softbody->vertex_positions_simulation[graphicsIndex2].pos; - } if (weight0 == 0) tri.colorA = XMFLOAT4(1, 1, 0, 1); else diff --git a/Template_UWP/Template_UWP.vcxproj b/Template_UWP/Template_UWP.vcxproj index 686c449e6..392996991 100644 --- a/Template_UWP/Template_UWP.vcxproj +++ b/Template_UWP/Template_UWP.vcxproj @@ -105,6 +105,7 @@ %(AdditionalDependencies) $(SolutionDir)BUILD\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64;../$(Platform)/$(Configuration) false + UseLinkTimeCodeGeneration pch.h diff --git a/Template_Windows/Template_Windows.vcxproj b/Template_Windows/Template_Windows.vcxproj index 0d1a9a1ce..256726128 100644 --- a/Template_Windows/Template_Windows.vcxproj +++ b/Template_Windows/Template_Windows.vcxproj @@ -73,6 +73,7 @@ true true $(SolutionDir)BUILD\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + UseLinkTimeCodeGeneration diff --git a/Tests/Tests.vcxproj b/Tests/Tests.vcxproj index 69062a077..22b6960de 100644 --- a/Tests/Tests.vcxproj +++ b/Tests/Tests.vcxproj @@ -76,6 +76,7 @@ true true $(SolutionDir)BUILD\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + UseLinkTimeCodeGeneration diff --git a/WickedEngine/Utility/basis_universal/encoder/jpgd.cpp b/WickedEngine/Utility/basis_universal/encoder/jpgd.cpp index fec8b7143..8ee3d06cf 100644 --- a/WickedEngine/Utility/basis_universal/encoder/jpgd.cpp +++ b/WickedEngine/Utility/basis_universal/encoder/jpgd.cpp @@ -3146,7 +3146,7 @@ namespace jpgd { for (int y = 0; y < image_height; y++) { - const uint8* pScan_line; + const uint8* pScan_line = nullptr; uint scan_line_len; if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) { diff --git a/WickedEngine/shaders/ShaderInterop_EmittedParticle.h b/WickedEngine/shaders/ShaderInterop_EmittedParticle.h index a3169e20f..39f909eab 100644 --- a/WickedEngine/shaders/ShaderInterop_EmittedParticle.h +++ b/WickedEngine/shaders/ShaderInterop_EmittedParticle.h @@ -42,6 +42,7 @@ static const uint EMITTER_OPTION_BIT_USE_RAIN_BLOCKER = 1 << 4; CBUFFER(EmittedParticleCB, CBSLOT_OTHER_EMITTEDPARTICLE) { ShaderTransform xEmitterTransform; + ShaderTransform xEmitterBaseMeshUnormRemap; uint xEmitCount; uint xEmitterMeshIndexCount; diff --git a/WickedEngine/shaders/ShaderInterop_HairParticle.h b/WickedEngine/shaders/ShaderInterop_HairParticle.h index 4401d99bf..2f6c45c09 100644 --- a/WickedEngine/shaders/ShaderInterop_HairParticle.h +++ b/WickedEngine/shaders/ShaderInterop_HairParticle.h @@ -17,6 +17,7 @@ struct PatchSimulationData CBUFFER(HairParticleCB, CBSLOT_OTHER_HAIRPARTICLE) { ShaderTransform xHairTransform; + ShaderTransform xHairBaseMeshUnormRemap; uint xHairRegenerate; float xLength; @@ -30,8 +31,8 @@ CBUFFER(HairParticleCB, CBSLOT_OTHER_HAIRPARTICLE) float xHairViewDistance; uint xHairBaseMeshIndexCount; - uint xHairBaseMeshVertexPositionStride; uint xHairInstanceIndex; + uint padding0_xHair; uint2 xHairFramesXY; uint xHairFrameCount; diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index bc17dd76d..623fc71ab 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -444,47 +444,60 @@ static const uint SHADERMESH_FLAG_EMITTEDPARTICLE = 1 << 2; // But because these are always loaded toghether by shaders, they are unrolled into one to reduce individual buffer loads struct ShaderGeometry { - int vb_pos_nor_wind; + int vb_pos_wind; int vb_uvs; int ib; uint indexOffset; + int vb_nor; int vb_tan; int vb_col; int vb_atl; - int vb_pre; + int vb_pre; uint materialIndex; uint meshletOffset; // offset of this subset in meshlets (locally within the mesh) uint meshletCount; - int impostorSliceOffset; float3 aabb_min; uint flags; float3 aabb_max; float tessellation_factor; + float2 uv_range_min; + float2 uv_range_max; + + int impostorSliceOffset; + int padding0; + int padding1; + int padding2; + void init() { ib = -1; indexOffset = 0; - vb_pos_nor_wind = -1; + vb_pos_wind = -1; vb_uvs = -1; + vb_nor = -1; vb_tan = -1; vb_col = -1; vb_atl = -1; - vb_pre = -1; + vb_pre = -1; materialIndex = 0; meshletOffset = 0; meshletCount = 0; - impostorSliceOffset = -1; aabb_min = float3(0, 0, 0); flags = 0; aabb_max = float3(0, 0, 0); tessellation_factor = 0; + + uv_range_min = float2(0, 0); + uv_range_max = float2(1, 1); + + impostorSliceOffset = -1; } }; @@ -1263,20 +1276,39 @@ CBUFFER(PaintRadiusCB, CBSLOT_RENDERER_MISC) struct SkinningPushConstants { - uint vertexCount; - int vb_pos_nor_wind; + int vb_pos_wind; + int vb_nor; int vb_tan; - int so_pos_nor_wind; + int so_pos; + int so_nor; int so_tan; int vb_bon; + int morphvb_index; + int skinningbuffer_index; uint bone_offset; - uint morph_offset; uint morph_count; - int morphvb_index; - int padding; + + float3 aabb_min; + uint vertexCount; + + float3 aabb_max; + float padding; +}; + +struct DebugObjectPushConstants +{ + int vb_pos_wind; +}; + +struct LightmapPushConstants +{ + int vb_pos_wind; + int vb_nor; + int vb_atl; + uint instanceIndex; }; struct MorphTargetGPU diff --git a/WickedEngine/shaders/bvh_primitivesCS.hlsl b/WickedEngine/shaders/bvh_primitivesCS.hlsl index 112edf669..2bb075105 100644 --- a/WickedEngine/shaders/bvh_primitivesCS.hlsl +++ b/WickedEngine/shaders/bvh_primitivesCS.hlsl @@ -32,9 +32,9 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex) uint i1 = bindless_buffers_uint[geometry.ib][startIndex + 1]; uint i2 = bindless_buffers_uint[geometry.ib][startIndex + 2]; - float3 p0 = bindless_buffers_float4[geometry.vb_pos_nor_wind][i0].xyz; - float3 p1 = bindless_buffers_float4[geometry.vb_pos_nor_wind][i1].xyz; - float3 p2 = bindless_buffers_float4[geometry.vb_pos_nor_wind][i2].xyz; + float3 p0 = bindless_buffers_float4[geometry.vb_pos_wind][i0].xyz; + float3 p1 = bindless_buffers_float4[geometry.vb_pos_wind][i1].xyz; + float3 p2 = bindless_buffers_float4[geometry.vb_pos_wind][i2].xyz; float3 P0 = mul(inst.transform.GetMatrix(), float4(p0, 1)).xyz; float3 P1 = mul(inst.transform.GetMatrix(), float4(p1, 1)).xyz; float3 P2 = mul(inst.transform.GetMatrix(), float4(p2, 1)).xyz; diff --git a/WickedEngine/shaders/emittedparticleMS.hlsl b/WickedEngine/shaders/emittedparticleMS.hlsl index 168e1b674..86b957035 100644 --- a/WickedEngine/shaders/emittedparticleMS.hlsl +++ b/WickedEngine/shaders/emittedparticleMS.hlsl @@ -75,9 +75,9 @@ void main( { uint vertexID = particleIndex * 4 + i; - float4 pos_nor_wind = bindless_buffers_float4[geometry.vb_pos_nor_wind][vertexID]; - float3 position = pos_nor_wind.xyz; - float3 normal = normalize(unpack_unitvector(asuint(pos_nor_wind.w))); + float4 pos_wind = bindless_buffers_float4[geometry.vb_pos_wind][vertexID]; + float3 position = pos_wind.xyz; + float3 normal = normalize(bindless_buffers_float4[geometry.vb_nor][vertexID].xyz); float4 uvsets = bindless_buffers_float4[geometry.vb_uvs][vertexID]; VertextoPixel_MS Out; diff --git a/WickedEngine/shaders/emittedparticleVS.hlsl b/WickedEngine/shaders/emittedparticleVS.hlsl index 09d57f09d..a73985555 100644 --- a/WickedEngine/shaders/emittedparticleVS.hlsl +++ b/WickedEngine/shaders/emittedparticleVS.hlsl @@ -20,9 +20,9 @@ VertextoPixel main(uint vid : SV_VertexID, uint instanceID : SV_InstanceID) uint particleIndex = culledIndirectionBuffer2[culledIndirectionBuffer[instanceID]]; uint vertexID = particleIndex * 4 + vid; - float4 pos_nor_wind = bindless_buffers_float4[geometry.vb_pos_nor_wind][vertexID]; - float3 position = pos_nor_wind.xyz; - float3 normal = normalize(unpack_unitvector(asuint(pos_nor_wind.w))); + float4 pos_wind = bindless_buffers_float4[geometry.vb_pos_wind][vertexID]; + float3 position = pos_wind.xyz; + float3 normal = normalize(bindless_buffers_float4[geometry.vb_nor][vertexID].xyz); float4 uvsets = bindless_buffers_float4[geometry.vb_uvs][vertexID]; float4 color = bindless_buffers_float4[geometry.vb_col][vertexID]; diff --git a/WickedEngine/shaders/emittedparticle_emitCS.hlsl b/WickedEngine/shaders/emittedparticle_emitCS.hlsl index 28d397a16..adbe40bf2 100644 --- a/WickedEngine/shaders/emittedparticle_emitCS.hlsl +++ b/WickedEngine/shaders/emittedparticle_emitCS.hlsl @@ -12,6 +12,7 @@ RWByteAddressBuffer counterBuffer : register(u4); #ifdef EMIT_FROM_MESH Buffer meshIndexBuffer : register(t0); Buffer meshVertexBuffer_POS : register(t1); +Buffer meshVertexBuffer_NOR : register(t2); #endif // EMIT_FROM_MESH @@ -39,13 +40,13 @@ void main(uint3 DTid : SV_DispatchThreadID) uint i2 = meshIndexBuffer[tri * 3 + 2]; // load vertices of triangle from vertex buffer: - float4 pos_nor0 = meshVertexBuffer_POS[i0]; - float4 pos_nor1 = meshVertexBuffer_POS[i1]; - float4 pos_nor2 = meshVertexBuffer_POS[i2]; + float3 pos0 = meshVertexBuffer_POS[i0].xyz; + float3 pos1 = meshVertexBuffer_POS[i1].xyz; + float3 pos2 = meshVertexBuffer_POS[i2].xyz; - float3 nor0 = unpack_unitvector(asuint(pos_nor0.w)); - float3 nor1 = unpack_unitvector(asuint(pos_nor1.w)); - float3 nor2 = unpack_unitvector(asuint(pos_nor2.w)); + float3 nor0 = meshVertexBuffer_NOR[i0].xyz; + float3 nor1 = meshVertexBuffer_NOR[i1].xyz; + float3 nor2 = meshVertexBuffer_NOR[i2].xyz; // random barycentric coords: float f = rng.next_float(); @@ -59,7 +60,8 @@ void main(uint3 DTid : SV_DispatchThreadID) float2 bary = float2(f, g); // compute final surface position on triangle from barycentric coords: - emitPos = attribute_at_bary(pos_nor0.xyz, pos_nor1.xyz, pos_nor2.xyz, bary); + emitPos = attribute_at_bary(pos0.xyz, pos1.xyz, pos2.xyz, bary); + emitPos = mul(xEmitterBaseMeshUnormRemap.GetMatrix(), float4(emitPos, 1)).xyz; float3 nor = normalize(attribute_at_bary(nor0, nor1, nor2, bary)); nor = normalize(mul((float3x3)worldMatrix, nor)); diff --git a/WickedEngine/shaders/emittedparticle_simulateCS.hlsl b/WickedEngine/shaders/emittedparticle_simulateCS.hlsl index 001bcd2b6..89e18846c 100644 --- a/WickedEngine/shaders/emittedparticle_simulateCS.hlsl +++ b/WickedEngine/shaders/emittedparticle_simulateCS.hlsl @@ -16,11 +16,12 @@ RWStructuredBuffer aliveBuffer_NEW : register(u2); RWStructuredBuffer deadBuffer : register(u3); RWByteAddressBuffer counterBuffer : register(u4); RWStructuredBuffer distanceBuffer : register(u6); -RWBuffer vertexBuffer_POS : register(u7); -RWBuffer vertexBuffer_UVS : register(u8); -RWBuffer vertexBuffer_COL : register(u9); -RWStructuredBuffer culledIndirectionBuffer : register(u10); -RWStructuredBuffer culledIndirectionBuffer2 : register(u11); +RWByteAddressBuffer vertexBuffer_POS : register(u7); +RWBuffer vertexBuffer_NOR : register(u8); +RWBuffer vertexBuffer_UVS : register(u9); +RWBuffer vertexBuffer_COL : register(u10); +RWStructuredBuffer culledIndirectionBuffer : register(u11); +RWStructuredBuffer culledIndirectionBuffer2 : register(u12); //#define SPH_FLOOR_COLLISION //#define SPH_BOX_COLLISION @@ -319,7 +320,8 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) quadPos = mul(quadPos, (float3x3)GetCamera().view); // reversed mul for inverse camera rotation! // write out vertex: - vertexBuffer_POS[v0 + vertexID] = float4(particle.position + quadPos, asfloat(pack_unitvector(normalize(-GetCamera().forward)))); + vertexBuffer_POS.Store((v0 + vertexID) * sizeof(float3), particle.position + quadPos); + vertexBuffer_NOR[v0 + vertexID] = float4(normalize(-GetCamera().forward), 0); vertexBuffer_UVS[v0 + vertexID] = float4(uv, uv2); vertexBuffer_COL[v0 + vertexID] = unpack_rgba(particleColorPacked); } @@ -353,10 +355,10 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) counterBuffer.InterlockedAdd(PARTICLECOUNTER_OFFSET_DEADCOUNT, 1, deadIndex); deadBuffer[deadIndex] = particleIndex; - vertexBuffer_POS[v0 + 0] = 0; - vertexBuffer_POS[v0 + 1] = 0; - vertexBuffer_POS[v0 + 2] = 0; - vertexBuffer_POS[v0 + 3] = 0; + vertexBuffer_POS.Store((v0 + 0) * sizeof(float3), 0); + vertexBuffer_POS.Store((v0 + 1) * sizeof(float3), 0); + vertexBuffer_POS.Store((v0 + 2) * sizeof(float3), 0); + vertexBuffer_POS.Store((v0 + 3) * sizeof(float3), 0); } } diff --git a/WickedEngine/shaders/globals.hlsli b/WickedEngine/shaders/globals.hlsli index e0632895a..7a972513d 100644 --- a/WickedEngine/shaders/globals.hlsli +++ b/WickedEngine/shaders/globals.hlsli @@ -435,6 +435,12 @@ inline float3 clipspace_to_uv(in float3 clipspace) return clipspace * float3(0.5, -0.5, 0.5) + 0.5; } +template +T inverse_lerp(T value1, T value2, T pos) +{ + return all(value2 == value1) ? 0 : ((pos - value1) / (value2 - value1)); +} + inline float3 GetSunColor() { return GetWeather().sun_color; } // sun color with intensity applied inline float3 GetSunDirection() { return GetWeather().sun_direction; } inline float3 GetHorizonColor() { return GetWeather().horizon.rgb; } diff --git a/WickedEngine/shaders/hairparticleVS.hlsl b/WickedEngine/shaders/hairparticleVS.hlsl index c43747006..d028daf87 100644 --- a/WickedEngine/shaders/hairparticleVS.hlsl +++ b/WickedEngine/shaders/hairparticleVS.hlsl @@ -6,15 +6,16 @@ Buffer primitiveBuffer : register(t0); VertexToPixel main(uint vid : SV_VERTEXID) { + ShaderMeshInstance inst = HairGetInstance(); ShaderGeometry geometry = HairGetGeometry(); VertexToPixel Out; Out.primitiveID = vid / 3; uint vertexID = primitiveBuffer[vid]; - float4 pos_nor_wind = bindless_buffers_float4[geometry.vb_pos_nor_wind][vertexID]; - float3 position = pos_nor_wind.xyz; - float3 normal = normalize(unpack_unitvector(asuint(pos_nor_wind.w))); + float4 pos_wind = bindless_buffers_float4[geometry.vb_pos_wind][vertexID]; + float3 position = mul(inst.transform.GetMatrix(), float4(pos_wind.xyz, 1)).xyz; + float3 normal = normalize(bindless_buffers_float4[geometry.vb_nor][vertexID].xyz); float4 uvsets = bindless_buffers_float4[geometry.vb_uvs][vertexID]; Out.fade = saturate(distance(position.xyz, GetCamera().position.xyz) / xHairViewDistance); diff --git a/WickedEngine/shaders/hairparticle_simulateCS.hlsl b/WickedEngine/shaders/hairparticle_simulateCS.hlsl index c81c79f37..57a4ad0b2 100644 --- a/WickedEngine/shaders/hairparticle_simulateCS.hlsl +++ b/WickedEngine/shaders/hairparticle_simulateCS.hlsl @@ -11,20 +11,24 @@ static const float3 HAIRPATCH[] = { Buffer meshIndexBuffer : register(t0); Buffer meshVertexBuffer_POS : register(t1); -Buffer meshVertexBuffer_length : register(t2); +Buffer meshVertexBuffer_NOR : register(t2); +Buffer meshVertexBuffer_length : register(t3); RWStructuredBuffer simulationBuffer : register(u0); RWBuffer vertexBuffer_POS : register(u1); RWBuffer vertexBuffer_UVS : register(u2); RWBuffer culledIndexBuffer : register(u3); RWStructuredBuffer indirectBuffer : register(u4); -RWByteAddressBuffer vertexBuffer_POS_RT : register(u5); +RWBuffer vertexBuffer_POS_RT : register(u5); +RWBuffer vertexBuffer_NOR : register(u6); [numthreads(THREADCOUNT_SIMULATEHAIR, 1, 1)] void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) { if (DTid.x >= xHairParticleCount) return; + + ShaderGeometry geometry = HairGetGeometry(); RNG rng; rng.init(uint2(xHairRandomSeed, DTid.x), 0); @@ -39,12 +43,12 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn uint i2 = meshIndexBuffer[tri * 3 + 2]; // load vertices of triangle from vertex buffer: - float4 pos_nor0 = meshVertexBuffer_POS[i0]; - float4 pos_nor1 = meshVertexBuffer_POS[i1]; - float4 pos_nor2 = meshVertexBuffer_POS[i2]; - float3 nor0 = unpack_unitvector(asuint(pos_nor0.w)); - float3 nor1 = unpack_unitvector(asuint(pos_nor1.w)); - float3 nor2 = unpack_unitvector(asuint(pos_nor2.w)); + float3 pos0 = meshVertexBuffer_POS[i0].xyz; + float3 pos1 = meshVertexBuffer_POS[i1].xyz; + float3 pos2 = meshVertexBuffer_POS[i2].xyz; + float3 nor0 = meshVertexBuffer_NOR[i0].xyz; + float3 nor1 = meshVertexBuffer_NOR[i1].xyz; + float3 nor2 = meshVertexBuffer_NOR[i2].xyz; float length0 = meshVertexBuffer_length[i0]; float length1 = meshVertexBuffer_length[i1]; float length2 = meshVertexBuffer_length[i2]; @@ -61,7 +65,8 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn float2 bary = float2(f, g); // compute final surface position on triangle from barycentric coords: - float3 position = attribute_at_bary(pos_nor0.xyz, pos_nor1.xyz, pos_nor2.xyz, bary); + float3 position = attribute_at_bary(pos0, pos1, pos2, bary); + position = mul(xHairBaseMeshUnormRemap.GetMatrix(), float4(position, 1)).xyz; float3 target = normalize(attribute_at_bary(nor0, nor1, nor2, bary)); float3 tangent = normalize(mul(float3(hemispherepoint_cos(rng.next_float(), rng.next_float()).xy, 0), get_tangentspace(target))); float3 binormal = cross(target, tangent); @@ -269,15 +274,17 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn const float3 wind = sample_wind(rootposition, segmentID + patchPos.y); float3 position = rootposition + patchPos + wind; + position = inverse_lerp(geometry.aabb_min, geometry.aabb_max, position); // remap to UNORM - vertexBuffer_POS[v0 + vertexID] = float4(position, asfloat(pack_unitvector(normalize(normal + wind)))); + vertexBuffer_POS[v0 + vertexID] = float4(position, 0); + vertexBuffer_NOR[v0 + vertexID] = float4(normalize(normal + wind), 0); vertexBuffer_UVS[v0 + vertexID] = uv.xyxy; // a second uv set could be used here if (distance_culled) { position = 0; // We can only zero out for raytracing geometry to keep correct prevpos swapping motion vectors! } - vertexBuffer_POS_RT.Store((v0 + vertexID) * sizeof(float3), position); + vertexBuffer_POS_RT[v0 + vertexID] = float4(position, 0); } // Frustum culling: diff --git a/WickedEngine/shaders/impostorHF.hlsli b/WickedEngine/shaders/impostorHF.hlsli index 555531374..d44163f6a 100644 --- a/WickedEngine/shaders/impostorHF.hlsli +++ b/WickedEngine/shaders/impostorHF.hlsli @@ -4,6 +4,7 @@ struct VSOut { precise float4 pos : SV_Position; + float clip : SV_ClipDistance0; float2 uv : TEXCOORD; uint slice : SLICE; nointerpolation float dither : DITHER; diff --git a/WickedEngine/shaders/impostorVS.hlsl b/WickedEngine/shaders/impostorVS.hlsl index 97aba0e30..c3c463c72 100644 --- a/WickedEngine/shaders/impostorVS.hlsl +++ b/WickedEngine/shaders/impostorVS.hlsl @@ -8,7 +8,7 @@ static const float2 BILLBOARD[] = { float2(1, 1), }; -Buffer vb_pos_nor : register(t0); +Buffer vb_pos : register(t0); ByteAddressBuffer impostor_data : register(t2); VSOut main(uint vertexID : SV_VertexID) @@ -16,7 +16,8 @@ VSOut main(uint vertexID : SV_VertexID) uint2 data = impostor_data.Load2((vertexID / 4u) * sizeof(uint2)); VSOut Out; - Out.pos3D = vb_pos_nor[vertexID].xyz; + Out.pos3D = vb_pos[vertexID].xyz; + Out.clip = dot(float4(Out.pos3D, 1), GetCamera().clip_plane); Out.pos = mul(GetCamera().view_projection, float4(Out.pos3D, 1)); Out.uv = float2(BILLBOARD[vertexID % 4u] * float2(0.5f, -0.5f) + 0.5f); Out.slice = data.x & 0xFFFFFF; diff --git a/WickedEngine/shaders/impostor_prepareCS.hlsl b/WickedEngine/shaders/impostor_prepareCS.hlsl index 467659995..97ee48f86 100644 --- a/WickedEngine/shaders/impostor_prepareCS.hlsl +++ b/WickedEngine/shaders/impostor_prepareCS.hlsl @@ -11,9 +11,10 @@ static const float3 BILLBOARD[] = }; RWBuffer output_indices : register(u0); -RWBuffer output_vertices_pos_nor : register(u1); -RWByteAddressBuffer output_impostor_data : register(u2); -RWStructuredBuffer output_indirect : register(u3); +RWByteAddressBuffer output_vertices_pos : register(u1); +RWBuffer output_vertices_nor : register(u2); +RWByteAddressBuffer output_impostor_data : register(u3); +RWStructuredBuffer output_indirect : register(u4); struct ObjectCount { @@ -103,7 +104,8 @@ void main(uint3 DTid : SV_DispatchThreadID) pos = mul(pos, float3x3(right, up, face)); pos *= instance.radius; pos += instance.center; - output_vertices_pos_nor[vertexOffset + vertexID] = float4(pos, asfloat(pack_unitvector(face))); + output_vertices_pos.Store((vertexOffset + vertexID) * sizeof(float3), pos); + output_vertices_nor[vertexOffset + vertexID] = float4(face, 0); } } } diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index da7c611c0..115a42195 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -121,17 +121,17 @@ struct VertexInput uint vertexID : SV_VertexID; uint instanceID : SV_InstanceID; - float4 GetPositionNormalWind() + float4 GetPositionWind() { - return bindless_buffers_float4[GetMesh().vb_pos_nor_wind][vertexID]; + return bindless_buffers_float4[GetMesh().vb_pos_wind][vertexID]; } - min16float4 GetUVSets() + float4 GetUVSets() { [branch] if (GetMesh().vb_uvs < 0) return 0; - return (min16float4)bindless_buffers_float4[GetMesh().vb_uvs][vertexID]; + return lerp(GetMesh().uv_range_min.xyxy, GetMesh().uv_range_max.xyxy, bindless_buffers_float4[GetMesh().vb_uvs][vertexID]); } ShaderMeshInstancePointer GetInstancePointer() @@ -159,6 +159,14 @@ struct VertexInput return 1; return (min16float4)bindless_buffers_float4[GetMesh().vb_col][vertexID]; } + + min16float3 GetNormal() + { + [branch] + if (GetMesh().vb_nor < 0) + return 0; + return (min16float3)bindless_buffers_float4[GetMesh().vb_nor][vertexID].xyz; + } min16float4 GetTangent() { @@ -191,10 +199,9 @@ struct VertexSurface inline void create(in ShaderMaterial material, in VertexInput input) { - float4 pos_nor_wind = input.GetPositionNormalWind(); - uint normal_wind = asuint(pos_nor_wind.w); - position = float4(pos_nor_wind.xyz, 1); - normal = min16float3(unpack_unitvector(normal_wind)); + float4 pos_wind = input.GetPositionWind(); + position = float4(pos_wind.xyz, 1); + normal = input.GetNormal(); color = min16float4(GetMaterial().baseColor * unpack_rgba(input.GetInstance().color)); color.a *= min16float(1 - input.GetInstancePointer().GetDither()); @@ -223,7 +230,7 @@ struct VertexSurface [branch] if (material.IsUsingWind()) { - position.xyz += sample_wind(position.xyz, ((normal_wind >> 24u) & 0xFF) / 255.0); + position.xyz += sample_wind(position.xyz, pos_wind.w); } #endif // DISABLE_WIND } diff --git a/WickedEngine/shaders/objectVS_debug.hlsl b/WickedEngine/shaders/objectVS_debug.hlsl index ec41aee91..db527cbe0 100644 --- a/WickedEngine/shaders/objectVS_debug.hlsl +++ b/WickedEngine/shaders/objectVS_debug.hlsl @@ -1,8 +1,8 @@ #include "globals.hlsli" -float4 main(float4 inPos : POSITION_NORMAL_WIND) : SV_POSITION -{ - float4 pos = mul(g_xTransform, float4(inPos.xyz, 1)); +PUSHCONSTANT(push, DebugObjectPushConstants); - return pos; +float4 main(uint vertexID : SV_VertexID) : SV_POSITION +{ + return mul(g_xTransform, float4(bindless_buffers_float4[push.vb_pos_wind][vertexID].xyz, 1)); } diff --git a/WickedEngine/shaders/renderlightmapVS.hlsl b/WickedEngine/shaders/renderlightmapVS.hlsl index f74a02e05..e76ba7ff1 100644 --- a/WickedEngine/shaders/renderlightmapVS.hlsl +++ b/WickedEngine/shaders/renderlightmapVS.hlsl @@ -1,11 +1,7 @@ #include "globals.hlsli" #include "ShaderInterop_Raytracing.h" -struct Input -{ - float4 pos : POSITION_NORMAL_WIND; - float2 atl : ATLAS; -}; +PUSHCONSTANT(push, LightmapPushConstants); struct Output { @@ -15,24 +11,25 @@ struct Output float3 normal : NORMAL; }; -Output main(Input input) +Output main(uint vertexID : SV_VertexID) { + ShaderMeshInstance inst = load_instance(push.instanceIndex); + float3 pos = bindless_buffers_float4[push.vb_pos_wind][vertexID].xyz; + float3 nor = bindless_buffers_float4[push.vb_nor][vertexID].xyz; + float2 atl = bindless_buffers_float2[push.vb_atl][vertexID]; + Output output; - output.pos = float4(input.atl, 0, 1); + output.pos = float4(atl, 0, 1); output.pos.xy = output.pos.xy * 2 - 1; output.pos.y *= -1; output.pos.xy += xTracePixelOffset; - output.uv = input.atl; + output.uv = atl; - output.pos3D = mul(g_xTransform, float4(input.pos.xyz, 1)).xyz; + output.pos3D = mul(inst.transform.GetMatrix(), float4(pos, 1)).xyz; - uint normal_wind = asuint(input.pos.w); - output.normal.x = (float)((normal_wind >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - output.normal.y = (float)((normal_wind >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - output.normal.z = (float)((normal_wind >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - output.normal = mul((float3x3)g_xTransform, output.normal); + output.normal = mul((float3x3)inst.transformInverseTranspose.GetMatrix(), nor); return output; } diff --git a/WickedEngine/shaders/skinningCS.hlsl b/WickedEngine/shaders/skinningCS.hlsl index de396323b..19d141716 100644 --- a/WickedEngine/shaders/skinningCS.hlsl +++ b/WickedEngine/shaders/skinningCS.hlsl @@ -2,24 +2,72 @@ PUSHCONSTANT(push, SkinningPushConstants); +#ifndef __PSSL__ +#undef WICKED_ENGINE_DEFAULT_ROOTSIGNATURE // don't use auto root signature! +[RootSignature( + "RootConstants(num32BitConstants=20, b999)," + "DescriptorTable( " + "SRV(t0, space = 2, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 3, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 4, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 5, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 6, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 7, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 8, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 9, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 10, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 11, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 12, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 13, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 14, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 15, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 16, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 17, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 18, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 19, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 20, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 21, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 22, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 23, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 24, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 25, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 26, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 27, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 28, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 29, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 30, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 31, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 32, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "UAV(u0, space = 33, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 34, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 35, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 36, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 37, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 38, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 39, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)," \ + "SRV(t0, space = 40, offset = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE)" \ + ")" +)] +#endif // __PSSL__ + [numthreads(64, 1, 1)] void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID) { const uint vertexID = DTid.x; [branch] - if (push.vb_pos_nor_wind < 0 || vertexID >= push.vertexCount) + if (push.vb_pos_wind < 0 || vertexID >= push.vertexCount) return; - float4 pos_nor_wind = bindless_buffers_float4[push.vb_pos_nor_wind][vertexID]; - uint nor_wind = asuint(pos_nor_wind.w); + float4 pos_wind = bindless_buffers_float4[push.vb_pos_wind][vertexID]; + float3 nor = bindless_buffers_float4[push.vb_nor][vertexID].xyz; - float3 pos = pos_nor_wind.xyz; - float4 nor = 0; - nor.x = (float)((nor_wind >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - nor.y = (float)((nor_wind >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - nor.z = (float)((nor_wind >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - nor.w = (float)((nor_wind >> 24) & 0x000000FF) / 255.0f; // wind + float3 pos = pos_wind.xyz; + if(any(push.aabb_min) || any(push.aabb_max)) + { + // UNORM vertex position remap: + pos = lerp(push.aabb_min, push.aabb_max, pos); + } float4 tan = bindless_buffers_float4[push.vb_tan][vertexID]; @@ -92,15 +140,15 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID) // Store data: [branch] - if (push.so_pos_nor_wind >= 0) + if (push.so_pos >= 0) { - uint nor_wind = 0; - nor_wind |= uint((nor.x * 0.5f + 0.5f) * 255.0f) << 0; - nor_wind |= uint((nor.y * 0.5f + 0.5f) * 255.0f) << 8; - nor_wind |= uint((nor.z * 0.5f + 0.5f) * 255.0f) << 16; - nor_wind |= uint(nor.w * 255.0f) << 24; // wind - pos_nor_wind = float4(pos.xyz, asfloat(nor_wind)); - bindless_rwbuffers_float4[push.so_pos_nor_wind][vertexID] = pos_nor_wind; + bindless_rwbuffers[push.so_pos].Store(vertexID * sizeof(float3), pos); + } + + [branch] + if (push.so_nor >= 0) + { + bindless_rwbuffers_float4[push.so_nor][vertexID] = float4(nor, 0); } [branch] diff --git a/WickedEngine/shaders/surfaceHF.hlsli b/WickedEngine/shaders/surfaceHF.hlsli index f070311f5..69d90a0a3 100644 --- a/WickedEngine/shaders/surfaceHF.hlsli +++ b/WickedEngine/shaders/surfaceHF.hlsli @@ -331,7 +331,7 @@ struct Surface return false; geometry = load_geometry(inst.geometryOffset + prim.subsetIndex); - if (geometry.vb_pos_nor_wind < 0) + if (geometry.vb_pos_wind < 0) return false; material = load_material(geometry.materialIndex); @@ -345,7 +345,7 @@ struct Surface i1 = indexBuffer[startIndex + 1]; i2 = indexBuffer[startIndex + 2]; - Buffer buf = bindless_buffers_float4[NonUniformResourceIndex(geometry.vb_pos_nor_wind)]; + Buffer buf = bindless_buffers_float4[NonUniformResourceIndex(geometry.vb_pos_wind)]; data0 = buf[i0]; data1 = buf[i1]; data2 = buf[i2]; @@ -360,13 +360,19 @@ struct Surface const bool is_emittedparticle = geometry.flags & SHADERMESH_FLAG_EMITTEDPARTICLE; const bool simple_lighting = is_hairparticle || is_emittedparticle; const bool is_backface = flags & SURFACE_FLAG_BACKFACE; - - float3 n0 = unpack_unitvector(asuint(data0.w)); - float3 n1 = unpack_unitvector(asuint(data1.w)); - float3 n2 = unpack_unitvector(asuint(data2.w)); - N = attribute_at_bary(n0, n1, n2, bary); - N = mul((float3x3)inst.transformInverseTranspose.GetMatrix(), N); - N = normalize(N); + + [branch] + if (geometry.vb_nor >= 0) + { + Buffer buf = bindless_buffers_float4[NonUniformResourceIndex(geometry.vb_nor)]; + float3 n0 = buf[i0].xyz; + float3 n1 = buf[i1].xyz; + float3 n2 = buf[i2].xyz; + N = attribute_at_bary(n0, n1, n2, bary); + N = mul((float3x3)inst.transformInverseTranspose.GetMatrix(), N); + N = normalize(N); + } + if (is_backface && !is_hairparticle && !is_emittedparticle) { N = -N; @@ -396,9 +402,9 @@ struct Surface if (geometry.vb_uvs >= 0) { Buffer buf = bindless_buffers_float4[NonUniformResourceIndex(geometry.vb_uvs)]; - float4 uv0 = buf[i0]; - float4 uv1 = buf[i1]; - float4 uv2 = buf[i2]; + float4 uv0 = lerp(geometry.uv_range_min.xyxy, geometry.uv_range_max.xyxy, buf[i0]); + float4 uv1 = lerp(geometry.uv_range_min.xyxy, geometry.uv_range_max.xyxy, buf[i1]); + float4 uv2 = lerp(geometry.uv_range_min.xyxy, geometry.uv_range_max.xyxy, buf[i2]); // all three must be transformed, to have correct derivatives (not enough to only transform final uvsets): uv0.xy = mad(uv0.xy, material.texMulAdd.xy, material.texMulAdd.zw); uv1.xy = mad(uv1.xy, material.texMulAdd.xy, material.texMulAdd.zw); @@ -882,12 +888,9 @@ struct Surface [branch] if (material.IsUsingWind()) { - float wind0 = ((asuint(data0.w) >> 24u) & 0xFF) / 255.0; - float wind1 = ((asuint(data1.w) >> 24u) & 0xFF) / 255.0; - float wind2 = ((asuint(data2.w) >> 24u) & 0xFF) / 255.0; - pre0 += sample_wind_prev(pre0, wind0); - pre1 += sample_wind_prev(pre1, wind1); - pre2 += sample_wind_prev(pre2, wind2); + pre0 += sample_wind_prev(pre0, data0.w); + pre1 += sample_wind_prev(pre1, data1.w); + pre2 += sample_wind_prev(pre2, data2.w); } pre = attribute_at_bary(pre0, pre1, pre2, bary); #else @@ -959,12 +962,9 @@ struct Surface [branch] if (material.IsUsingWind()) { - float wind0 = ((asuint(data0.w) >> 24u) & 0xFF) / 255.0; - float wind1 = ((asuint(data1.w) >> 24u) & 0xFF) / 255.0; - float wind2 = ((asuint(data2.w) >> 24u) & 0xFF) / 255.0; - P0 += sample_wind(P0, wind0); - P1 += sample_wind(P1, wind1); - P2 += sample_wind(P2, wind2); + P0 += sample_wind(P0, data0.w); + P1 += sample_wind(P1, data1.w); + P2 += sample_wind(P2, data2.w); } #endif // SURFACE_LOAD_ENABLE_WIND @@ -1003,14 +1003,9 @@ struct Surface [branch] if (material.IsUsingWind()) { - float wind0 = ((asuint(data0.w) >> 24u) & 0xFF) / 255.0; - float wind1 = ((asuint(data1.w) >> 24u) & 0xFF) / 255.0; - float wind2 = ((asuint(data2.w) >> 24u) & 0xFF) / 255.0; - - // this is hella slow to do per pixel: - P0 += sample_wind(P0, wind0); - P1 += sample_wind(P1, wind1); - P2 += sample_wind(P2, wind2); + P0 += sample_wind(P0, data0.w); + P1 += sample_wind(P1, data1.w); + P2 += sample_wind(P2, data2.w); } #endif // SURFACE_LOAD_ENABLE_WIND diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp index 54ec9f768..660751b17 100644 --- a/WickedEngine/wiEmittedParticle.cpp +++ b/WickedEngine/wiEmittedParticle.cpp @@ -104,12 +104,14 @@ namespace wi } const uint64_t alignment = device->GetMinOffsetAlignment(&bd); - vb_pos.size = sizeof(MeshComponent::Vertex_POS) * 4 * MAX_PARTICLES; + vb_pos.size = sizeof(MeshComponent::Vertex_POS32) * 4 * MAX_PARTICLES; + vb_nor.size = sizeof(MeshComponent::Vertex_NOR) * 4 * MAX_PARTICLES; vb_uvs.size = sizeof(MeshComponent::Vertex_UVS) * 4 * MAX_PARTICLES; vb_col.size = sizeof(MeshComponent::Vertex_COL) * 4 * MAX_PARTICLES; bd.size = AlignTo(vb_pos.size, alignment) + + AlignTo(vb_nor.size, alignment) + AlignTo(vb_uvs.size, alignment) + AlignTo(vb_col.size, alignment) ; @@ -121,11 +123,18 @@ namespace wi vb_pos.offset = buffer_offset; buffer_offset += AlignTo(vb_pos.size, alignment); - vb_pos.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos.offset, vb_pos.size, &MeshComponent::Vertex_POS::FORMAT); - vb_pos.subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos.offset, vb_pos.size, &MeshComponent::Vertex_POS::FORMAT); + vb_pos.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos.offset, vb_pos.size, &MeshComponent::Vertex_POS32::FORMAT); + vb_pos.subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos.offset, vb_pos.size); // UAV can't have RGB32_F format! vb_pos.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_pos.subresource_srv); vb_pos.descriptor_uav = device->GetDescriptorIndex(&generalBuffer, SubresourceType::UAV, vb_pos.subresource_uav); + vb_nor.offset = buffer_offset; + buffer_offset += AlignTo(vb_nor.size, alignment); + vb_nor.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_nor.offset, vb_nor.size, &MeshComponent::Vertex_NOR::FORMAT); + vb_nor.subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_nor.offset, vb_nor.size, &MeshComponent::Vertex_NOR::FORMAT); + vb_nor.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_nor.subresource_srv); + vb_nor.descriptor_uav = device->GetDescriptorIndex(&generalBuffer, SubresourceType::UAV, vb_nor.subresource_uav); + vb_uvs.offset = buffer_offset; buffer_offset += AlignTo(vb_uvs.size, alignment); vb_uvs.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_uvs.offset, vb_uvs.size, &MeshComponent::Vertex_UVS::FORMAT); @@ -278,9 +287,9 @@ namespace wi geometry.triangles.index_format = GetIndexBufferFormat(primitiveBuffer.desc.format); geometry.triangles.index_count = MAX_PARTICLES * 6; geometry.triangles.index_offset = 0; - geometry.triangles.vertex_count = (uint32_t)(vb_pos.size / sizeof(MeshComponent::Vertex_POS)); - geometry.triangles.vertex_format = Format::R32G32B32_FLOAT; - geometry.triangles.vertex_stride = sizeof(MeshComponent::Vertex_POS); + geometry.triangles.vertex_count = (uint32_t)(vb_pos.size / sizeof(MeshComponent::Vertex_POS32)); + geometry.triangles.vertex_format = MeshComponent::Vertex_POS32::FORMAT; + geometry.triangles.vertex_stride = sizeof(MeshComponent::Vertex_POS32); bool success = device->CreateRaytracingAccelerationStructure(&desc, &BLAS); assert(success); @@ -365,6 +374,16 @@ namespace wi { EmittedParticleCB cb; cb.xEmitterTransform.Create(worldMatrix); + if (mesh == nullptr || !IsFormatUnorm(mesh->position_format) || mesh->so_pos.IsValid()) + { + cb.xEmitterBaseMeshUnormRemap.init(); + } + else + { + XMFLOAT4X4 unormRemap; + XMStoreFloat4x4(&unormRemap, mesh->aabb.getUnormRemapMatrix()); + cb.xEmitterBaseMeshUnormRemap.Create(unormRemap); + } cb.xEmitCount = (uint32_t)emit; cb.xEmitterMeshIndexCount = mesh == nullptr ? 0 : (uint32_t)mesh->indices.size(); cb.xEmitterRandomness = wi::random::GetRandom(0.0f, 1.0f); @@ -446,21 +465,24 @@ namespace wi device->BindUAV(&indirectBuffers, 5, cmd); device->BindUAV(&distanceBuffer, 6, cmd); device->BindUAV(&generalBuffer, 7, cmd, vb_pos.subresource_uav); - device->BindUAV(&generalBuffer, 8, cmd, vb_uvs.subresource_uav); - device->BindUAV(&generalBuffer, 9, cmd, vb_col.subresource_uav); - device->BindUAV(&culledIndirectionBuffer, 10, cmd); - device->BindUAV(&culledIndirectionBuffer2, 11, cmd); + device->BindUAV(&generalBuffer, 8, cmd, vb_nor.subresource_uav); + device->BindUAV(&generalBuffer, 9, cmd, vb_uvs.subresource_uav); + device->BindUAV(&generalBuffer, 10, cmd, vb_col.subresource_uav); + device->BindUAV(&culledIndirectionBuffer, 11, cmd); + device->BindUAV(&culledIndirectionBuffer2, 12, cmd); if (mesh != nullptr) { device->BindResource(&mesh->generalBuffer, 0, cmd, mesh->ib.subresource_srv); if (mesh->streamoutBuffer.IsValid()) { - device->BindResource(&mesh->streamoutBuffer, 1, cmd, mesh->so_pos_nor_wind.subresource_srv); + device->BindResource(&mesh->streamoutBuffer, 1, cmd, mesh->so_pos.subresource_srv); + device->BindResource(&mesh->streamoutBuffer, 2, cmd, mesh->so_nor.subresource_srv); } else { - device->BindResource(&mesh->generalBuffer, 1, cmd, mesh->vb_pos_nor_wind.subresource_srv); + device->BindResource(&mesh->generalBuffer, 1, cmd, mesh->vb_pos_wind.subresource_srv); + device->BindResource(&mesh->generalBuffer, 2, cmd, mesh->vb_nor.subresource_srv); } } @@ -624,10 +646,11 @@ namespace wi device->BindUAV(&indirectBuffers, 5, cmd); device->BindUAV(&distanceBuffer, 6, cmd); device->BindUAV(&generalBuffer, 7, cmd, vb_pos.subresource_uav); - device->BindUAV(&generalBuffer, 8, cmd, vb_uvs.subresource_uav); - device->BindUAV(&generalBuffer, 9, cmd, vb_col.subresource_uav); - device->BindUAV(&culledIndirectionBuffer, 10, cmd); - device->BindUAV(&culledIndirectionBuffer2, 11, cmd); + device->BindUAV(&generalBuffer, 8, cmd, vb_nor.subresource_uav); + device->BindUAV(&generalBuffer, 9, cmd, vb_uvs.subresource_uav); + device->BindUAV(&generalBuffer, 10, cmd, vb_col.subresource_uav); + device->BindUAV(&culledIndirectionBuffer, 11, cmd); + device->BindUAV(&culledIndirectionBuffer2, 12, cmd); // update CURRENT alive list, write NEW alive list if (IsSorted()) diff --git a/WickedEngine/wiEmittedParticle.h b/WickedEngine/wiEmittedParticle.h index 0b61b9cdd..810a3181e 100644 --- a/WickedEngine/wiEmittedParticle.h +++ b/WickedEngine/wiEmittedParticle.h @@ -46,6 +46,7 @@ namespace wi wi::graphics::GPUBuffer constantBuffer; wi::graphics::GPUBuffer generalBuffer; wi::scene::MeshComponent::BufferView vb_pos; + wi::scene::MeshComponent::BufferView vb_nor; wi::scene::MeshComponent::BufferView vb_uvs; wi::scene::MeshComponent::BufferView vb_col; wi::graphics::GPUBuffer primitiveBuffer; // raytracing diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index ad0bff20b..41779641a 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -408,8 +408,6 @@ namespace wi::enums // input layouts enum ILTYPES { - ILTYPE_OBJECT_DEBUG, - ILTYPE_RENDERLIGHTMAP, ILTYPE_VERTEXCOLOR, ILTYPE_POSITION, ILTYPE_COUNT diff --git a/WickedEngine/wiHairParticle.cpp b/WickedEngine/wiHairParticle.cpp index 096eff1f1..ae9d48793 100644 --- a/WickedEngine/wiHairParticle.cpp +++ b/WickedEngine/wiHairParticle.cpp @@ -48,6 +48,15 @@ namespace wi void HairParticleSystem::CreateFromMesh(const wi::scene::MeshComponent& mesh) { + if (mesh.so_pos.IsValid()) + { + position_format = MeshComponent::Vertex_POS32::FORMAT; + } + else + { + position_format = MeshComponent::Vertex_POS16::FORMAT; + } + if (vertex_lengths.size() != mesh.vertex_positions.size()) { vertex_lengths.resize(mesh.vertex_positions.size()); @@ -96,22 +105,25 @@ namespace wi bd.misc_flags |= ResourceMiscFlag::RAY_TRACING; } + const size_t position_stride = GetFormatStride(position_format); const Format ib_format = GetIndexBufferFormatRaw(particleCount * 4); const uint64_t alignment = device->GetMinOffsetAlignment(&bd); simulation_view.size = sizeof(PatchSimulationData) * particleCount; - vb_pos[0].size = sizeof(MeshComponent::Vertex_POS) * 4 * particleCount; - vb_pos[1].size = sizeof(MeshComponent::Vertex_POS) * 4 * particleCount; + vb_pos[0].size = position_stride * 4 * particleCount; + vb_pos[1].size = position_stride * 4 * particleCount; + vb_nor.size = sizeof(MeshComponent::Vertex_NOR) * 4 * particleCount; vb_uvs.size = sizeof(MeshComponent::Vertex_UVS) * 4 * particleCount; ib_culled.size = GetFormatStride(ib_format) * 6 * particleCount; indirect_view.size = sizeof(IndirectDrawArgsIndexedInstanced); - vb_pos_raytracing.size = sizeof(float3) * 4 * particleCount; + vb_pos_raytracing.size = position_stride * 4 * particleCount; bd.size = AlignTo(AlignTo(indirect_view.size, alignment), sizeof(IndirectDrawArgsIndexedInstanced)) + // additional structured buffer alignment AlignTo(AlignTo(simulation_view.size, alignment), sizeof(PatchSimulationData)) + // additional structured buffer alignment AlignTo(vb_pos[0].size, alignment) + AlignTo(vb_pos[1].size, alignment) + + AlignTo(vb_nor.size, alignment) + AlignTo(vb_uvs.size, alignment) + AlignTo(ib_culled.size, alignment) + AlignTo(vb_pos_raytracing.size, alignment) @@ -144,20 +156,28 @@ namespace wi buffer_offset = AlignTo(buffer_offset, alignment); vb_pos[0].offset = buffer_offset; - vb_pos[0].subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos[0].offset, vb_pos[0].size, &MeshComponent::Vertex_POS::FORMAT); - vb_pos[0].subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos[0].offset, vb_pos[0].size, &MeshComponent::Vertex_POS::FORMAT); + vb_pos[0].subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos[0].offset, vb_pos[0].size, &position_format); + vb_pos[0].subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos[0].offset, vb_pos[0].size, &position_format); vb_pos[0].descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_pos[0].subresource_srv); vb_pos[0].descriptor_uav = device->GetDescriptorIndex(&generalBuffer, SubresourceType::UAV, vb_pos[0].subresource_uav); buffer_offset += vb_pos[0].size; buffer_offset = AlignTo(buffer_offset, alignment); vb_pos[1].offset = buffer_offset; - vb_pos[1].subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos[1].offset, vb_pos[1].size, &MeshComponent::Vertex_POS::FORMAT); - vb_pos[1].subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos[1].offset, vb_pos[1].size, &MeshComponent::Vertex_POS::FORMAT); + vb_pos[1].subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos[1].offset, vb_pos[1].size, &position_format); + vb_pos[1].subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos[1].offset, vb_pos[1].size, &position_format); vb_pos[1].descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_pos[1].subresource_srv); vb_pos[1].descriptor_uav = device->GetDescriptorIndex(&generalBuffer, SubresourceType::UAV, vb_pos[1].subresource_uav); buffer_offset += vb_pos[1].size; + buffer_offset = AlignTo(buffer_offset, alignment); + vb_nor.offset = buffer_offset; + vb_nor.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_nor.offset, vb_nor.size, &MeshComponent::Vertex_NOR::FORMAT); + vb_nor.subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_nor.offset, vb_nor.size, &MeshComponent::Vertex_NOR::FORMAT); + vb_nor.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_nor.subresource_srv); + vb_nor.descriptor_uav = device->GetDescriptorIndex(&generalBuffer, SubresourceType::UAV, vb_nor.subresource_uav); + buffer_offset += vb_nor.size; + buffer_offset = AlignTo(buffer_offset, alignment); vb_uvs.offset = buffer_offset; vb_uvs.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_uvs.offset, vb_uvs.size, &MeshComponent::Vertex_UVS::FORMAT); @@ -176,7 +196,7 @@ namespace wi buffer_offset = AlignTo(buffer_offset, alignment); vb_pos_raytracing.offset = buffer_offset; - vb_pos_raytracing.subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos_raytracing.offset, vb_pos_raytracing.size); + vb_pos_raytracing.subresource_uav = device->CreateSubresource(&generalBuffer, SubresourceType::UAV, vb_pos_raytracing.offset, vb_pos_raytracing.size, &position_format); vb_pos_raytracing.descriptor_uav = device->GetDescriptorIndex(&generalBuffer, SubresourceType::UAV, vb_pos_raytracing.subresource_uav); buffer_offset += vb_pos_raytracing.size; @@ -240,9 +260,9 @@ namespace wi geometry.triangles.index_format = GetIndexBufferFormat(primitiveBuffer.desc.format); geometry.triangles.index_count = GetParticleCount() * 6; geometry.triangles.index_offset = 0; - geometry.triangles.vertex_count = (uint32_t)(vb_pos_raytracing.size / sizeof(float3)); - geometry.triangles.vertex_format = Format::R32G32B32_FLOAT; - geometry.triangles.vertex_stride = sizeof(float3); + geometry.triangles.vertex_count = (uint32_t)(vb_pos_raytracing.size / GetFormatStride(position_format)); + geometry.triangles.vertex_format = position_format == Format::R32G32B32A32_FLOAT ? Format::R32G32B32_FLOAT : position_format; + geometry.triangles.vertex_stride = GetFormatStride(position_format); geometry.triangles.vertex_byte_offset = vb_pos_raytracing.offset; bool success = device->CreateRaytracingAccelerationStructure(&desc, &BLAS); @@ -317,6 +337,16 @@ namespace wi } HairParticleCB hcb; hcb.xHairTransform.Create(hair.world); + if (!IsFormatUnorm(mesh.position_format) || mesh.so_pos.IsValid()) + { + hcb.xHairBaseMeshUnormRemap.init(); + } + else + { + XMFLOAT4X4 unormRemap; + XMStoreFloat4x4(&unormRemap, mesh.aabb.getUnormRemapMatrix()); + hcb.xHairBaseMeshUnormRemap.Create(unormRemap); + } hcb.xHairRegenerate = hair.regenerate_frame ? 1 : 0; hcb.xLength = hair.length; hcb.xStiffness = hair.stiffness; @@ -327,7 +357,6 @@ namespace wi hcb.xHairRandomSeed = hair.randomSeed; hcb.xHairViewDistance = hair.viewDistance; hcb.xHairBaseMeshIndexCount = (uint)hair.indices.size(); - hcb.xHairBaseMeshVertexPositionStride = sizeof(MeshComponent::Vertex_POS); hcb.xHairFramesXY = uint2(std::max(1u, hair.framesX), std::max(1u, hair.framesY)); hcb.xHairFrameCount = std::max(1u, hair.frameCount); hcb.xHairFrameStart = hair.frameStart; @@ -375,6 +404,7 @@ namespace wi device->BindUAV(&hair.generalBuffer, 3, cmd, hair.ib_culled.subresource_uav); device->BindUAV(&hair.generalBuffer, 4, cmd, hair.indirect_view.subresource_uav); device->BindUAV(&hair.generalBuffer, 5, cmd, hair.vb_pos_raytracing.subresource_uav); + device->BindUAV(&hair.generalBuffer, 6, cmd, hair.vb_nor.subresource_uav); if (hair.indexBuffer.IsValid()) { @@ -386,13 +416,15 @@ namespace wi } if (mesh.streamoutBuffer.IsValid()) { - device->BindResource(&mesh.streamoutBuffer, 1, cmd, mesh.so_pos_nor_wind.subresource_srv); + device->BindResource(&mesh.streamoutBuffer, 1, cmd, mesh.so_pos.subresource_srv); + device->BindResource(&mesh.streamoutBuffer, 2, cmd, mesh.so_nor.subresource_srv); } else { - device->BindResource(&mesh.generalBuffer, 1, cmd, mesh.vb_pos_nor_wind.subresource_srv); + device->BindResource(&mesh.generalBuffer, 1, cmd, mesh.vb_pos_wind.subresource_srv); + device->BindResource(&mesh.generalBuffer, 2, cmd, mesh.vb_nor.subresource_srv); } - device->BindResource(&hair.vertexBuffer_length, 2, cmd); + device->BindResource(&hair.vertexBuffer_length, 3, cmd); device->Dispatch((hair.strandCount + THREADCOUNT_SIMULATEHAIR - 1) / THREADCOUNT_SIMULATEHAIR, 1, 1, cmd); @@ -406,6 +438,8 @@ namespace wi void HairParticleSystem::InitializeGPUDataIfNeeded(wi::graphics::CommandList cmd) { + if (strandCount == 0 || !generalBuffer.IsValid()) + return; if (gpu_initialized) return; GraphicsDevice* device = wi::graphics::GetDevice(); diff --git a/WickedEngine/wiHairParticle.h b/WickedEngine/wiHairParticle.h index 4321a1eac..6f6317007 100644 --- a/WickedEngine/wiHairParticle.h +++ b/WickedEngine/wiHairParticle.h @@ -23,6 +23,7 @@ namespace wi wi::graphics::GPUBuffer generalBuffer; wi::scene::MeshComponent::BufferView simulation_view; wi::scene::MeshComponent::BufferView vb_pos[2]; + wi::scene::MeshComponent::BufferView vb_nor; wi::scene::MeshComponent::BufferView vb_pos_raytracing; wi::scene::MeshComponent::BufferView vb_uvs; wi::scene::MeshComponent::BufferView ib_culled; @@ -98,6 +99,7 @@ namespace wi wi::vector indices; // it is dependent on vertex_lengths and contains triangles with non-zero lengths uint32_t layerMask = ~0u; mutable bool regenerate_frame = true; + wi::graphics::Format position_format = wi::graphics::Format::R16G16B16A16_UNORM; void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index e0d4a7a6d..32b1013d4 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -115,6 +115,10 @@ namespace wi::math { return XMFLOAT3((a.x + b.x)*0.5f, (a.y + b.y)*0.5f, (a.z + b.z)*0.5f); } + inline XMVECTOR InverseLerp(XMVECTOR value1, XMVECTOR value2, XMVECTOR pos) + { + return (pos - value1) / (value2 - value1); + } constexpr float InverseLerp(float value1, float value2, float pos) { return value2 == value1 ? 0 : ((pos - value1) / (value2 - value1)); @@ -131,6 +135,10 @@ namespace wi::math { return XMFLOAT4(InverseLerp(value1.x, value2.x, pos.x), InverseLerp(value1.y, value2.y, pos.y), InverseLerp(value1.z, value2.z, pos.z), InverseLerp(value1.w, value2.w, pos.w)); } + inline XMVECTOR Lerp(XMVECTOR value1, XMVECTOR value2, XMVECTOR amount) + { + return value1 + (value2 - value1) * amount; + } constexpr float Lerp(float value1, float value2, float amount) { return value1 + (value2 - value1) * amount; @@ -147,6 +155,18 @@ namespace wi::math { return XMFLOAT4(Lerp(a.x, b.x, i), Lerp(a.y, b.y, i), Lerp(a.z, b.z, i), Lerp(a.w, b.w, i)); } + constexpr XMFLOAT2 Lerp(const XMFLOAT2& a, const XMFLOAT2& b, const XMFLOAT2& i) + { + return XMFLOAT2(Lerp(a.x, b.x, i.x), Lerp(a.y, b.y, i.y)); + } + constexpr XMFLOAT3 Lerp(const XMFLOAT3& a, const XMFLOAT3& b, const XMFLOAT3& i) + { + return XMFLOAT3(Lerp(a.x, b.x, i.x), Lerp(a.y, b.y, i.y), Lerp(a.z, b.z, i.z)); + } + constexpr XMFLOAT4 Lerp(const XMFLOAT4& a, const XMFLOAT4& b, const XMFLOAT4& i) + { + return XMFLOAT4(Lerp(a.x, b.x, i.x), Lerp(a.y, b.y, i.y), Lerp(a.z, b.z, i.z), Lerp(a.w, b.w, i.w)); + } inline XMFLOAT4 Slerp(const XMFLOAT4& a, const XMFLOAT4& b, float i) { XMVECTOR _a = XMLoadFloat4(&a); @@ -156,12 +176,33 @@ namespace wi::math XMStoreFloat4(&retVal, result); return retVal; } + constexpr XMFLOAT2 Max(const XMFLOAT2& a, const XMFLOAT2& b) { + return XMFLOAT2(std::max(a.x, b.x), std::max(a.y, b.y)); + } constexpr XMFLOAT3 Max(const XMFLOAT3& a, const XMFLOAT3& b) { return XMFLOAT3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); } + constexpr XMFLOAT4 Max(const XMFLOAT4& a, const XMFLOAT4& b) { + return XMFLOAT4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); + } + constexpr XMFLOAT2 Min(const XMFLOAT2& a, const XMFLOAT2& b) { + return XMFLOAT2(std::min(a.x, b.x), std::min(a.y, b.y)); + } constexpr XMFLOAT3 Min(const XMFLOAT3& a, const XMFLOAT3& b) { return XMFLOAT3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); } + constexpr XMFLOAT4 Min(const XMFLOAT4& a, const XMFLOAT4& b) { + return XMFLOAT4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); + } + constexpr XMFLOAT2 Abs(const XMFLOAT2& a) { + return XMFLOAT2(std::abs(a.x), std::abs(a.y)); + } + constexpr XMFLOAT3 Abs(const XMFLOAT3& a) { + return XMFLOAT3(std::abs(a.x), std::abs(a.y), std::abs(a.z)); + } + constexpr XMFLOAT4 Abs(const XMFLOAT4& a) { + return XMFLOAT4(std::abs(a.x), std::abs(a.y), std::abs(a.z), std::abs(a.w)); + } constexpr float Clamp(float val, float min, float max) { return std::min(max, std::max(min, val)); diff --git a/WickedEngine/wiPhysics_Bullet.cpp b/WickedEngine/wiPhysics_Bullet.cpp index bab00273e..b1ed2a436 100644 --- a/WickedEngine/wiPhysics_Bullet.cpp +++ b/WickedEngine/wiPhysics_Bullet.cpp @@ -1403,24 +1403,17 @@ namespace wi::physics btVector3 aabb_max; softbody->getAabb(aabb_min, aabb_max); physicscomponent->aabb = wi::primitive::AABB(XMFLOAT3(aabb_min.x(), aabb_min.y(), aabb_min.z()), XMFLOAT3(aabb_max.x(), aabb_max.y(), aabb_max.z())); + mesh.aabb = physicscomponent->aabb; // Soft body simulation nodes will update graphics mesh: - for (size_t ind = 0; ind < physicscomponent->vertex_positions_simulation.size(); ++ind) + for (size_t ind = 0; ind < mesh.vertex_positions.size(); ++ind) { uint32_t physicsInd = physicscomponent->graphicsToPhysicsVertexMapping[ind]; btSoftBody::Node& node = softbody->m_nodes[physicsInd]; - MeshComponent::Vertex_POS& vertex = physicscomponent->vertex_positions_simulation[ind]; - vertex.pos.x = node.m_x.getX(); - vertex.pos.y = node.m_x.getY(); - vertex.pos.z = node.m_x.getZ(); - - XMFLOAT3 normal; - normal.x = -node.m_n.getX(); - normal.y = -node.m_n.getY(); - normal.z = -node.m_n.getZ(); - vertex.MakeFromParams(normal); + physicscomponent->vertex_positions_simulation[ind].FromFULL(XMFLOAT3(node.m_x.getX(), node.m_x.getY(), node.m_x.getZ())); + physicscomponent->vertex_normals_simulation[ind].FromFULL(XMFLOAT3(-node.m_n.getX(), -node.m_n.getY(), -node.m_n.getZ())); } // Update tangent vectors: @@ -1438,17 +1431,17 @@ namespace wi::physics const uint32_t i1 = mesh.indices[i + 1]; const uint32_t i2 = mesh.indices[i + 2]; - const XMFLOAT3 v0 = physicscomponent->vertex_positions_simulation[i0].pos; - const XMFLOAT3 v1 = physicscomponent->vertex_positions_simulation[i1].pos; - const XMFLOAT3 v2 = physicscomponent->vertex_positions_simulation[i2].pos; + const XMFLOAT3 v0 = physicscomponent->vertex_positions_simulation[i0].GetPOS(); + const XMFLOAT3 v1 = physicscomponent->vertex_positions_simulation[i1].GetPOS(); + const XMFLOAT3 v2 = physicscomponent->vertex_positions_simulation[i2].GetPOS(); const XMFLOAT2 u0 = mesh.vertex_uvset_0[i0]; const XMFLOAT2 u1 = mesh.vertex_uvset_0[i1]; const XMFLOAT2 u2 = mesh.vertex_uvset_0[i2]; - const XMVECTOR nor0 = physicscomponent->vertex_positions_simulation[i0].LoadNOR(); - const XMVECTOR nor1 = physicscomponent->vertex_positions_simulation[i1].LoadNOR(); - const XMVECTOR nor2 = physicscomponent->vertex_positions_simulation[i2].LoadNOR(); + const XMVECTOR nor0 = physicscomponent->vertex_normals_simulation[i0].LoadNOR(); + const XMVECTOR nor1 = physicscomponent->vertex_normals_simulation[i1].LoadNOR(); + const XMVECTOR nor2 = physicscomponent->vertex_normals_simulation[i2].LoadNOR(); const XMVECTOR facenormal = XMVector3Normalize(XMVectorAdd(XMVectorAdd(nor0, nor1), nor2)); diff --git a/WickedEngine/wiPrimitive.cpp b/WickedEngine/wiPrimitive.cpp index 9f014e677..a55cc57bf 100644 --- a/WickedEngine/wiPrimitive.cpp +++ b/WickedEngine/wiPrimitive.cpp @@ -64,6 +64,13 @@ namespace wi::primitive return sca * tra; } + XMMATRIX AABB::AABB::getUnormRemapMatrix() const + { + return + XMMatrixScaling(_max.x - _min.x, _max.y - _min.y, _max.z - _min.z) * + XMMatrixTranslation(_min.x, _min.y, _min.z) + ; + } float AABB::getArea() const { XMFLOAT3 _min = getMin(); diff --git a/WickedEngine/wiPrimitive.h b/WickedEngine/wiPrimitive.h index 6837100e8..38a9fd2bf 100644 --- a/WickedEngine/wiPrimitive.h +++ b/WickedEngine/wiPrimitive.h @@ -39,6 +39,7 @@ namespace wi::primitive XMFLOAT3 getCenter() const; XMFLOAT3 getHalfWidth() const; XMMATRIX getAsBoxMatrix() const; + XMMATRIX getUnormRemapMatrix() const; float getArea() const; float getRadius() const; INTERSECTION_TYPE intersects2D(const AABB& b) const; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 90865d7b8..e321f0cb7 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -741,10 +741,6 @@ void LoadShaders() wi::jobsystem::context ctx; wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { - inputLayouts[ILTYPE_OBJECT_DEBUG].elements = - { - { "POSITION_NORMAL_WIND", 0, MeshComponent::Vertex_POS::FORMAT, 0, InputLayout::APPEND_ALIGNED_ELEMENT, InputClassification::PER_VERTEX_DATA }, - }; LoadShader(ShaderStage::VS, shaders[VSTYPE_OBJECT_DEBUG], "objectVS_debug.cso"); }); @@ -774,11 +770,6 @@ void LoadShaders() }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { - inputLayouts[ILTYPE_RENDERLIGHTMAP].elements = - { - { "POSITION_NORMAL_WIND", 0, MeshComponent::Vertex_POS::FORMAT, 0, InputLayout::APPEND_ALIGNED_ELEMENT, InputClassification::PER_VERTEX_DATA }, - { "ATLAS", 0, MeshComponent::Vertex_TEX::FORMAT, 1, InputLayout::APPEND_ALIGNED_ELEMENT, InputClassification::PER_VERTEX_DATA }, - }; LoadShader(ShaderStage::VS, shaders[VSTYPE_RENDERLIGHTMAP], "renderlightmapVS.cso"); }); @@ -1347,7 +1338,6 @@ void LoadShaders() }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { PipelineStateDesc desc; - desc.il = &inputLayouts[ILTYPE_RENDERLIGHTMAP]; desc.vs = &shaders[VSTYPE_RENDERLIGHTMAP]; desc.ps = &shaders[PSTYPE_RENDERLIGHTMAP]; desc.rs = &rasterizers[RSTYPE_DOUBLESIDED]; @@ -1541,7 +1531,6 @@ void LoadShaders() case DEBUGRENDERING_EMITTER: desc.vs = &shaders[VSTYPE_OBJECT_DEBUG]; desc.ps = &shaders[PSTYPE_OBJECT_DEBUG]; - desc.il = &inputLayouts[ILTYPE_OBJECT_DEBUG]; desc.dss = &depthStencils[DSSTYPE_DEPTHREAD]; desc.rs = &rasterizers[RSTYPE_WIRE_DOUBLESIDED_SMOOTH]; desc.bs = &blendStates[BSTYPE_OPAQUE]; @@ -2959,7 +2948,7 @@ void RenderImpostors( vis.scene->impostor_ib_format == Format::R32_UINT ? vis.scene->impostor_ib32.offset : vis.scene->impostor_ib16.offset, cmd ); - device->BindResource(&vis.scene->impostorBuffer, 0, cmd, vis.scene->impostor_vb.subresource_srv); + device->BindResource(&vis.scene->impostorBuffer, 0, cmd, vis.scene->impostor_vb_pos.subresource_srv); device->BindResource(&vis.scene->impostorBuffer, 2, cmd, vis.scene->impostor_data.subresource_srv); device->BindResource(&vis.scene->impostorArray, 1, cmd); @@ -4235,15 +4224,28 @@ void UpdateRenderData( const SoftBodyPhysicsComponent& softbody = vis.scene->softbodies[i]; const MeshComponent* mesh = vis.scene->meshes.GetComponent(entity); - if (mesh != nullptr && mesh->streamoutBuffer.IsValid() && !softbody.vertex_positions_simulation.empty()) + if (mesh != nullptr && mesh->streamoutBuffer.IsValid() && softbody.HasVertices()) { - GraphicsDevice::GPUAllocation allocation = device->AllocateGPU(mesh->so_pos_nor_wind.size + mesh->so_tan.size, cmd); - std::memcpy(allocation.data, softbody.vertex_positions_simulation.data(), mesh->so_pos_nor_wind.size); - device->CopyBuffer(&mesh->streamoutBuffer, mesh->so_pos_nor_wind.offset, &allocation.buffer, allocation.offset, mesh->so_pos_nor_wind.size, cmd); + GraphicsDevice::GPUAllocation allocation = device->AllocateGPU(mesh->so_pos.size + mesh->so_nor.size + mesh->so_tan.size, cmd); + uint8_t* dst = (uint8_t*)allocation.data; + uint64_t offset = allocation.offset; + std::memcpy(dst, softbody.vertex_positions_simulation.data(), mesh->so_pos.size); + device->CopyBuffer(&mesh->streamoutBuffer, mesh->so_pos.offset, &allocation.buffer, offset, mesh->so_pos.size, cmd); + dst += mesh->so_pos.size; + offset += mesh->so_pos.size; + if (!softbody.vertex_normals_simulation.empty()) + { + std::memcpy(dst, softbody.vertex_normals_simulation.data(), mesh->so_nor.size); + device->CopyBuffer(&mesh->streamoutBuffer, mesh->so_nor.offset, &allocation.buffer, offset, mesh->so_nor.size, cmd); + dst += mesh->so_nor.size; + offset += mesh->so_nor.size; + } if (!softbody.vertex_tangents_simulation.empty()) { - std::memcpy((uint8_t*)allocation.data + mesh->so_pos_nor_wind.size, softbody.vertex_tangents_simulation.data(), mesh->so_tan.size); - device->CopyBuffer(&mesh->streamoutBuffer, mesh->so_tan.offset, &allocation.buffer, allocation.offset + mesh->so_pos_nor_wind.size, mesh->so_tan.size, cmd); + std::memcpy(dst, softbody.vertex_tangents_simulation.data(), mesh->so_tan.size); + device->CopyBuffer(&mesh->streamoutBuffer, mesh->so_tan.offset, &allocation.buffer, offset, mesh->so_tan.size, cmd); + dst += mesh->so_tan.size; + offset += mesh->so_tan.size; } barrier_stack.push_back(GPUBarrier::Buffer(&mesh->streamoutBuffer, ResourceState::COPY_DST, ResourceState::SHADER_RESOURCE)); } @@ -4306,10 +4308,11 @@ void UpdateRenderData( } SkinningPushConstants push; - push.vertexCount = (uint)mesh.vertex_positions.size(); - push.vb_pos_nor_wind = mesh.vb_pos_nor_wind.descriptor_srv; + push.vb_pos_wind = mesh.vb_pos_wind.descriptor_srv; + push.vb_nor = mesh.vb_nor.descriptor_srv; push.vb_tan = mesh.vb_tan.descriptor_srv; - push.so_pos_nor_wind = mesh.so_pos_nor_wind.descriptor_uav; + push.so_pos = mesh.so_pos.descriptor_uav; + push.so_nor = mesh.so_nor.descriptor_uav; push.so_tan = mesh.so_tan.descriptor_uav; push.skinningbuffer_index = descriptor_skinningbuffer; const ArmatureComponent* armature = vis.scene->armatures.GetComponent(mesh.armatureID); @@ -4334,6 +4337,17 @@ void UpdateRenderData( push.morph_offset = ~0u; push.morphvb_index = -1; } + if (IsFormatUnorm(mesh.position_format)) + { + push.aabb_min = mesh.aabb._min; + push.aabb_max = mesh.aabb._max; + } + else + { + push.aabb_min = {}; + push.aabb_max = {}; + } + push.vertexCount = (uint)mesh.vertex_positions.size(); device->PushConstants(&push, sizeof(push), cmd); device->Dispatch(((uint32_t)mesh.vertex_positions.size() + 63) / 64, 1, 1, cmd); @@ -4404,9 +4418,10 @@ void UpdateRenderData( device->BindComputeShader(&shaders[CSTYPE_IMPOSTOR_PREPARE], cmd); device->BindUAV(&vis.scene->impostorBuffer, 0, cmd, vis.scene->impostor_ib_format == Format::R32_UINT ? vis.scene->impostor_ib32.subresource_uav : vis.scene->impostor_ib16.subresource_uav); - device->BindUAV(&vis.scene->impostorBuffer, 1, cmd, vis.scene->impostor_vb.subresource_uav); - device->BindUAV(&vis.scene->impostorBuffer, 2, cmd, vis.scene->impostor_data.subresource_uav); - device->BindUAV(&vis.scene->impostorBuffer, 3, cmd, vis.scene->impostor_indirect.subresource_uav); + device->BindUAV(&vis.scene->impostorBuffer, 1, cmd, vis.scene->impostor_vb_pos.subresource_uav); + device->BindUAV(&vis.scene->impostorBuffer, 2, cmd, vis.scene->impostor_vb_nor.subresource_uav); + device->BindUAV(&vis.scene->impostorBuffer, 3, cmd, vis.scene->impostor_data.subresource_uav); + device->BindUAV(&vis.scene->impostorBuffer, 4, cmd, vis.scene->impostor_indirect.subresource_uav); uint object_count = (uint)vis.scene->objects.GetCount(); device->PushConstants(&object_count, sizeof(object_count), cmd); @@ -7134,16 +7149,9 @@ void DrawDebugWorld( { // Draw mesh wireframe: device->BindPipelineState(&PSO_debug[DEBUGRENDERING_EMITTER], cmd); - const GPUBuffer* vbs[] = { - mesh->streamoutBuffer.IsValid() ? &mesh->streamoutBuffer : &mesh->generalBuffer, - }; - const uint32_t strides[] = { - sizeof(MeshComponent::Vertex_POS), - }; - const uint64_t offsets[] = { - mesh->so_pos_nor_wind.IsValid() ? mesh->so_pos_nor_wind.offset : mesh->vb_pos_nor_wind.offset, - }; - device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + DebugObjectPushConstants push; + push.vb_pos_wind = mesh->so_pos.IsValid() ? mesh->so_pos.descriptor_srv : mesh->vb_pos_wind.descriptor_srv; + device->PushConstants(&push, sizeof(push), cmd); device->BindIndexBuffer(&mesh->generalBuffer, mesh->GetIndexFormat(), mesh->ib.offset, cmd); device->DrawIndexed((uint32_t)mesh->indices.size(), 0, 0, cmd); @@ -8321,9 +8329,16 @@ void RefreshImpostors(const Scene& scene, CommandList cmd) impostorcamera.TransformCamera(camera_transform); impostorcamera.UpdateCamera(); + if (IsFormatUnorm(mesh.position_format)) + { + XMMATRIX VP = impostorcamera.GetViewProjection(); + VP = mesh.aabb.getUnormRemapMatrix() * VP; + XMStoreFloat4x4(&impostorcamera.VP, VP); + } + BindCameraCB(impostorcamera, impostorcamera, impostorcamera, cmd); - int slice = (int)(impostor.textureIndex * impostorCaptureAngles * 3 + i * 3); + int slice = int(impostor.textureIndex * impostorCaptureAngles * 3 + i * 3); const RenderPassImage rp[] = { RenderPassImage::RenderTarget( @@ -9665,26 +9680,17 @@ void RefreshLightmaps(const Scene& scene, CommandList cmd) vp.height = (float)desc.height; device->BindViewports(1, &vp, cmd); - MiscCB misccb; - misccb.g_xTransform = scene.matrix_objects[objectIndex]; + device->BindPipelineState(&PSO_renderlightmap, cmd); - device->BindDynamicConstantBuffer(misccb, CB_GETBINDSLOT(MiscCB), cmd); - - const GPUBuffer* vbs[] = { - &mesh.generalBuffer, - &mesh.generalBuffer, - }; - uint32_t strides[] = { - sizeof(MeshComponent::Vertex_POS), - sizeof(MeshComponent::Vertex_TEX), - }; - uint64_t offsets[] = { - mesh.vb_pos_nor_wind.offset, - mesh.vb_atl.offset, - }; - device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); device->BindIndexBuffer(&mesh.generalBuffer, mesh.GetIndexFormat(), mesh.ib.offset, cmd); + LightmapPushConstants push; + push.vb_pos_wind = mesh.vb_pos_wind.descriptor_srv; + push.vb_nor = mesh.vb_nor.descriptor_srv; + push.vb_atl = mesh.vb_atl.descriptor_srv; + push.instanceIndex = objectIndex; + device->PushConstants(&push, sizeof(push), cmd); + RaytracingCB cb; cb.xTraceResolution.x = desc.width; cb.xTraceResolution.y = desc.height; @@ -9702,9 +9708,7 @@ void RefreshLightmaps(const Scene& scene, CommandList cmd) cb.xTraceSampleIndex = object.lightmapIterationCount; device->BindDynamicConstantBuffer(cb, CB_GETBINDSLOT(RaytracingCB), cmd); - device->BindPipelineState(&PSO_renderlightmap, cmd); - - device->DrawIndexedInstanced((uint32_t)mesh.indices.size(), 1, 0, 0, 0, cmd); + device->DrawIndexed((uint32_t)mesh.indices.size(), 0, 0, cmd); object.lightmapIterationCount++; device->RenderPassEnd(cmd); diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index bab2236b7..c434f1c36 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -693,12 +693,17 @@ namespace wi::scene desc.bind_flags = BindFlag::INDEX_BUFFER | BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS; desc.misc_flags = ResourceMiscFlag::BUFFER_RAW | ResourceMiscFlag::TYPED_FORMAT_CASTING | ResourceMiscFlag::INDIRECT_ARGS | ResourceMiscFlag::NO_DEFAULT_DESCRIPTORS; - const uint64_t alignment = device->GetMinOffsetAlignment(&desc); + const uint64_t alignment = + device->GetMinOffsetAlignment(&desc) * + sizeof(IndirectDrawArgsIndexedInstanced) * // additional alignment + sizeof(MeshComponent::Vertex_POS32) // additional alignment + ; desc.size = - AlignTo(AlignTo(sizeof(IndirectDrawArgsIndexedInstanced), alignment), sizeof(IndirectDrawArgsIndexedInstanced)) + // indirect args, additional structured buffer alignment + AlignTo(sizeof(IndirectDrawArgsIndexedInstanced), alignment) + // indirect args AlignTo(allocated_impostor_capacity * sizeof(uint) * 6, alignment) + // indices (must overestimate here for 32-bit indices, because we create 16 bit and 32 bit descriptors) - AlignTo(allocated_impostor_capacity * sizeof(MeshComponent::Vertex_POS) * 4, alignment) + // vertices + AlignTo(allocated_impostor_capacity * sizeof(MeshComponent::Vertex_POS32) * 4, alignment) + // vertices + AlignTo(allocated_impostor_capacity * sizeof(MeshComponent::Vertex_NOR) * 4, alignment) + // vertices AlignTo(allocated_impostor_capacity * sizeof(uint2), alignment) // impostordata ; device->CreateBuffer(&desc, nullptr, &impostorBuffer); @@ -733,13 +738,22 @@ namespace wi::scene impostor_ib16.descriptor_uav = device->GetDescriptorIndex(&impostorBuffer, SubresourceType::UAV, impostor_ib16.subresource_uav); buffer_offset = AlignTo(buffer_offset, alignment); - impostor_vb.offset = buffer_offset; - impostor_vb.size = allocated_impostor_capacity * sizeof(MeshComponent::Vertex_POS) * 4; - impostor_vb.subresource_srv = device->CreateSubresource(&impostorBuffer, SubresourceType::SRV, impostor_vb.offset, impostor_vb.size, &MeshComponent::Vertex_POS::FORMAT); - impostor_vb.subresource_uav = device->CreateSubresource(&impostorBuffer, SubresourceType::UAV, impostor_vb.offset, impostor_vb.size, &MeshComponent::Vertex_POS::FORMAT); - impostor_vb.descriptor_srv = device->GetDescriptorIndex(&impostorBuffer, SubresourceType::SRV, impostor_vb.subresource_srv); - impostor_vb.descriptor_uav = device->GetDescriptorIndex(&impostorBuffer, SubresourceType::UAV, impostor_vb.subresource_uav); - buffer_offset += impostor_vb.size; + impostor_vb_pos.offset = buffer_offset; + impostor_vb_pos.size = allocated_impostor_capacity * sizeof(MeshComponent::Vertex_POS32) * 4; + impostor_vb_pos.subresource_srv = device->CreateSubresource(&impostorBuffer, SubresourceType::SRV, impostor_vb_pos.offset, impostor_vb_pos.size, &MeshComponent::Vertex_POS32::FORMAT); + impostor_vb_pos.subresource_uav = device->CreateSubresource(&impostorBuffer, SubresourceType::UAV, impostor_vb_pos.offset, impostor_vb_pos.size); // can't have RGB32F format for UAV! + impostor_vb_pos.descriptor_srv = device->GetDescriptorIndex(&impostorBuffer, SubresourceType::SRV, impostor_vb_pos.subresource_srv); + impostor_vb_pos.descriptor_uav = device->GetDescriptorIndex(&impostorBuffer, SubresourceType::UAV, impostor_vb_pos.subresource_uav); + buffer_offset += impostor_vb_pos.size; + + buffer_offset = AlignTo(buffer_offset, alignment); + impostor_vb_nor.offset = buffer_offset; + impostor_vb_nor.size = allocated_impostor_capacity * sizeof(MeshComponent::Vertex_NOR) * 4; + impostor_vb_nor.subresource_srv = device->CreateSubresource(&impostorBuffer, SubresourceType::SRV, impostor_vb_nor.offset, impostor_vb_nor.size, &MeshComponent::Vertex_NOR::FORMAT); + impostor_vb_nor.subresource_uav = device->CreateSubresource(&impostorBuffer, SubresourceType::UAV, impostor_vb_nor.offset, impostor_vb_nor.size, &MeshComponent::Vertex_NOR::FORMAT); + impostor_vb_nor.descriptor_srv = device->GetDescriptorIndex(&impostorBuffer, SubresourceType::SRV, impostor_vb_nor.subresource_srv); + impostor_vb_nor.descriptor_uav = device->GetDescriptorIndex(&impostorBuffer, SubresourceType::UAV, impostor_vb_nor.subresource_uav); + buffer_offset += impostor_vb_nor.size; buffer_offset = AlignTo(buffer_offset, alignment); impostor_data.offset = buffer_offset; @@ -3376,9 +3390,9 @@ namespace wi::scene } } - if (mesh.so_pos_nor_wind.IsValid() && mesh.so_pre.IsValid()) + if (mesh.so_pos.IsValid() && mesh.so_pre.IsValid()) { - std::swap(mesh.so_pos_nor_wind, mesh.so_pre); + std::swap(mesh.so_pos, mesh.so_pre); } mesh._flags &= ~MeshComponent::TLAS_FORCE_DOUBLE_SIDED; @@ -3408,13 +3422,21 @@ namespace wi::scene ShaderGeometry geometry; geometry.init(); geometry.ib = mesh.ib.descriptor_srv; - if (mesh.so_pos_nor_wind.IsValid()) + if (mesh.so_pos.IsValid()) { - geometry.vb_pos_nor_wind = mesh.so_pos_nor_wind.descriptor_srv; + geometry.vb_pos_wind = mesh.so_pos.descriptor_srv; } else { - geometry.vb_pos_nor_wind = mesh.vb_pos_nor_wind.descriptor_srv; + geometry.vb_pos_wind = mesh.vb_pos_wind.descriptor_srv; + } + if (mesh.so_nor.IsValid()) + { + geometry.vb_nor = mesh.so_nor.descriptor_srv; + } + else + { + geometry.vb_nor = mesh.vb_nor.descriptor_srv; } if (mesh.so_tan.IsValid()) { @@ -3431,6 +3453,8 @@ namespace wi::scene geometry.aabb_min = mesh.aabb._min; geometry.aabb_max = mesh.aabb._max; geometry.tessellation_factor = mesh.tessellationFactor; + geometry.uv_range_min = mesh.uv_range_min; + geometry.uv_range_max = mesh.uv_range_max; const ImpostorComponent* impostor = impostors.GetComponent(entity); if (impostor != nullptr && impostor->textureIndex >= 0) @@ -3508,7 +3532,7 @@ namespace wi::scene { mesh.BLAS_state = MeshComponent::BLAS_STATE_NEEDS_REBUILD; geometry.triangles.vertex_buffer = mesh.streamoutBuffer; - geometry.triangles.vertex_byte_offset = mesh.so_pos_nor_wind.offset; + geometry.triangles.vertex_byte_offset = mesh.so_pos.offset; } if (material.IsDoubleSided()) { @@ -3714,7 +3738,8 @@ namespace wi::scene geometry.meshletCount = triangle_count_to_meshlet_count(uint32_t(objects.GetCount()) * 2); geometry.meshletOffset = 0; // local meshlet offset geometry.ib = impostor_ib_format == Format::R32_UINT ? impostor_ib32.descriptor_srv : impostor_ib16.descriptor_srv; - geometry.vb_pos_nor_wind = impostor_vb.descriptor_srv; + geometry.vb_pos_wind = impostor_vb_pos.descriptor_srv; + geometry.vb_nor = impostor_vb_nor.descriptor_srv; geometry.materialIndex = impostorMaterialOffset; std::memcpy(geometryArrayMapped + impostorGeometryOffset, &geometry, sizeof(geometry)); @@ -3910,21 +3935,30 @@ namespace wi::scene object.sort_bits = sort_bits.value; - // Create GPU instance data: - GraphicsDevice* device = wi::graphics::GetDevice(); - ShaderMeshInstance inst; - inst.init(); - XMFLOAT4X4& worldMatrix = matrix_objects[args.jobIndex]; - matrix_objects_prev[args.jobIndex] = worldMatrix; - inst.transformPrev.Create(worldMatrix); - XMStoreFloat4x4(&worldMatrix, W); - inst.transform.Create(worldMatrix); - // Correction matrix for mesh normals with non-uniform object scaling: XMMATRIX worldMatrixInverseTranspose = XMMatrixTranspose(XMMatrixInverse(nullptr, W)); XMFLOAT4X4 transformIT; XMStoreFloat4x4(&transformIT, worldMatrixInverseTranspose); + // Create GPU instance data: + GraphicsDevice* device = wi::graphics::GetDevice(); + ShaderMeshInstance inst; + inst.init(); + XMFLOAT4X4 worldMatrixPrev = matrix_objects[args.jobIndex]; + matrix_objects_prev[args.jobIndex] = worldMatrixPrev; + XMStoreFloat4x4(matrix_objects.data() + args.jobIndex, W); + XMFLOAT4X4 worldMatrix = matrix_objects[args.jobIndex]; + + if (IsFormatUnorm(mesh.position_format) && !mesh.so_pos.IsValid()) + { + // The UNORM correction is only done for the GPU data! + XMMATRIX R = mesh.aabb.getUnormRemapMatrix(); + XMStoreFloat4x4(&worldMatrix, R * W); + XMStoreFloat4x4(&worldMatrixPrev, R * XMLoadFloat4x4(&worldMatrixPrev)); + } + inst.transform.Create(worldMatrix); + inst.transformPrev.Create(worldMatrixPrev); + inst.transformInverseTranspose.Create(transformIT); if (object.lightmap.IsValid()) { @@ -4301,12 +4335,15 @@ namespace wi::scene geometry.indexOffset = 0; geometry.materialIndex = (uint)materials.GetIndex(entity); geometry.ib = device->GetDescriptorIndex(&hair.primitiveBuffer, SubresourceType::SRV); - geometry.vb_pos_nor_wind = hair.vb_pos[0].descriptor_srv; + geometry.vb_pos_wind = hair.vb_pos[0].descriptor_srv; + geometry.vb_nor = hair.vb_nor.descriptor_srv; geometry.vb_pre = hair.vb_pos[1].descriptor_srv; geometry.vb_uvs = hair.vb_uvs.descriptor_srv; geometry.flags = SHADERMESH_FLAG_DOUBLE_SIDED | SHADERMESH_FLAG_HAIRPARTICLE; geometry.meshletOffset = 0; geometry.meshletCount = meshletCount; + geometry.aabb_min = hair.aabb._min; + geometry.aabb_max = hair.aabb._max; size_t geometryAllocation = geometryAllocator.fetch_add(1); std::memcpy(geometryArrayMapped + geometryAllocation, &geometry, sizeof(geometry)); @@ -4325,6 +4362,11 @@ namespace wi::scene inst.baseGeometryCount = inst.geometryCount; inst.meshletOffset = meshletOffset; + XMFLOAT4X4 remapMatrix; + XMStoreFloat4x4(&remapMatrix, hair.aabb.getUnormRemapMatrix()); + inst.transform.Create(remapMatrix); + inst.transformPrev = inst.transform; + const size_t instanceIndex = objects.GetCount() + args.jobIndex; std::memcpy(instanceArrayMapped + instanceIndex, &inst, sizeof(inst)); @@ -4342,7 +4384,7 @@ namespace wi::scene { for (int j = 0; j < arraysize(instance.transform[i]); ++j) { - instance.transform[i][j] = wi::math::IDENTITY_MATRIX.m[j][i]; + instance.transform[i][j] = remapMatrix.m[j][i]; } } instance.instance_id = (uint32_t)instanceIndex; @@ -4398,7 +4440,8 @@ namespace wi::scene geometry.indexOffset = 0; geometry.materialIndex = (uint)materials.GetIndex(entity); geometry.ib = device->GetDescriptorIndex(&emitter.primitiveBuffer, SubresourceType::SRV); - geometry.vb_pos_nor_wind = emitter.vb_pos.descriptor_srv; + geometry.vb_pos_wind = emitter.vb_pos.descriptor_srv; + geometry.vb_nor = emitter.vb_nor.descriptor_srv; geometry.vb_uvs = emitter.vb_uvs.descriptor_srv; geometry.vb_col = emitter.vb_col.descriptor_srv; geometry.flags = SHADERMESH_FLAG_DOUBLE_SIDED | SHADERMESH_FLAG_EMITTEDPARTICLE; @@ -4547,7 +4590,8 @@ namespace wi::scene geometry.indexOffset = 0; geometry.materialIndex = rainMaterialOffset; geometry.ib = device->GetDescriptorIndex(&rainEmitter.primitiveBuffer, SubresourceType::SRV); - geometry.vb_pos_nor_wind = rainEmitter.vb_pos.descriptor_srv; + geometry.vb_pos_wind = rainEmitter.vb_pos.descriptor_srv; + geometry.vb_nor = rainEmitter.vb_nor.descriptor_srv; geometry.vb_uvs = rainEmitter.vb_uvs.descriptor_srv; geometry.vb_col = rainEmitter.vb_col.descriptor_srv; geometry.flags = SHADERMESH_FLAG_DOUBLE_SIDED | SHADERMESH_FLAG_EMITTEDPARTICLE; @@ -4806,6 +4850,8 @@ namespace wi::scene const XMVECTOR rayOrigin_local = XMVector3Transform(rayOrigin, objectMat_Inverse); const XMVECTOR rayDirection_local = XMVector3Normalize(XMVector3TransformNormal(rayDirection, objectMat_Inverse)); const ArmatureComponent* armature = mesh->IsSkinned() ? armatures.GetComponent(mesh->armatureID) : nullptr; + const XMVECTOR aabb_min = XMLoadFloat3(&mesh->aabb._min); + const XMVECTOR aabb_max = XMLoadFloat3(&mesh->aabb._max); auto intersect_triangle = [&](uint32_t subsetIndex, uint32_t indexOffset, uint32_t triangleIndex) { @@ -4817,7 +4863,7 @@ namespace wi::scene XMVECTOR p1; XMVECTOR p2; - const bool softbody_active = softbody != nullptr && !softbody->vertex_positions_simulation.empty(); + const bool softbody_active = softbody != nullptr && softbody->HasVertices(); if (softbody_active) { p0 = softbody->vertex_positions_simulation[i0].LoadPOS(); @@ -5000,6 +5046,8 @@ namespace wi::scene const XMMATRIX objectMatPrev = XMLoadFloat4x4(&matrix_objects_prev[objectIndex]); const XMMATRIX objectMatInverse = XMMatrixInverse(nullptr, objectMat); const ArmatureComponent* armature = mesh->IsSkinned() ? armatures.GetComponent(mesh->armatureID) : nullptr; + const XMVECTOR aabb_min = XMLoadFloat3(&mesh->aabb._min); + const XMVECTOR aabb_max = XMLoadFloat3(&mesh->aabb._max); auto intersect_triangle = [&](uint32_t subsetIndex, uint32_t indexOffset, uint32_t triangleIndex) { @@ -5011,7 +5059,7 @@ namespace wi::scene XMVECTOR p1; XMVECTOR p2; - const bool softbody_active = softbody != nullptr && !softbody->vertex_positions_simulation.empty(); + const bool softbody_active = softbody != nullptr && softbody->HasVertices(); if (softbody_active) { p0 = softbody->vertex_positions_simulation[i0].LoadPOS(); @@ -5282,6 +5330,8 @@ namespace wi::scene const XMMATRIX objectMatPrev = XMLoadFloat4x4(&matrix_objects_prev[objectIndex]); const ArmatureComponent* armature = mesh->IsSkinned() ? armatures.GetComponent(mesh->armatureID) : nullptr; const XMMATRIX objectMat_Inverse = XMMatrixInverse(nullptr, objectMat); + const XMVECTOR aabb_min = XMLoadFloat3(&mesh->aabb._min); + const XMVECTOR aabb_max = XMLoadFloat3(&mesh->aabb._max); auto intersect_triangle = [&](uint32_t subsetIndex, uint32_t indexOffset, uint32_t triangleIndex) { @@ -5293,7 +5343,7 @@ namespace wi::scene XMVECTOR p1; XMVECTOR p2; - const bool softbody_active = softbody != nullptr && !softbody->vertex_positions_simulation.empty(); + const bool softbody_active = softbody != nullptr && softbody->HasVertices(); if (softbody_active) { p0 = softbody->vertex_positions_simulation[i0].LoadPOS(); diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 20b5c44ff..ca40a3446 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -228,7 +228,8 @@ namespace wi::scene uint32_t allocated_impostor_capacity = 0; MeshComponent::BufferView impostor_ib32; MeshComponent::BufferView impostor_ib16; - MeshComponent::BufferView impostor_vb; + MeshComponent::BufferView impostor_vb_pos; + MeshComponent::BufferView impostor_vb_nor; MeshComponent::BufferView impostor_data; MeshComponent::BufferView impostor_indirect; wi::graphics::Format impostor_ib_format = wi::graphics::Format::R32_UINT; diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index c2e6fce37..3c1902c26 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -460,13 +460,15 @@ namespace wi::scene generalBuffer = {}; streamoutBuffer = {}; ib = {}; - vb_pos_nor_wind = {}; + vb_pos_wind = {}; + vb_nor = {}; vb_tan = {}; vb_uvs = {}; vb_atl = {}; vb_col = {}; vb_bon = {}; - so_pos_nor_wind = {}; + so_pos = {}; + so_nor = {}; so_tan = {}; so_pre = {}; BLASes.clear(); @@ -562,6 +564,108 @@ namespace wi::scene const size_t uv_count = std::max(vertex_uvset_0.size(), vertex_uvset_1.size()); + // Bounds computation: + XMFLOAT3 _min = XMFLOAT3(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()); + XMFLOAT3 _max = XMFLOAT3(std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()); + for (size_t i = 0; i < vertex_positions.size(); ++i) + { + const XMFLOAT3& pos = vertex_positions[i]; + _min = wi::math::Min(_min, pos); + _max = wi::math::Max(_max, pos); + } + aabb = AABB(_min, _max); + + if (IsQuantizedPositionsDisabled()) + { + position_format = vertex_windweights.empty() ? Vertex_POS32::FORMAT : Vertex_POS32W::FORMAT; + } + else + { + // Determine minimum precision for positions: + const float target_precision = 1.0f / 1000.0f; // millimeter + position_format = Vertex_POS10::FORMAT; + for (size_t i = 0; i < vertex_positions.size(); ++i) + { + const XMFLOAT3& pos = vertex_positions[i]; + const uint8_t wind = vertex_windweights.empty() ? 0xFF : vertex_windweights[i]; + if (position_format == Vertex_POS10::FORMAT) + { + Vertex_POS10 v; + v.FromFULL(aabb, pos, wind); + XMFLOAT3 p = v.GetPOS(aabb); + if ( + std::abs(p.x - pos.x) <= target_precision && + std::abs(p.y - pos.y) <= target_precision && + std::abs(p.z - pos.z) <= target_precision && + wind == v.GetWind() + ) + { + // success, continue to next vertex with 8 bits + continue; + } + position_format = Vertex_POS16::FORMAT; // failed, increase to 16 bits + } + if (position_format == Vertex_POS16::FORMAT) + { + Vertex_POS16 v; + v.FromFULL(aabb, pos, wind); + XMFLOAT3 p = v.GetPOS(aabb); + if ( + std::abs(p.x - pos.x) <= target_precision && + std::abs(p.y - pos.y) <= target_precision && + std::abs(p.z - pos.z) <= target_precision && + wind == v.GetWind() + ) + { + // success, continue to next vertex with 16 bits + continue; + } + position_format = vertex_windweights.empty() ? Vertex_POS32::FORMAT : Vertex_POS32W::FORMAT; // failed, increase to 32 bits + break; // since 32 bit is the max, we can bail out + } + } + + if (IsFormatUnorm(position_format)) + { + // This is done to avoid 0 scaling on any axis of the UNORM remap matrix of the AABB + // It specifically solves a problem with hardware raytracing which treats AABB with zero axis as invisible + if (aabb._max.x - aabb._min.x < std::numeric_limits::epsilon()) + { + aabb._max.x += std::numeric_limits::epsilon(); + aabb._min.x -= std::numeric_limits::epsilon(); + } + if (aabb._max.y - aabb._min.y < std::numeric_limits::epsilon()) + { + aabb._max.y += std::numeric_limits::epsilon(); + aabb._min.y -= std::numeric_limits::epsilon(); + } + if (aabb._max.z - aabb._min.z < std::numeric_limits::epsilon()) + { + aabb._max.z += std::numeric_limits::epsilon(); + aabb._min.z -= std::numeric_limits::epsilon(); + } + } + } + + // Determine UV range for normalization: + if (!vertex_uvset_0.empty() || !vertex_uvset_1.empty()) + { + const XMFLOAT2* uv0_stream = vertex_uvset_0.empty() ? vertex_uvset_1.data() : vertex_uvset_0.data(); + const XMFLOAT2* uv1_stream = vertex_uvset_1.empty() ? vertex_uvset_0.data() : vertex_uvset_1.data(); + + uv_range_min = XMFLOAT2(std::numeric_limits::max(), std::numeric_limits::max()); + uv_range_max = XMFLOAT2(std::numeric_limits::lowest(), std::numeric_limits::lowest()); + for (size_t i = 0; i < uv_count; ++i) + { + uv_range_max = wi::math::Max(uv_range_max, uv0_stream[i]); + uv_range_max = wi::math::Max(uv_range_max, uv1_stream[i]); + uv_range_min = wi::math::Min(uv_range_min, uv0_stream[i]); + uv_range_min = wi::math::Min(uv_range_min, uv1_stream[i]); + } + } + + const size_t position_stride = GetFormatStride(position_format); + GPUBufferDesc bd; if (device->CheckCapability(GraphicsDeviceCapability::CACHE_COHERENT_UMA)) { @@ -580,8 +684,9 @@ namespace wi::scene } const uint64_t alignment = device->GetMinOffsetAlignment(&bd); bd.size = + AlignTo(vertex_positions.size() * position_stride, alignment) + // position will be first to have 0 offset for flexible alignment! AlignTo(indices.size() * GetIndexStride(), alignment) + - AlignTo(vertex_positions.size() * sizeof(Vertex_POS), alignment) + + AlignTo(vertex_normals.size() * sizeof(Vertex_NOR), alignment) + AlignTo(vertex_tangents.size() * sizeof(Vertex_TAN), alignment) + AlignTo(uv_count * sizeof(Vertex_UVS), alignment) + AlignTo(vertex_atlas.size() * sizeof(Vertex_TEX), alignment) + @@ -607,6 +712,78 @@ namespace wi::scene uint8_t* buffer_data = (uint8_t*)dest; uint64_t buffer_offset = 0ull; + // vertexBuffer - POSITION + WIND: + switch (position_format) + { + case Vertex_POS10::FORMAT: + { + vb_pos_wind.offset = buffer_offset; + vb_pos_wind.size = vertex_positions.size() * sizeof(Vertex_POS10); + Vertex_POS10* vertices = (Vertex_POS10*)(buffer_data + buffer_offset); + buffer_offset += AlignTo(vb_pos_wind.size, alignment); + for (size_t i = 0; i < vertex_positions.size(); ++i) + { + XMFLOAT3 pos = vertex_positions[i]; + const uint8_t wind = vertex_windweights.empty() ? 0xFF : vertex_windweights[i]; + Vertex_POS10 vert; + vert.FromFULL(aabb, pos, wind); + std::memcpy(vertices + i, &vert, sizeof(vert)); + } + } + break; + case Vertex_POS16::FORMAT: + { + vb_pos_wind.offset = buffer_offset; + vb_pos_wind.size = vertex_positions.size() * sizeof(Vertex_POS16); + Vertex_POS16* vertices = (Vertex_POS16*)(buffer_data + buffer_offset); + buffer_offset += AlignTo(vb_pos_wind.size, alignment); + for (size_t i = 0; i < vertex_positions.size(); ++i) + { + XMFLOAT3 pos = vertex_positions[i]; + const uint8_t wind = vertex_windweights.empty() ? 0xFF : vertex_windweights[i]; + Vertex_POS16 vert; + vert.FromFULL(aabb, pos, wind); + std::memcpy(vertices + i, &vert, sizeof(vert)); + } + } + break; + case Vertex_POS32::FORMAT: + { + vb_pos_wind.offset = buffer_offset; + vb_pos_wind.size = vertex_positions.size() * sizeof(Vertex_POS32); + Vertex_POS32* vertices = (Vertex_POS32*)(buffer_data + buffer_offset); + buffer_offset += AlignTo(vb_pos_wind.size, alignment); + for (size_t i = 0; i < vertex_positions.size(); ++i) + { + const XMFLOAT3& pos = vertex_positions[i]; + const uint8_t wind = vertex_windweights.empty() ? 0xFF : vertex_windweights[i]; + Vertex_POS32 vert; + vert.FromFULL(pos); + std::memcpy(vertices + i, &vert, sizeof(vert)); + } + } + break; + case Vertex_POS32W::FORMAT: + { + vb_pos_wind.offset = buffer_offset; + vb_pos_wind.size = vertex_positions.size() * sizeof(Vertex_POS32W); + Vertex_POS32W* vertices = (Vertex_POS32W*)(buffer_data + buffer_offset); + buffer_offset += AlignTo(vb_pos_wind.size, alignment); + for (size_t i = 0; i < vertex_positions.size(); ++i) + { + const XMFLOAT3& pos = vertex_positions[i]; + const uint8_t wind = vertex_windweights.empty() ? 0xFF : vertex_windweights[i]; + Vertex_POS32W vert; + vert.FromFULL(pos, wind); + std::memcpy(vertices + i, &vert, sizeof(vert)); + } + } + break; + default: + assert(0); + break; + } + // Create index buffer GPU data: if (GetIndexFormat() == IndexBufferFormat::UINT32) { @@ -628,32 +805,23 @@ namespace wi::scene } } - XMFLOAT3 _min = XMFLOAT3(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()); - XMFLOAT3 _max = XMFLOAT3(std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()); - - // vertexBuffer - POSITION + NORMAL + WIND: + // vertexBuffer - NORMALS: + if (!vertex_normals.empty()) { - vb_pos_nor_wind.offset = buffer_offset; - vb_pos_nor_wind.size = vertex_positions.size() * sizeof(Vertex_POS); - Vertex_POS* vertices = (Vertex_POS*)(buffer_data + buffer_offset); - buffer_offset += AlignTo(vb_pos_nor_wind.size, alignment); - for (size_t i = 0; i < vertex_positions.size(); ++i) + vb_nor.offset = buffer_offset; + vb_nor.size = vertex_normals.size() * sizeof(Vertex_NOR); + Vertex_NOR* vertices = (Vertex_NOR*)(buffer_data + buffer_offset); + buffer_offset += AlignTo(vb_nor.size, alignment); + for (size_t i = 0; i < vertex_normals.size(); ++i) { - const XMFLOAT3& pos = vertex_positions[i]; XMFLOAT3 nor = vertex_normals.empty() ? XMFLOAT3(1, 1, 1) : vertex_normals[i]; XMStoreFloat3(&nor, XMVector3Normalize(XMLoadFloat3(&nor))); - const uint8_t wind = vertex_windweights.empty() ? 0xFF : vertex_windweights[i]; - Vertex_POS vert; - vert.FromFULL(pos, nor, wind); + Vertex_NOR vert; + vert.FromFULL(nor); std::memcpy(vertices + i, &vert, sizeof(vert)); - - _min = wi::math::Min(_min, pos); - _max = wi::math::Max(_max, pos); } } - aabb = AABB(_min, _max); - // vertexBuffer - TANGENTS if (!vertex_tangents.empty()) { @@ -682,8 +850,8 @@ namespace wi::scene for (size_t i = 0; i < uv_count; ++i) { Vertex_UVS vert; - vert.uv0.FromFULL(uv0_stream[i]); - vert.uv1.FromFULL(uv1_stream[i]); + vert.uv0.FromFULL(uv0_stream[i], uv_range_min, uv_range_max); + vert.uv1.FromFULL(uv1_stream[i], uv_range_min, uv_range_max); std::memcpy(vertices + i, &vert, sizeof(vert)); } } @@ -812,10 +980,15 @@ namespace wi::scene ib.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, ib.offset, ib.size, &ib_format); ib.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, ib.subresource_srv); - assert(vb_pos_nor_wind.IsValid()); - vb_pos_nor_wind.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos_nor_wind.offset, vb_pos_nor_wind.size, &Vertex_POS::FORMAT); - vb_pos_nor_wind.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_pos_nor_wind.subresource_srv); + assert(vb_pos_wind.IsValid()); + vb_pos_wind.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_pos_wind.offset, vb_pos_wind.size, &position_format); + vb_pos_wind.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_pos_wind.subresource_srv); + if (vb_nor.IsValid()) + { + vb_nor.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_nor.offset, vb_nor.size, &Vertex_NOR::FORMAT); + vb_nor.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_nor.subresource_srv); + } if (vb_tan.IsValid()) { vb_tan.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_tan.offset, vb_tan.size, &Vertex_TAN::FORMAT); @@ -864,9 +1037,12 @@ namespace wi::scene { desc.misc_flags |= ResourceMiscFlag::RAY_TRACING; } - const uint64_t alignment = device->GetMinOffsetAlignment(&desc); + + const uint64_t alignment = device->GetMinOffsetAlignment(&desc) * sizeof(Vertex_POS32); // additional alignment for RGB32F desc.size = - AlignTo(vertex_positions.size() * sizeof(Vertex_POS) * 2, alignment) + // *2 because prevpos also goes into this! + AlignTo(vertex_positions.size() * sizeof(Vertex_POS32), alignment) + // pos + AlignTo(vertex_positions.size() * sizeof(Vertex_POS32), alignment) + // prevpos + AlignTo(vertex_normals.size() * sizeof(Vertex_NOR), alignment) + AlignTo(vertex_tangents.size() * sizeof(Vertex_TAN), alignment) ; @@ -876,13 +1052,32 @@ namespace wi::scene uint64_t buffer_offset = 0ull; - so_pos_nor_wind.offset = buffer_offset; - so_pos_nor_wind.size = vb_pos_nor_wind.size; - buffer_offset += AlignTo(so_pos_nor_wind.size, alignment); - so_pos_nor_wind.subresource_srv = device->CreateSubresource(&streamoutBuffer, SubresourceType::SRV, so_pos_nor_wind.offset, so_pos_nor_wind.size, &Vertex_POS::FORMAT); - so_pos_nor_wind.subresource_uav = device->CreateSubresource(&streamoutBuffer, SubresourceType::UAV, so_pos_nor_wind.offset, so_pos_nor_wind.size, &Vertex_POS::FORMAT); - so_pos_nor_wind.descriptor_srv = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::SRV, so_pos_nor_wind.subresource_srv); - so_pos_nor_wind.descriptor_uav = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::UAV, so_pos_nor_wind.subresource_uav); + so_pos.offset = buffer_offset; + so_pos.size = vertex_positions.size() * sizeof(Vertex_POS32); + buffer_offset += AlignTo(so_pos.size, alignment); + so_pos.subresource_srv = device->CreateSubresource(&streamoutBuffer, SubresourceType::SRV, so_pos.offset, so_pos.size, &Vertex_POS32::FORMAT); + so_pos.subresource_uav = device->CreateSubresource(&streamoutBuffer, SubresourceType::UAV, so_pos.offset, so_pos.size); // UAV can't have RGB32_F format! + so_pos.descriptor_srv = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::SRV, so_pos.subresource_srv); + so_pos.descriptor_uav = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::UAV, so_pos.subresource_uav); + + so_pre.offset = buffer_offset; + so_pre.size = so_pos.size; + buffer_offset += AlignTo(so_pre.size, alignment); + so_pre.subresource_srv = device->CreateSubresource(&streamoutBuffer, SubresourceType::SRV, so_pre.offset, so_pre.size, &Vertex_POS32::FORMAT); + so_pre.subresource_uav = device->CreateSubresource(&streamoutBuffer, SubresourceType::UAV, so_pre.offset, so_pre.size); // UAV can't have RGB32_F format! + so_pre.descriptor_srv = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::SRV, so_pre.subresource_srv); + so_pre.descriptor_uav = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::UAV, so_pre.subresource_uav); + + if (vb_nor.IsValid()) + { + so_nor.offset = buffer_offset; + so_nor.size = vb_nor.size; + buffer_offset += AlignTo(so_nor.size, alignment); + so_nor.subresource_srv = device->CreateSubresource(&streamoutBuffer, SubresourceType::SRV, so_nor.offset, so_nor.size, &Vertex_NOR::FORMAT); + so_nor.subresource_uav = device->CreateSubresource(&streamoutBuffer, SubresourceType::UAV, so_nor.offset, so_nor.size, &Vertex_NOR::FORMAT); + so_nor.descriptor_srv = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::SRV, so_nor.subresource_srv); + so_nor.descriptor_uav = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::UAV, so_nor.subresource_uav); + } if (vb_tan.IsValid()) { @@ -894,14 +1089,6 @@ namespace wi::scene so_tan.descriptor_srv = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::SRV, so_tan.subresource_srv); so_tan.descriptor_uav = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::UAV, so_tan.subresource_uav); } - - so_pre.offset = buffer_offset; - so_pre.size = vb_pos_nor_wind.size; - buffer_offset += AlignTo(so_pre.size, alignment); - so_pre.subresource_srv = device->CreateSubresource(&streamoutBuffer, SubresourceType::SRV, so_pre.offset, so_pre.size, &Vertex_POS::FORMAT); - so_pre.subresource_uav = device->CreateSubresource(&streamoutBuffer, SubresourceType::UAV, so_pre.offset, so_pre.size, &Vertex_POS::FORMAT); - so_pre.descriptor_srv = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::SRV, so_pre.subresource_srv); - so_pre.descriptor_uav = device->GetDescriptorIndex(&streamoutBuffer, SubresourceType::UAV, so_pre.subresource_uav); } void MeshComponent::CreateRaytracingRenderData() { @@ -939,14 +1126,22 @@ namespace wi::scene auto& geometry = desc.bottom_level.geometries.back(); geometry.type = RaytracingAccelerationStructureDesc::BottomLevel::Geometry::Type::TRIANGLES; geometry.triangles.vertex_buffer = generalBuffer; - geometry.triangles.vertex_byte_offset = vb_pos_nor_wind.offset; + geometry.triangles.vertex_byte_offset = vb_pos_wind.offset; geometry.triangles.index_buffer = generalBuffer; geometry.triangles.index_format = GetIndexFormat(); geometry.triangles.index_count = subset.indexCount; geometry.triangles.index_offset = ib.offset / GetIndexStride() + subset.indexOffset; geometry.triangles.vertex_count = (uint32_t)vertex_positions.size(); - geometry.triangles.vertex_format = Format::R32G32B32_FLOAT; - geometry.triangles.vertex_stride = sizeof(MeshComponent::Vertex_POS); + if (so_pos.IsValid()) + { + geometry.triangles.vertex_format = Vertex_POS32::FORMAT; + geometry.triangles.vertex_stride = sizeof(Vertex_POS32); + } + else + { + geometry.triangles.vertex_format = position_format == Format::R32G32B32A32_FLOAT ? Format::R32G32B32_FLOAT : position_format; + geometry.triangles.vertex_stride = GetFormatStride(position_format); + } } bool success = device->CreateRaytracingAccelerationStructure(&desc, &BLASes[lod]); @@ -1616,20 +1811,18 @@ namespace wi::scene void SoftBodyPhysicsComponent::CreateFromMesh(const MeshComponent& mesh) { vertex_positions_simulation.resize(mesh.vertex_positions.size()); + vertex_normals_simulation.resize(mesh.vertex_normals.size()); vertex_tangents_tmp.resize(mesh.vertex_tangents.size()); vertex_tangents_simulation.resize(mesh.vertex_tangents.size()); - XMMATRIX W = XMLoadFloat4x4(&worldMatrix); XMFLOAT3 _min = XMFLOAT3(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()); XMFLOAT3 _max = XMFLOAT3(std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()); - for (size_t i = 0; i < vertex_positions_simulation.size(); ++i) + XMMATRIX W = XMLoadFloat4x4(&worldMatrix); + for (size_t i = 0; i < mesh.vertex_positions.size(); ++i) { XMFLOAT3 pos = mesh.vertex_positions[i]; XMStoreFloat3(&pos, XMVector3Transform(XMLoadFloat3(&pos), W)); - XMFLOAT3 nor = mesh.vertex_normals.empty() ? XMFLOAT3(1, 1, 1) : mesh.vertex_normals[i]; - XMStoreFloat3(&nor, XMVector3Normalize(XMVector3TransformNormal(XMLoadFloat3(&nor), W))); - const uint8_t wind = mesh.vertex_windweights.empty() ? 0xFF : mesh.vertex_windweights[i]; - vertex_positions_simulation[i].FromFULL(pos, nor, wind); + vertex_positions_simulation[i].FromFULL(pos); _min = wi::math::Min(_min, pos); _max = wi::math::Max(_max, pos); } diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index c4e2e042d..ec889beec 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -339,6 +339,7 @@ namespace wi::scene TLAS_FORCE_DOUBLE_SIDED = 1 << 6, DOUBLE_SIDED_SHADOW = 1 << 7, BVH_ENABLED = 1 << 8, + QUANTIZED_POSITIONS_DISABLED = 1 << 9, }; uint32_t _flags = RENDERABLE; @@ -403,20 +404,24 @@ namespace wi::scene } }; BufferView ib; - BufferView vb_pos_nor_wind; + BufferView vb_pos_wind; + BufferView vb_nor; BufferView vb_tan; BufferView vb_uvs; BufferView vb_atl; BufferView vb_col; BufferView vb_bon; BufferView vb_mor; - BufferView so_pos_nor_wind; + BufferView so_pos; + BufferView so_nor; BufferView so_tan; BufferView so_pre; uint32_t geometryOffset = 0; uint32_t meshletCount = 0; uint32_t active_morph_count = 0; uint32_t morphGPUOffset = 0; + XMFLOAT2 uv_range_min = XMFLOAT2(0, 0); + XMFLOAT2 uv_range_max = XMFLOAT2(1, 1); wi::vector BLASes; // one BLAS per LOD enum BLAS_STATE @@ -440,11 +445,16 @@ namespace wi::scene // false: BVH will be deleted immediately if it exists inline void SetBVHEnabled(bool value) { if (value) { _flags |= BVH_ENABLED; if (!bvh.IsValid()) { BuildBVH(); } } else { _flags &= ~BVH_ENABLED; bvh = {}; bvh_leaf_aabbs.clear(); } } + // Disable quantization of position GPU data. You can use this if you notice inaccuracy in positions. + // This should be enabled for connecting meshes like terrain chunks if their AABB is not consistent with each other + inline void SetQuantizedPositionsDisabled(bool value) { if (value) { _flags |= QUANTIZED_POSITIONS_DISABLED; } else { _flags &= ~QUANTIZED_POSITIONS_DISABLED; } } + inline bool IsRenderable() const { return _flags & RENDERABLE; } inline bool IsDoubleSided() const { return _flags & DOUBLE_SIDED; } inline bool IsDoubleSidedShadow() const { return _flags & DOUBLE_SIDED_SHADOW; } inline bool IsDynamic() const { return _flags & DYNAMIC; } inline bool IsBVHEnabled() const { return _flags & BVH_ENABLED; } + inline bool IsQuantizedPositionsDisabled() const { return _flags & QUANTIZED_POSITIONS_DISABLED; } inline float GetTessellationFactor() const { return tessellationFactor; } inline wi::graphics::IndexBufferFormat GetIndexFormat() const { return wi::graphics::GetIndexBufferFormat((uint32_t)vertex_positions.size()); } @@ -493,75 +503,145 @@ namespace wi::scene void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); - - struct Vertex_POS + struct Vertex_POS10 { - XMFLOAT3 pos = XMFLOAT3(0.0f, 0.0f, 0.0f); - uint8_t n_x = 0; - uint8_t n_y = 0; - uint8_t n_z = 0; - uint8_t w = 0; + uint32_t x : 10; + uint32_t y : 10; + uint32_t z : 10; + uint32_t w : 2; - constexpr void FromFULL(const XMFLOAT3& _pos, const XMFLOAT3& _nor, uint8_t wind) + constexpr void FromFULL(const wi::primitive::AABB& aabb, XMFLOAT3 pos, uint8_t wind) { - pos.x = _pos.x; - pos.y = _pos.y; - pos.z = _pos.z; - MakeFromParams(_nor, wind); + pos = wi::math::InverseLerp(aabb._min, aabb._max, pos); // UNORM remap + x = uint32_t(wi::math::saturate(pos.x) * 1023.0f); + y = uint32_t(wi::math::saturate(pos.y) * 1023.0f); + z = uint32_t(wi::math::saturate(pos.z) * 1023.0f); + w = uint32_t((float(wind) / 255.0f) * 3); } - inline XMVECTOR LoadPOS() const + inline XMVECTOR LoadPOS(const wi::primitive::AABB& aabb) const { - return XMLoadFloat3(&pos); + XMFLOAT3 v = GetPOS(aabb); + return XMLoadFloat3(&v); } - inline XMVECTOR LoadNOR() const + constexpr XMFLOAT3 GetPOS(const wi::primitive::AABB& aabb) const { - XMFLOAT3 N = GetNor_FULL(); - return XMLoadFloat3(&N); - } - constexpr void MakeFromParams(const XMFLOAT3& normal) - { - n_x = uint8_t((normal.x * 0.5f + 0.5f) * 255.0f); - n_y = uint8_t((normal.y * 0.5f + 0.5f) * 255.0f); - n_z = uint8_t((normal.z * 0.5f + 0.5f) * 255.0f); - } - constexpr void MakeFromParams(const XMFLOAT3& normal, uint8_t wind) - { - n_x = uint8_t((normal.x * 0.5f + 0.5f) * 255.0f); - n_y = uint8_t((normal.y * 0.5f + 0.5f) * 255.0f); - n_z = uint8_t((normal.z * 0.5f + 0.5f) * 255.0f); - w = wind; - } - constexpr XMFLOAT3 GetNor_FULL() const - { - XMFLOAT3 nor_FULL(0, 0, 0); - nor_FULL.x = (float(n_x) / 255.0f) * 2.0f - 1.0f; - nor_FULL.y = (float(n_y) / 255.0f) * 2.0f - 1.0f; - nor_FULL.z = (float(n_z) / 255.0f) * 2.0f - 1.0f; - return nor_FULL; + XMFLOAT3 v = XMFLOAT3( + float(x) / 1023.0f, + float(y) / 1023.0f, + float(z) / 1023.0f + ); + return wi::math::Lerp(aabb._min, aabb._max, v); } constexpr uint8_t GetWind() const { - return w; + return uint8_t((float(w) / 3.0f) * 255); } + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R10G10B10A2_UNORM; + }; + struct Vertex_POS16 + { + uint16_t x = 0; + uint16_t y = 0; + uint16_t z = 0; + uint16_t w = 0; + constexpr void FromFULL(const wi::primitive::AABB& aabb, XMFLOAT3 pos, uint8_t wind) + { + pos = wi::math::InverseLerp(aabb._min, aabb._max, pos); // UNORM remap + x = uint16_t(pos.x * 65535.0f); + y = uint16_t(pos.y * 65535.0f); + z = uint16_t(pos.z * 65535.0f); + w = uint16_t((float(wind) / 255.0f) * 65535.0f); + } + inline XMVECTOR LoadPOS(const wi::primitive::AABB& aabb) const + { + XMFLOAT3 v = GetPOS(aabb); + return XMLoadFloat3(&v); + } + constexpr XMFLOAT3 GetPOS(const wi::primitive::AABB& aabb) const + { + XMFLOAT3 v = XMFLOAT3( + float(x) / 65535.0f, + float(y) / 65535.0f, + float(z) / 65535.0f + ); + return wi::math::Lerp(aabb._min, aabb._max, v); + } + constexpr uint8_t GetWind() const + { + return uint8_t((float(w) / 65535.0f) * 255); + } + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R16G16B16A16_UNORM; + }; + struct Vertex_POS32 + { + float x = 0; + float y = 0; + float z = 0; + + constexpr void FromFULL(const XMFLOAT3& pos) + { + x = pos.x; + y = pos.y; + z = pos.z; + } + inline XMVECTOR LoadPOS() const + { + return XMVectorSet(x, y, z, 1); + } + constexpr XMFLOAT3 GetPOS() const + { + return XMFLOAT3(x, y, z); + } + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R32G32B32_FLOAT; + }; + struct Vertex_POS32W + { + float x = 0; + float y = 0; + float z = 0; + float w = 0; + + constexpr void FromFULL(const XMFLOAT3& pos, uint8_t wind) + { + x = pos.x; + y = pos.y; + z = pos.z; + w = float(wind) / 255.0f; + } + inline XMVECTOR LoadPOS() const + { + return XMVectorSet(x, y, z, 1); + } + constexpr XMFLOAT3 GetPOS() const + { + return XMFLOAT3(x, y, z); + } + constexpr uint8_t GetWind() const + { + return uint8_t(w * 255); + } static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R32G32B32A32_FLOAT; }; + wi::graphics::Format position_format = Vertex_POS16::FORMAT; // CreateRenderData() will choose the appropriate format + struct Vertex_TEX { - XMHALF2 tex = XMHALF2(0.0f, 0.0f); + uint16_t x = 0; + uint16_t y = 0; - void FromFULL(const XMFLOAT2& texcoords) + constexpr void FromFULL(const XMFLOAT2& uv, const XMFLOAT2& uv_range_min = XMFLOAT2(0, 0), const XMFLOAT2& uv_range_max = XMFLOAT2(1, 1)) { - tex = XMHALF2(texcoords.x, texcoords.y); + x = uint16_t(wi::math::InverseLerp(uv_range_min.x, uv_range_max.x, uv.x) * 65535.0f); + y = uint16_t(wi::math::InverseLerp(uv_range_min.y, uv_range_max.y, uv.y) * 65535.0f); } - - static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R16G16_FLOAT; + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R16G16_UNORM; }; struct Vertex_UVS { Vertex_TEX uv0; Vertex_TEX uv1; - static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R16G16B16A16_FLOAT; + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R16G16B16A16_UNORM; }; struct Vertex_BON { @@ -606,6 +686,44 @@ namespace wi::scene uint32_t color = 0; static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R8G8B8A8_UNORM; }; + struct Vertex_NOR + { + int8_t x = 0; + int8_t y = 0; + int8_t z = 0; + int8_t w = 0; + + void FromFULL(const XMFLOAT3& nor) + { + XMVECTOR N = XMLoadFloat3(&nor); + N = XMVector3Normalize(N); + XMFLOAT3 n; + XMStoreFloat3(&n, N); + + x = int8_t(n.x * 127.5f); + y = int8_t(n.y * 127.5f); + z = int8_t(n.z * 127.5f); + w = 0; + } + inline XMFLOAT3 GetNOR() const + { + return XMFLOAT3( + float(x) / 127.5f, + float(y) / 127.5f, + float(z) / 127.5f + ); + } + inline XMVECTOR LoadNOR() const + { + return XMVectorSet( + float(x) / 127.5f, + float(y) / 127.5f, + float(z) / 127.5f, + 0 + ); + } + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R8G8B8A8_SNORM; + }; struct Vertex_TAN { int8_t x = 0; @@ -626,7 +744,15 @@ namespace wi::scene z = int8_t(t.z * 127.5f); w = int8_t(t.w * 127.5f); } - + inline XMFLOAT4 GetTAN() const + { + return XMFLOAT4( + float(x) / 127.5f, + float(y) / 127.5f, + float(z) / 127.5f, + float(w) / 127.5f + ); + } static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R8G8B8A8_SNORM; }; @@ -819,7 +945,8 @@ namespace wi::scene // Non-serialized attributes: std::shared_ptr physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running. XMFLOAT4X4 worldMatrix = wi::math::IDENTITY_MATRIX; - wi::vector vertex_positions_simulation; // graphics vertices after simulation (world space) + wi::vector vertex_positions_simulation; // graphics vertices after simulation (world space) + wi::vector vertex_normals_simulation; wi::vectorvertex_tangents_tmp; wi::vector vertex_tangents_simulation; wi::primitive::AABB aabb; @@ -828,6 +955,11 @@ namespace wi::scene inline bool IsDisableDeactivation() const { return _flags & DISABLE_DEACTIVATION; } + inline bool HasVertices() const + { + return !vertex_positions_simulation.empty(); + } + // Create physics represenation of graphics mesh void CreateFromMesh(const MeshComponent& mesh); diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index e8616af06..36f0e4249 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -750,6 +750,7 @@ namespace wi::terrain material.SetReflectance(1); MeshComponent& mesh = generator->scene.meshes.Create(chunk_data.entity); + mesh.SetQuantizedPositionsDisabled(true); // connecting meshes quantization is not correct because mismatching AABBs object.meshID = chunk_data.entity; mesh.indices = chunk_indices().indices; for (auto& lod : chunk_indices().lods) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 548a74778..a9d4de404 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 344; + const int revision = 345; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);