diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index f2c5ea9dc..77d586a2d 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -105,7 +105,8 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) MeshComponent* mesh = wiRenderer::GetScene().meshes.GetComponent(entity); if (mesh != nullptr) { - wiRenderer::CreateImpostor(entity, GRAPHICSTHREAD_IMMEDIATE); + Scene& scene = wiRenderer::GetScene(); + scene.impostors.Create(entity).swapInDistance = impostorDistanceSlider->GetValue(); } }); meshWindow->AddWidget(impostorCreateButton); @@ -115,10 +116,10 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) impostorDistanceSlider->SetSize(XMFLOAT2(100, 30)); impostorDistanceSlider->SetPos(XMFLOAT2(x, y += step)); impostorDistanceSlider->OnSlide([&](wiEventArgs args) { - MeshComponent* mesh = wiRenderer::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr) + ImpostorComponent* impostor = wiRenderer::GetScene().impostors.GetComponent(entity); + if (impostor != nullptr) { - mesh->impostorDistance = args.fValue; + impostor->swapInDistance = args.fValue; } }); meshWindow->AddWidget(impostorDistanceSlider); @@ -229,7 +230,12 @@ void MeshWindow::SetEntity(Entity entity) meshInfoLabel->SetText(ss.str()); doubleSidedCheckBox->SetCheck(mesh->IsDoubleSided()); - impostorDistanceSlider->SetValue(mesh->impostorDistance); + + const ImpostorComponent* impostor = scene.impostors.GetComponent(entity); + if (impostor != nullptr) + { + impostorDistanceSlider->SetValue(impostor->swapInDistance); + } tessellationFactorSlider->SetValue(mesh->GetTessellationFactor()); SoftBodyPhysicsComponent* physicscomponent = wiRenderer::GetScene().softbodies.GetComponent(entity); diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp index cea3be88e..6e028bffc 100644 --- a/WickedEngine/wiEmittedParticle.cpp +++ b/WickedEngine/wiEmittedParticle.cpp @@ -226,6 +226,8 @@ void wiEmittedParticle::Restart() //#define DEBUG_SORTING // slow but great for debug!! void wiEmittedParticle::UpdateRenderData(const TransformComponent& transform, const MaterialComponent& material, const MeshComponent* mesh, GRAPHICSTHREAD threadID) { + center = transform.GetPosition(); + CreateSelfBuffers(); GraphicsDevice* device = wiRenderer::GetDevice(); diff --git a/WickedEngine/wiEmittedParticle.h b/WickedEngine/wiEmittedParticle.h index 5015cf35e..26b264089 100644 --- a/WickedEngine/wiEmittedParticle.h +++ b/WickedEngine/wiEmittedParticle.h @@ -115,6 +115,9 @@ public: uint32_t GetMaxParticleCount() const { return MAX_PARTICLES; } uint32_t GetMemorySizeInBytes() const; + // Non-serialized attributes: + XMFLOAT3 center; + inline bool IsDebug() const { return _flags & DEBUG; } inline bool IsPaused() const { return _flags & PAUSED; } inline bool IsSorted() const { return _flags & SORTING; } diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 2530515f2..d757d4c23 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -159,16 +159,18 @@ struct RenderBatch { uint32_t hash; uint32_t instance; + float distance; - inline void Create(size_t meshIndex, size_t instanceIndex, float distance) + inline void Create(size_t meshIndex, size_t instanceIndex, float _distance) { hash = 0; assert(meshIndex < 0x00FFFFFF); hash |= (uint32_t)(meshIndex & 0x00FFFFFF) << 8; - hash |= ((uint32_t)(distance)) & 0xFF; + hash |= ((uint32_t)(_distance)) & 0xFF; instance = (uint32_t)instanceIndex; + distance = _distance; } inline uint32_t GetMeshIndex() const @@ -181,7 +183,7 @@ struct RenderBatch } inline float GetDistance() const { - return (float)(hash & 0xFF); + return distance; } }; @@ -1222,6 +1224,7 @@ void RenderMeshes(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYP uint32_t meshIndex; int instanceCount; uint32_t dataOffset; + int forceAlphatestForDithering; }; InstancedBatch* instancedBatchArray = nullptr; int instancedBatchCount = 0; @@ -1242,6 +1245,7 @@ void RenderMeshes(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYP instancedBatch->meshIndex = meshIndex; instancedBatch->instanceCount = 0; instancedBatch->dataOffset = instancesOffset + batchID * instanceDataSize; + instancedBatch->forceAlphatestForDithering = 0; if (instancedBatchArray == nullptr) { instancedBatchArray = instancedBatch; @@ -1250,7 +1254,16 @@ void RenderMeshes(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYP const ObjectComponent& instance = scene.objects[instanceIndex]; - float dither = instance.GetTransparency(); + float dither = instance.GetTransparency(); + + if (instance.IsImpostorPlacement()) + { + float distance = batch.GetDistance(); + float swapDistance = instance.impostorSwapDistance; + float fadeThreshold = instance.impostorFadeThresholdRadius; + dither = max(0, distance - swapDistance) / fadeThreshold; + instancedBatchArray[instancedBatchCount - 1].forceAlphatestForDithering = 1; + } Entity objectEntity = scene.objects.GetEntity(instanceIndex); const TransformComponent& transform = *scene.transforms.GetComponent(objectEntity); @@ -1258,7 +1271,7 @@ void RenderMeshes(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYP // Write into actual GPU-buffer: if (advancedVBRequest) { - ((volatile InstBuf*)instances)[batchID].instance.Create(transform.world, instance.color); + ((volatile InstBuf*)instances)[batchID].instance.Create(transform.world, instance.color, dither); const PreviousFrameTransformComponent& prev_transform = *scene.prev_transforms.GetComponent(objectEntity); ((volatile InstBuf*)instances)[batchID].instancePrev.Create(prev_transform.world_prev); @@ -1279,7 +1292,7 @@ void RenderMeshes(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYP { const InstancedBatch& instancedBatch = instancedBatchArray[instancedBatchID]; const MeshComponent& mesh = scene.meshes[instancedBatch.meshIndex]; - + bool forceAlphaTestForDithering = instancedBatch.forceAlphatestForDithering != 0; const float tessF = mesh.GetTessellationFactor(); const bool tessellatorRequested = tessF > 0 && tessellation; @@ -1292,8 +1305,6 @@ void RenderMeshes(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYP device->BindConstantBuffer(HS, constantBuffers[CBTYPE_TESSELLATION], CBSLOT_RENDERER_TESSELLATION, threadID); } - bool forceAlphaTestForDithering = false; - device->BindIndexBuffer(mesh.indexBuffer.get(), mesh.GetIndexFormat(), 0, threadID); @@ -1481,165 +1492,146 @@ void RenderMeshes(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYP } } -void RenderImpostors(const XMFLOAT3& eye, const RenderQueue& renderQueue, SHADERTYPE shaderType, UINT renderTypeFlags, GRAPHICSTHREAD threadID) +void RenderImpostors(const CameraComponent& camera, SHADERTYPE shaderType, GRAPHICSTHREAD threadID) { - //GraphicsPSO* impostorRequest = GetImpostorPSO(shaderType); + Scene& scene = GetScene(); + GraphicsPSO* impostorRequest = GetImpostorPSO(shaderType); - //if (!renderQueue.empty() && impostorRequest != nullptr) - //{ - // GraphicsDevice* device = GetDevice(); - // Scene& scene = GetScene(); + if (scene.impostors.GetCount() > 0 && impostorRequest != nullptr) + { + GraphicsDevice* device = GetDevice(); - // device->EventBegin("RenderImpostors", threadID); + device->EventBegin("RenderImpostors", threadID); - // const bool easyTextureBind = - // shaderType == SHADERTYPE_TEXTURE || - // shaderType == SHADERTYPE_SHADOW || - // shaderType == SHADERTYPE_SHADOWCUBE || - // shaderType == SHADERTYPE_DEPTHONLY || - // shaderType == SHADERTYPE_VOXELIZE; + // TODO: Now the impostors are using the regular mesh shaders for simplicity, but we should do much better, simpler impostor shaders! + struct InstBuf + { + Instance instance; + InstancePrev instancePrev; + }; + const bool advancedVBRequest = + !IsWireRender() && + (shaderType == SHADERTYPE_FORWARD || + shaderType == SHADERTYPE_DEFERRED || + shaderType == SHADERTYPE_TILEDFORWARD); - // // Pre-allocate space for all the instances in GPU-buffer: - // const UINT instanceDataSize = sizeof(Instance); - // UINT instancesOffset; - // const size_t alloc_size = renderQueue.batchCount * instanceDataSize; - // void* instances = device->AllocateFromRingBuffer(dynamicVertexBufferPool, alloc_size, instancesOffset, threadID); + const bool easyTextureBind = + shaderType == SHADERTYPE_TEXTURE || + shaderType == SHADERTYPE_SHADOW || + shaderType == SHADERTYPE_SHADOWCUBE || + shaderType == SHADERTYPE_DEPTHONLY || + shaderType == SHADERTYPE_VOXELIZE; - // // Render impostors: - // if (impostorRequest != nullptr) - // { - // bool impostorGraphicsStateComplete = false; + bool impostorGraphicsStateComplete = false; - // for (size_t batchID = 0; batchID < renderQueue.batchCount; ++batchID) - // { - // const RenderBatch& batch = renderQueue.batchArray[batchID]; + for (size_t impostorID = 0; impostorID < scene.impostors.GetCount(); ++impostorID) + { + const ImpostorComponent& impostor = scene.impostors[impostorID]; + if (!camera.frustum.CheckBox(impostor.aabb)) + { + continue; + } - // const size_t meshIndex = batch.GetMeshIndex(); - // const MeshComponent& mesh = scene.meshes[meshIndex]; - // if (!mesh.IsRenderable() || !mesh.HasImpostor()) - // { - // continue; - // } + if (!impostorGraphicsStateComplete) + { + device->BindGraphicsPSO(impostorRequest, threadID); + device->BindConstantBuffer(PS, &impostorMaterialCB, CB_GETBINDSLOT(MaterialCB), threadID); + SetAlphaRef(0.75f, threadID); + impostorGraphicsStateComplete = true; + } - // //const auto& visibleInstances = iter->second; + UINT instanceCount = (UINT)impostor.instanceMatrices.size(); - // UINT instancesOffset; - // size_t alloc_size = /*visibleInstances.size()*/ 1; - // alloc_size *= advancedVBRequest ? sizeof(InstBuf) : sizeof(Instance); - // void* instances = device->AllocateFromRingBuffer(dynamicVertexBufferPool, alloc_size, instancesOffset, threadID); + // Pre-allocate space for all the instances in GPU-buffer: + const UINT instanceDataSize = advancedVBRequest ? sizeof(InstBuf) : sizeof(Instance); + UINT instancesOffset; + const size_t alloc_size = instanceCount * instanceDataSize; + void* instances = device->AllocateFromRingBuffer(&dynamicVertexBufferPools[threadID], alloc_size, instancesOffset, threadID); + + int drawableInstanceCount = 0; + for (UINT instanceID = 0; instanceID < instanceCount; ++instanceID) + { + const XMFLOAT4X4& mat = impostor.instanceMatrices[instanceID]; + const XMFLOAT3 center = *((XMFLOAT3*)&mat._41); + float distance = wiMath::Distance(camera.Eye, center); - // int k = 0; - // for (size_t instanceID = 0; instanceID < 1; ++instanceID) - // { - // size_t instanceIndex = batch.GetInstanceIndex(); - // const ObjectComponent& instance = scene.objects[instanceIndex]; - // if (occlusionCulling && instance.IsOccluded()) - // continue; + if (distance < impostor.swapInDistance - impostor.fadeThresholdRadius) + { + continue; + } - // const AABB& aabb = scene.aabb_objects[instanceIndex]; + float dither = max(0, impostor.swapInDistance - distance) / impostor.fadeThresholdRadius; - // const float impostorThreshold = aabb.getRadius(); - // float dist = wiMath::Distance(eye, aabb.getCenter()); - // float dither = instance.GetTransparency(); - // dither = wiMath::SmoothStep(1.0f, dither, wiMath::Clamp((dist - mesh.impostorDistance) / impostorThreshold, 0, 1)); - // if (dither > 1.0f - FLT_EPSILON) - // continue; + if (advancedVBRequest) + { + ((volatile InstBuf*)instances)[drawableInstanceCount].instance.Create(mat, XMFLOAT4(1, 1, 1, 1), dither); + ((volatile InstBuf*)instances)[drawableInstanceCount].instancePrev.Create(mat); + } + else + { + ((volatile Instance*)instances)[drawableInstanceCount].Create(mat, XMFLOAT4(1, 1, 1, 1), dither); + } - // XMMATRIX boxMat = mesh.aabb.getAsBoxMatrix(); + drawableInstanceCount++; + } + device->InvalidateBufferAccess(&dynamicVertexBufferPools[threadID], threadID); - // Entity objectEntity = scene.objects.GetEntity(instanceIndex); - // const TransformComponent& transform = *scene.transforms.GetComponent(objectEntity); + if (!advancedVBRequest || IsWireRender()) + { + GPUBuffer* vbs[] = { + &impostorVB_POS, + &impostorVB_TEX, + &dynamicVertexBufferPools[threadID] + }; + UINT strides[] = { + sizeof(MeshComponent::Vertex_POS), + sizeof(MeshComponent::Vertex_TEX), + sizeof(Instance) + }; + UINT offsets[] = { + 0, + 0, + instancesOffset + }; + device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, offsets, threadID); + } + else + { + GPUBuffer* vbs[] = { + &impostorVB_POS, + &impostorVB_TEX, + &impostorVB_POS, + &dynamicVertexBufferPools[threadID] + }; + UINT strides[] = { + sizeof(MeshComponent::Vertex_POS), + sizeof(MeshComponent::Vertex_TEX), + sizeof(MeshComponent::Vertex_POS), + sizeof(InstBuf) + }; + UINT offsets[] = { + 0, + 0, + 0, + instancesOffset + }; + device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, offsets, threadID); + } - // XMFLOAT4X4 tempMat; - // XMStoreFloat4x4(&tempMat, boxMat*XMLoadFloat4x4(&transform.world)); + GPUResource* res[] = { + impostor.rendertarget.GetTexture(0), + impostor.rendertarget.GetTexture(1), + impostor.rendertarget.GetTexture(2) + }; + device->BindResources(PS, res, TEXSLOT_ONDEMAND0, (easyTextureBind ? 1 : ARRAYSIZE(res)), threadID); - // if (advancedVBRequest) - // { - // ((volatile InstBuf*)instances)[k].instance.Create(tempMat, instance.color, dither); + device->DrawInstanced(6 * 6, drawableInstanceCount, 0, 0, threadID); // 6 * 6: see MeshComponent::CreateImpostorVB function - // const PreviousFrameTransformComponent& prev_transform = *scene.prev_transforms.GetComponent(objectEntity); - // XMStoreFloat4x4(&tempMat, boxMat*XMLoadFloat4x4(&prev_transform.world_prev)); - // ((volatile InstBuf*)instances)[k].instancePrev.Create(tempMat); - // } - // else - // { - // ((volatile Instance*)instances)[k].Create(tempMat, instance.color, dither); - // } + } - // ++k; - // } - - // device->InvalidateBufferAccess(dynamicVertexBufferPool, threadID); - - // if (k < 1) - // continue; - - // if (!advancedVBRequest || IsWireRender()) - // { - // GPUBuffer* vbs[] = { - // &impostorVB_POS, - // &impostorVB_TEX, - // dynamicVertexBufferPool - // }; - // UINT strides[] = { - // sizeof(MeshComponent::Vertex_POS), - // sizeof(MeshComponent::Vertex_TEX), - // sizeof(Instance) - // }; - // UINT offsets[] = { - // 0, - // 0, - // instancesOffset - // }; - // device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, offsets, threadID); - // } - // else - // { - // GPUBuffer* vbs[] = { - // &impostorVB_POS, - // &impostorVB_TEX, - // &impostorVB_POS, - // dynamicVertexBufferPool - // }; - // UINT strides[] = { - // sizeof(MeshComponent::Vertex_POS), - // sizeof(MeshComponent::Vertex_TEX), - // sizeof(MeshComponent::Vertex_POS), - // sizeof(InstBuf) - // }; - // UINT offsets[] = { - // 0, - // 0, - // 0, - // instancesOffset - // }; - // device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, offsets, threadID); - // } - - // GPUResource* res[] = { - // mesh.impostorTarget.GetTexture(0), - // mesh.impostorTarget.GetTexture(1), - // mesh.impostorTarget.GetTexture(2) - // }; - // device->BindResources(PS, res, TEXSLOT_ONDEMAND0, (easyTextureBind ? 1 : ARRAYSIZE(res)), threadID); - - // if (!impostorGraphicsStateComplete) - // { - // device->BindGraphicsPSO(impostorRequest, threadID); - // device->BindConstantBuffer(PS, &impostorMaterialCB, CB_GETBINDSLOT(MaterialCB), threadID); - // SetAlphaRef(0.75f, threadID); - // impostorGraphicsStateComplete = true; - // } - - // device->DrawInstanced(6 * 6, k, 0, 0, threadID); // 6 * 6: see MeshComponent::CreateImpostorVB function - - // } - // } - - - // device->EventEnd(threadID); - //} + device->EventEnd(threadID); + } } @@ -3462,7 +3454,7 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) if (material.IsDirty()) { - material.SetClean(); + material.SetDirty(false); materialGPUData.g_xMat_baseColor = material.baseColor; materialGPUData.g_xMat_texMulAdd = material.texMulAdd; @@ -3861,8 +3853,8 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) GenerateClouds((Texture2D*)textures[TEXTYPE_2D_CLOUDS], 5, cloudPhase, GRAPHICSTHREAD_IMMEDIATE); } - // Render out of date environment probes: RefreshEnvProbes(threadID); + RefreshImpostors(threadID); } void OcclusionCulling_Render(GRAPHICSTHREAD threadID) { @@ -4042,11 +4034,26 @@ void DrawWaterRipples(GRAPHICSTHREAD threadID) void DrawSoftParticles(const CameraComponent& camera, bool distortion, GRAPHICSTHREAD threadID) { Scene& scene = GetScene(); + size_t emitterCount = scene.emitters.GetCount(); - for (size_t i = 0; i < scene.emitters.GetCount(); ++i) + // Sort emitters based on distance: + assert(emitterCount < 0x0000FFFF); // watch out for sorting hash truncation! + uint32_t* emitterSortingHashes = (uint32_t*)frameAllocators[threadID].allocate(sizeof(uint32_t) * emitterCount); + for (size_t i = 0; i < emitterCount; ++i) { wiEmittedParticle& emitter = scene.emitters[i]; - Entity entity = scene.emitters.GetEntity(i); + float distance = wiMath::DistanceEstimated(emitter.center, camera.Eye); + emitterSortingHashes[i] = 0; + emitterSortingHashes[i] |= (uint32_t)i & 0x0000FFFF; + emitterSortingHashes[i] |= ((uint32_t)(distance * 10) & 0x0000FFFF) << 16; + } + std::sort(emitterSortingHashes, emitterSortingHashes + emitterCount, std::greater()); + + for (size_t i = 0; i < emitterCount; ++i) + { + uint32_t emitterIndex = emitterSortingHashes[i] & 0x0000FFFF; + wiEmittedParticle& emitter = scene.emitters[emitterIndex]; + Entity entity = scene.emitters.GetEntity(emitterIndex); const MaterialComponent& material = *scene.materials.GetComponent(entity); if (distortion && emitter.shaderType == wiEmittedParticle::SOFT_DISTORTION) @@ -4059,6 +4066,8 @@ void DrawSoftParticles(const CameraComponent& camera, bool distortion, GRAPHICST } } + frameAllocators[threadID].free(sizeof(uint32_t) * emitterCount); + } void DrawTrails(GRAPHICSTHREAD threadID, Texture2D* refracRes) { @@ -4883,6 +4892,7 @@ void DrawWorld(const CameraComponent& camera, bool tessellation, GRAPHICSTHREAD } } + RenderImpostors(camera, shaderType, threadID); RenderQueue renderQueue; for (uint32_t instanceIndex : culling.culledObjects) @@ -4904,16 +4914,20 @@ void DrawWorld(const CameraComponent& camera, bool tessellation, GRAPHICSTHREAD if (object.IsRenderable() && object.GetRenderTypes() & RENDERTYPE_OPAQUE) { + const float distance = wiMath::Distance(camera.Eye, object.center); + if (object.IsImpostorPlacement() && distance > object.impostorSwapDistance + object.impostorFadeThresholdRadius) + { + continue; + } RenderBatch* batch = (RenderBatch*)frameAllocators[threadID].allocate(sizeof(RenderBatch)); size_t meshIndex = scene.meshes.GetIndex(object.meshID); - batch->Create(meshIndex, instanceIndex, wiMath::DistanceEstimated(camera.Eye, object.position)); + batch->Create(meshIndex, instanceIndex, distance); renderQueue.add(batch); } } if (!renderQueue.empty()) { renderQueue.sort(RenderQueue::SORT_FRONT_TO_BACK); - RenderImpostors(camera.Eye, renderQueue, shaderType, RENDERTYPE_OPAQUE, threadID); RenderMeshes(camera.Eye, renderQueue, shaderType, RENDERTYPE_OPAQUE, threadID, tessellation); frameAllocators[threadID].free(sizeof(RenderBatch) * renderQueue.batchCount); @@ -4980,7 +4994,7 @@ void DrawWorldTransparent(const CameraComponent& camera, SHADERTYPE shaderType, { RenderBatch* batch = (RenderBatch*)frameAllocators[threadID].allocate(sizeof(RenderBatch)); size_t meshIndex = scene.meshes.GetIndex(object.meshID); - batch->Create(meshIndex, instanceIndex, wiMath::DistanceEstimated(camera.Eye, object.position)); + batch->Create(meshIndex, instanceIndex, wiMath::DistanceEstimated(camera.Eye, object.center)); renderQueue.add(batch); } } @@ -5526,10 +5540,11 @@ void DrawDecals(const CameraComponent& camera, GRAPHICSTHREAD threadID) void RefreshEnvProbes(GRAPHICSTHREAD threadID) { - GetDevice()->EventBegin("EnvironmentProbe Refresh", threadID); - Scene& scene = GetScene(); + GraphicsDevice* device = GetDevice(); + device->EventBegin("EnvironmentProbe Refresh", threadID); + static const UINT envmapRes = 128; static const UINT envmapCount = 16; static const UINT envmapMIPs = 8; @@ -5552,7 +5567,7 @@ void RefreshEnvProbes(GRAPHICSTHREAD threadID) textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]->RequestIndependentShaderResourceArraySlices(true); textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]->RequestIndependentShaderResourcesForMIPs(true); textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]->RequestIndependentUnorderedAccessResourcesForMIPs(true); - HRESULT hr = GetDevice()->CreateTexture2D(&desc, nullptr, (Texture2D**)&textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]); + HRESULT hr = device->CreateTexture2D(&desc, nullptr, (Texture2D**)&textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]); assert(SUCCEEDED(hr)); } @@ -5570,7 +5585,7 @@ void RefreshEnvProbes(GRAPHICSTHREAD threadID) desc.MiscFlags = RESOURCE_MISC_TEXTURECUBE; desc.Usage = USAGE_DEFAULT; - HRESULT hr = GetDevice()->CreateTexture2D(&desc, nullptr, &envrenderingDepthBuffer); + HRESULT hr = device->CreateTexture2D(&desc, nullptr, &envrenderingDepthBuffer); assert(SUCCEEDED(hr)); } @@ -5581,7 +5596,7 @@ void RefreshEnvProbes(GRAPHICSTHREAD threadID) VP.TopLeftY = 0; VP.MinDepth = 0.0f; VP.MaxDepth = 1.0f; - GetDevice()->BindViewports(1, &VP, threadID); + device->BindViewports(1, &VP, threadID); const float zNearP = GetCamera().zNearP; const float zFarP = GetCamera().zFarP; @@ -5632,10 +5647,10 @@ void RefreshEnvProbes(GRAPHICSTHREAD threadID) probe.SetDirty(false); } - GetDevice()->BindRenderTargets(1, (Texture2D**)&textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], envrenderingDepthBuffer, threadID, probe.textureIndex); + device->BindRenderTargets(1, (Texture2D**)&textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], envrenderingDepthBuffer, threadID, probe.textureIndex); const float clearColor[4] = { 0,0,0,1 }; - GetDevice()->ClearRenderTarget(textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], clearColor, threadID, probe.textureIndex); - GetDevice()->ClearDepthStencil(envrenderingDepthBuffer, CLEAR_DEPTH, 0.0f, 0, threadID); + device->ClearRenderTarget(textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], clearColor, threadID, probe.textureIndex); + device->ClearDepthStencil(envrenderingDepthBuffer, CLEAR_DEPTH, 0.0f, 0, threadID); std::vector cameras; @@ -5662,13 +5677,13 @@ void RefreshEnvProbes(GRAPHICSTHREAD threadID) XMStoreFloat4x4(&cb.xCubeShadowVP[i], cameras[i].getVP()); } - GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_CUBEMAPRENDER], &cb, threadID); - GetDevice()->BindConstantBuffer(GS, constantBuffers[CBTYPE_CUBEMAPRENDER], CB_GETBINDSLOT(CubemapRenderCB), threadID); + device->UpdateBuffer(constantBuffers[CBTYPE_CUBEMAPRENDER], &cb, threadID); + device->BindConstantBuffer(GS, constantBuffers[CBTYPE_CUBEMAPRENDER], CB_GETBINDSLOT(CubemapRenderCB), threadID); CameraCB camcb; camcb.g_xCamera_CamPos = center; // only this will be used by envprobe rendering shaders the rest is read from cubemaprenderCB - GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_CAMERA], &camcb, threadID); + device->UpdateBuffer(constantBuffers[CBTYPE_CAMERA], &camcb, threadID); const LayerComponent& layer = *scene.layers.GetComponent(entity); const uint32_t layerMask = layer.GetLayerMask(); @@ -5709,39 +5724,39 @@ void RefreshEnvProbes(GRAPHICSTHREAD threadID) if (enviroMap != nullptr) { - GetDevice()->BindGraphicsPSO(PSO_sky[SKYRENDERING_ENVMAPCAPTURE_STATIC], threadID); - GetDevice()->BindResource(PS, enviroMap, TEXSLOT_ONDEMAND0, threadID); + device->BindGraphicsPSO(PSO_sky[SKYRENDERING_ENVMAPCAPTURE_STATIC], threadID); + device->BindResource(PS, enviroMap, TEXSLOT_ONDEMAND0, threadID); } else { - GetDevice()->BindGraphicsPSO(PSO_sky[SKYRENDERING_ENVMAPCAPTURE_DYNAMIC], threadID); - GetDevice()->BindResource(PS, textures[TEXTYPE_2D_CLOUDS], TEXSLOT_ONDEMAND0, threadID); + device->BindGraphicsPSO(PSO_sky[SKYRENDERING_ENVMAPCAPTURE_DYNAMIC], threadID); + device->BindResource(PS, textures[TEXTYPE_2D_CLOUDS], TEXSLOT_ONDEMAND0, threadID); } - GetDevice()->Draw(240, 0, threadID); + device->Draw(240, 0, threadID); } - GetDevice()->BindRenderTargets(0, nullptr, nullptr, threadID); - //GetDevice()->GenerateMips(textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], threadID, probe->textureIndex); + device->BindRenderTargets(0, nullptr, nullptr, threadID); + //device->GenerateMips(textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], threadID, probe->textureIndex); GenerateMipChain((Texture2D*)textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], MIPGENFILTER_LINEAR, threadID, probe.textureIndex); // Filter the enviroment map mip chain according to BRDF: // A bit similar to MIP chain generation, but its input is the MIP-mapped texture, // and we generatethe filtered MIPs from bottom to top. - GetDevice()->EventBegin("FilterEnvMap", threadID); + device->EventBegin("FilterEnvMap", threadID); { Texture* texture = textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]; TextureDesc desc = texture->GetDesc(); int arrayIndex = probe.textureIndex; - GetDevice()->BindComputePSO(CPSO[CSTYPE_FILTERENVMAP], threadID); + device->BindComputePSO(CPSO[CSTYPE_FILTERENVMAP], threadID); desc.Width = 1; desc.Height = 1; for (UINT i = desc.MipLevels - 1; i > 0; --i) { - GetDevice()->BindUAV(CS, texture, 0, threadID, i); - GetDevice()->BindResource(CS, texture, TEXSLOT_UNIQUE0, threadID, max(0, (int)i - 2)); + device->BindUAV(CS, texture, 0, threadID, i); + device->BindResource(CS, texture, TEXSLOT_UNIQUE0, threadID, max(0, (int)i - 2)); FilterEnvmapCB cb; cb.filterResolution.x = desc.Width; @@ -5749,30 +5764,410 @@ void RefreshEnvProbes(GRAPHICSTHREAD threadID) cb.filterArrayIndex = arrayIndex; cb.filterRoughness = (float)i / (float)desc.MipLevels; cb.filterRayCount = 128; - GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_FILTERENVMAP], &cb, threadID); - GetDevice()->BindConstantBuffer(CS, constantBuffers[CBTYPE_FILTERENVMAP], CB_GETBINDSLOT(FilterEnvmapCB), threadID); + device->UpdateBuffer(constantBuffers[CBTYPE_FILTERENVMAP], &cb, threadID); + device->BindConstantBuffer(CS, constantBuffers[CBTYPE_FILTERENVMAP], CB_GETBINDSLOT(FilterEnvmapCB), threadID); - GetDevice()->Dispatch( + device->Dispatch( max(1, (UINT)ceilf((float)desc.Width / GENERATEMIPCHAIN_2D_BLOCK_SIZE)), max(1, (UINT)ceilf((float)desc.Height / GENERATEMIPCHAIN_2D_BLOCK_SIZE)), 6, threadID); - GetDevice()->UAVBarrier((GPUResource**)&texture, 1, threadID); + device->UAVBarrier((GPUResource**)&texture, 1, threadID); desc.Width *= 2; desc.Height *= 2; } - GetDevice()->UnbindUAVs(0, 1, threadID); + device->UnbindUAVs(0, 1, threadID); } - GetDevice()->EventEnd(threadID); + device->EventEnd(threadID); } - GetDevice()->BindResource(PS, textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], TEXSLOT_ENVMAPARRAY, threadID); - GetDevice()->BindResource(CS, textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], TEXSLOT_ENVMAPARRAY, threadID); + device->BindResource(PS, textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], TEXSLOT_ENVMAPARRAY, threadID); + device->BindResource(CS, textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], TEXSLOT_ENVMAPARRAY, threadID); - GetDevice()->EventEnd(threadID); // EnvironmentProbe Refresh + device->EventEnd(threadID); // EnvironmentProbe Refresh +} + +void RefreshImpostors(GRAPHICSTHREAD threadID) +{ + Scene& scene = GetScene(); + + if (scene.impostors.GetCount() > 0) + { + GraphicsDevice* device = GetDevice(); + device->EventBegin("Impostor Refresh", threadID); + + + if (!impostorMaterialCB.IsValid()) + { + MaterialCB mcb; + ZeroMemory(&mcb, sizeof(mcb)); + mcb.g_xMat_baseColor = XMFLOAT4(1, 1, 1, 1); + mcb.g_xMat_texMulAdd = XMFLOAT4(1, 1, 0, 0); + mcb.g_xMat_normalMapStrength = 1.0f; + mcb.g_xMat_roughness = 1.0f; + mcb.g_xMat_reflectance = 1.0f; + mcb.g_xMat_metalness = 1.0f; + + GPUBufferDesc bd; + bd.BindFlags = BIND_CONSTANT_BUFFER; + bd.Usage = USAGE_IMMUTABLE; + bd.CPUAccessFlags = 0; + bd.ByteWidth = sizeof(MaterialCB); + SubresourceData initData; + initData.pSysMem = &mcb; + + device->CreateBuffer(&bd, &initData, &impostorMaterialCB); + } + if (!impostorVB_POS.IsValid()) + { + const int count = 6 * 6; + + XMFLOAT3 impostorVertices_pos[count]; + XMFLOAT3 impostorVertices_nor[count]; + XMFLOAT2 impostorVertices_tex[count]; + + float stepX = 1.f / 6.f; + + // front + impostorVertices_pos[0] = XMFLOAT3(-1, 1, 0); + impostorVertices_nor[0] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[0] = XMFLOAT2(0, 0); + + impostorVertices_pos[1] = XMFLOAT3(-1, -1, 0); + impostorVertices_nor[1] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[1] = XMFLOAT2(0, 1); + + impostorVertices_pos[2] = XMFLOAT3(1, 1, 0); + impostorVertices_nor[2] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[2] = XMFLOAT2(stepX, 0); + + impostorVertices_pos[3] = XMFLOAT3(-1, -1, 0); + impostorVertices_nor[3] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[3] = XMFLOAT2(0, 1); + + impostorVertices_pos[4] = XMFLOAT3(1, -1, 0); + impostorVertices_nor[4] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[4] = XMFLOAT2(stepX, 1); + + impostorVertices_pos[5] = XMFLOAT3(1, 1, 0); + impostorVertices_nor[5] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[5] = XMFLOAT2(stepX, 0); + + // right + impostorVertices_pos[6] = XMFLOAT3(0, 1, -1); + impostorVertices_nor[6] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[6] = XMFLOAT2(stepX, 0); + + impostorVertices_pos[7] = XMFLOAT3(0, -1, -1); + impostorVertices_nor[7] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[7] = XMFLOAT2(stepX, 1); + + impostorVertices_pos[8] = XMFLOAT3(0, 1, 1); + impostorVertices_nor[8] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[8] = XMFLOAT2(stepX * 2, 0); + + impostorVertices_pos[9] = XMFLOAT3(0, -1, -1); + impostorVertices_nor[9] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[9] = XMFLOAT2(stepX, 1); + + impostorVertices_pos[10] = XMFLOAT3(0, -1, 1); + impostorVertices_nor[10] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[10] = XMFLOAT2(stepX * 2, 1); + + impostorVertices_pos[11] = XMFLOAT3(0, 1, 1); + impostorVertices_nor[11] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[11] = XMFLOAT2(stepX * 2, 0); + + // back + impostorVertices_pos[12] = XMFLOAT3(-1, 1, 0); + impostorVertices_nor[12] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[12] = XMFLOAT2(stepX * 3, 0); + + impostorVertices_pos[13] = XMFLOAT3(1, 1, 0); + impostorVertices_nor[13] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[13] = XMFLOAT2(stepX * 2, 0); + + impostorVertices_pos[14] = XMFLOAT3(-1, -1, 0); + impostorVertices_nor[14] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[14] = XMFLOAT2(stepX * 3, 1); + + impostorVertices_pos[15] = XMFLOAT3(-1, -1, 0); + impostorVertices_nor[15] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[15] = XMFLOAT2(stepX * 3, 1); + + impostorVertices_pos[16] = XMFLOAT3(1, 1, 0); + impostorVertices_nor[16] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[16] = XMFLOAT2(stepX * 2, 0); + + impostorVertices_pos[17] = XMFLOAT3(1, -1, 0); + impostorVertices_nor[17] = XMFLOAT3(0, 0, -1); + impostorVertices_tex[17] = XMFLOAT2(stepX * 2, 1); + + // left + impostorVertices_pos[18] = XMFLOAT3(0, 1, -1); + impostorVertices_nor[18] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[18] = XMFLOAT2(stepX * 4, 0); + + impostorVertices_pos[19] = XMFLOAT3(0, 1, 1); + impostorVertices_nor[19] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[19] = XMFLOAT2(stepX * 3, 0); + + impostorVertices_pos[20] = XMFLOAT3(0, -1, -1); + impostorVertices_nor[20] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[20] = XMFLOAT2(stepX * 4, 1); + + impostorVertices_pos[21] = XMFLOAT3(0, -1, -1); + impostorVertices_nor[21] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[21] = XMFLOAT2(stepX * 4, 1); + + impostorVertices_pos[22] = XMFLOAT3(0, 1, 1); + impostorVertices_nor[22] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[22] = XMFLOAT2(stepX * 3, 0); + + impostorVertices_pos[23] = XMFLOAT3(0, -1, 1); + impostorVertices_nor[23] = XMFLOAT3(1, 0, 0); + impostorVertices_tex[23] = XMFLOAT2(stepX * 3, 1); + + // bottom + impostorVertices_pos[24] = XMFLOAT3(-1, 0, 1); + impostorVertices_nor[24] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[24] = XMFLOAT2(stepX * 4, 0); + + impostorVertices_pos[25] = XMFLOAT3(1, 0, 1); + impostorVertices_nor[25] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[25] = XMFLOAT2(stepX * 5, 0); + + impostorVertices_pos[26] = XMFLOAT3(-1, 0, -1); + impostorVertices_nor[26] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[26] = XMFLOAT2(stepX * 4, 1); + + impostorVertices_pos[27] = XMFLOAT3(-1, 0, -1); + impostorVertices_nor[27] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[27] = XMFLOAT2(stepX * 4, 1); + + impostorVertices_pos[28] = XMFLOAT3(1, 0, 1); + impostorVertices_nor[28] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[28] = XMFLOAT2(stepX * 5, 0); + + impostorVertices_pos[29] = XMFLOAT3(1, 0, -1); + impostorVertices_nor[29] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[29] = XMFLOAT2(stepX * 5, 1); + + // top + impostorVertices_pos[30] = XMFLOAT3(-1, 0, 1); + impostorVertices_nor[30] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[30] = XMFLOAT2(stepX * 5, 0); + + impostorVertices_pos[31] = XMFLOAT3(-1, 0, -1); + impostorVertices_nor[31] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[31] = XMFLOAT2(stepX * 5, 1); + + impostorVertices_pos[32] = XMFLOAT3(1, 0, 1); + impostorVertices_nor[32] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[32] = XMFLOAT2(stepX * 6, 0); + + impostorVertices_pos[33] = XMFLOAT3(-1, 0, -1); + impostorVertices_nor[33] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[33] = XMFLOAT2(stepX * 5, 1); + + impostorVertices_pos[34] = XMFLOAT3(1, 0, -1); + impostorVertices_nor[34] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[34] = XMFLOAT2(stepX * 6, 1); + + impostorVertices_pos[35] = XMFLOAT3(1, 0, 1); + impostorVertices_nor[35] = XMFLOAT3(0, 1, 0); + impostorVertices_tex[35] = XMFLOAT2(stepX * 6, 0); + + + MeshComponent::Vertex_POS impostorVertices_POS[count]; + MeshComponent::Vertex_TEX impostorVertices_TEX[count]; + for (int i = 0; i < count; ++i) + { + impostorVertices_POS[i].FromFULL(impostorVertices_pos[i], impostorVertices_nor[i], 0); + impostorVertices_TEX[i].FromFULL(impostorVertices_tex[i]); + } + + + GPUBufferDesc bd; + ZeroMemory(&bd, sizeof(bd)); + bd.Usage = USAGE_IMMUTABLE; + bd.BindFlags = BIND_VERTEX_BUFFER; + bd.CPUAccessFlags = 0; + SubresourceData InitData; + ZeroMemory(&InitData, sizeof(InitData)); + InitData.pSysMem = impostorVertices_POS; + bd.ByteWidth = sizeof(impostorVertices_POS); + device->CreateBuffer(&bd, &InitData, &impostorVB_POS); + InitData.pSysMem = impostorVertices_TEX; + bd.ByteWidth = sizeof(impostorVertices_TEX); + device->CreateBuffer(&bd, &InitData, &impostorVB_TEX); + } + + for (size_t impostorID = 0; impostorID < scene.impostors.GetCount(); ++impostorID) + { + ImpostorComponent& impostor = scene.impostors[impostorID]; + if (!impostor.IsDirty()) + { + continue; + } + impostor.SetDirty(false); + + Entity entity = scene.impostors.GetEntity(impostorID); + const MeshComponent& mesh = *scene.meshes.GetComponent(entity); + + static const int res = 256; + + const AABB& bbox = mesh.aabb; + const XMFLOAT3 extents = bbox.getHalfWidth(); + if (!impostor.rendertarget.IsInitialized()) + { + impostor.rendertarget.Initialize(res * 6, res, true, RTFormat_impostor_albedo, 0); + impostor.rendertarget.Add(RTFormat_impostor_normal); // normal, roughness + impostor.rendertarget.Add(RTFormat_impostor_surface); // surface properties + } + + + CameraComponent impostorcamera; + TransformComponent camera_transform; + + BindPersistentState(threadID); + + const XMFLOAT4X4 __identity = XMFLOAT4X4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + struct InstBuf + { + Instance instance; + InstancePrev instancePrev; + }; + UINT instancesOffset; + volatile InstBuf* buff = (volatile InstBuf*)device->AllocateFromRingBuffer(&dynamicVertexBufferPools[threadID], sizeof(InstBuf), instancesOffset, threadID); + buff->instance.Create(__identity); + buff->instancePrev.Create(__identity); + device->InvalidateBufferAccess(&dynamicVertexBufferPools[threadID], threadID); + + GPUBuffer* vbs[] = { + mesh.IsSkinned() ? mesh.streamoutBuffer_POS.get() : mesh.vertexBuffer_POS.get(), + mesh.vertexBuffer_TEX.get(), + mesh.IsSkinned() ? mesh.streamoutBuffer_PRE.get() : mesh.vertexBuffer_POS.get(), + &dynamicVertexBufferPools[threadID] + }; + UINT strides[] = { + sizeof(MeshComponent::Vertex_POS), + sizeof(MeshComponent::Vertex_TEX), + sizeof(MeshComponent::Vertex_POS), + sizeof(InstBuf) + }; + UINT offsets[] = { + 0, + 0, + 0, + instancesOffset + }; + device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, offsets, threadID); + + device->BindIndexBuffer(mesh.indexBuffer.get(), mesh.GetIndexFormat(), 0, threadID); + + device->BindGraphicsPSO(PSO_captureimpostor, threadID); + + ViewPort savedViewPort = impostor.rendertarget.viewPort; + impostor.rendertarget.Activate(threadID, 0, 0, 0, 0); + for (size_t i = 0; i < 6; ++i) + { + impostor.rendertarget.viewPort.Height = (float)res; + impostor.rendertarget.viewPort.Width = (float)res; + impostor.rendertarget.viewPort.TopLeftX = (float)(i*res); + impostor.rendertarget.viewPort.TopLeftY = 0.f; + impostor.rendertarget.Set(threadID); + + camera_transform.ClearTransform(); + camera_transform.Translate(bbox.getCenter()); + switch (i) + { + case 0: + { + // front capture + XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.y, extents.y, -extents.z, extents.z); + XMStoreFloat4x4(&impostorcamera.Projection, ortho); + } + break; + case 1: + { + // right capture + XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.z, extents.z, -extents.y, extents.y, -extents.x, extents.x); + XMStoreFloat4x4(&impostorcamera.Projection, ortho); + camera_transform.RotateRollPitchYaw(XMFLOAT3(0, -XM_PIDIV2, 0)); + } + break; + case 2: + { + // back capture + XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.y, extents.y, -extents.z, extents.z); + XMStoreFloat4x4(&impostorcamera.Projection, ortho); + camera_transform.RotateRollPitchYaw(XMFLOAT3(0, -XM_PI, 0)); + } + break; + case 3: + { + // left capture + XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.z, extents.z, -extents.y, extents.y, -extents.x, extents.x); + XMStoreFloat4x4(&impostorcamera.Projection, ortho); + camera_transform.RotateRollPitchYaw(XMFLOAT3(0, XM_PIDIV2, 0)); + } + break; + case 4: + { + // bottom capture + XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.z, extents.z, -extents.y, extents.y); + XMStoreFloat4x4(&impostorcamera.Projection, ortho); + camera_transform.RotateRollPitchYaw(XMFLOAT3(-XM_PIDIV2, 0, 0)); + } + break; + case 5: + { + // top capture + XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.z, extents.z, -extents.y, extents.y); + XMStoreFloat4x4(&impostorcamera.Projection, ortho); + camera_transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); + } + break; + default: + break; + } + camera_transform.UpdateTransform(); + impostorcamera.UpdateCamera(&camera_transform); + impostorcamera.UpdateProjection(); + UpdateCameraCB(impostorcamera, threadID); + + for (auto& subset : mesh.subsets) + { + if (subset.indexCount == 0) + { + continue; + } + MaterialComponent& material = *GetScene().materials.GetComponent(subset.materialID); + + device->BindConstantBuffer(PS, material.constantBuffer.get(), CB_GETBINDSLOT(MaterialCB), threadID); + + device->BindResource(PS, material.GetBaseColorMap(), TEXSLOT_ONDEMAND0, threadID); + device->BindResource(PS, material.GetNormalMap(), TEXSLOT_ONDEMAND1, threadID); + device->BindResource(PS, material.GetSurfaceMap(), TEXSLOT_ONDEMAND2, threadID); + + device->DrawIndexedInstanced((int)subset.indexCount, 1, subset.indexOffset, 0, 0, threadID); + + } + + } + GenerateMipChain(impostor.rendertarget.GetTexture(), MIPGENFILTER_LINEAR, threadID); + + impostor.rendertarget.viewPort = savedViewPort; + } + + UpdateCameraCB(GetCamera(), threadID); + + device->EventEnd(threadID); + } } void VoxelRadiance(GRAPHICSTHREAD threadID) @@ -7934,367 +8329,6 @@ RayIntersectWorldResult RayIntersectWorld(const RAY& ray, UINT renderTypeMask, u return result; } -void CreateImpostor(Entity entity, GRAPHICSTHREAD threadID) -{ - GraphicsDevice* device = GetDevice(); - - if (!impostorMaterialCB.IsValid()) - { - MaterialCB mcb; - ZeroMemory(&mcb, sizeof(mcb)); - mcb.g_xMat_baseColor = XMFLOAT4(1, 1, 1, 1); - mcb.g_xMat_texMulAdd = XMFLOAT4(1, 1, 0, 0); - mcb.g_xMat_normalMapStrength = 1.0f; - mcb.g_xMat_roughness = 1.0f; - mcb.g_xMat_reflectance = 1.0f; - mcb.g_xMat_metalness = 1.0f; - - GPUBufferDesc bd; - bd.BindFlags = BIND_CONSTANT_BUFFER; - bd.Usage = USAGE_IMMUTABLE; - bd.CPUAccessFlags = 0; - bd.ByteWidth = sizeof(MaterialCB); - SubresourceData initData; - initData.pSysMem = &mcb; - - device->CreateBuffer(&bd, &initData, &impostorMaterialCB); - } - if (!impostorVB_POS.IsValid()) - { - const int count = 6 * 6; - - XMFLOAT3 impostorVertices_pos[count]; - XMFLOAT3 impostorVertices_nor[count]; - XMFLOAT2 impostorVertices_tex[count]; - - float stepX = 1.f / 6.f; - - // front - impostorVertices_pos[0] = XMFLOAT3(-1, 1, 0); - impostorVertices_nor[0] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[0] = XMFLOAT2(0, 0); - - impostorVertices_pos[1] = XMFLOAT3(-1, -1, 0); - impostorVertices_nor[1] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[1] = XMFLOAT2(0, 1); - - impostorVertices_pos[2] = XMFLOAT3(1, 1, 0); - impostorVertices_nor[2] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[2] = XMFLOAT2(stepX, 0); - - impostorVertices_pos[3] = XMFLOAT3(-1, -1, 0); - impostorVertices_nor[3] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[3] = XMFLOAT2(0, 1); - - impostorVertices_pos[4] = XMFLOAT3(1, -1, 0); - impostorVertices_nor[4] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[4] = XMFLOAT2(stepX, 1); - - impostorVertices_pos[5] = XMFLOAT3(1, 1, 0); - impostorVertices_nor[5] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[5] = XMFLOAT2(stepX, 0); - - // right - impostorVertices_pos[6] = XMFLOAT3(0, 1, -1); - impostorVertices_nor[6] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[6] = XMFLOAT2(stepX, 0); - - impostorVertices_pos[7] = XMFLOAT3(0, -1, -1); - impostorVertices_nor[7] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[7] = XMFLOAT2(stepX, 1); - - impostorVertices_pos[8] = XMFLOAT3(0, 1, 1); - impostorVertices_nor[8] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[8] = XMFLOAT2(stepX * 2, 0); - - impostorVertices_pos[9] = XMFLOAT3(0, -1, -1); - impostorVertices_nor[9] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[9] = XMFLOAT2(stepX, 1); - - impostorVertices_pos[10] = XMFLOAT3(0, -1, 1); - impostorVertices_nor[10] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[10] = XMFLOAT2(stepX * 2, 1); - - impostorVertices_pos[11] = XMFLOAT3(0, 1, 1); - impostorVertices_nor[11] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[11] = XMFLOAT2(stepX * 2, 0); - - // back - impostorVertices_pos[12] = XMFLOAT3(-1, 1, 0); - impostorVertices_nor[12] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[12] = XMFLOAT2(stepX * 3, 0); - - impostorVertices_pos[13] = XMFLOAT3(1, 1, 0); - impostorVertices_nor[13] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[13] = XMFLOAT2(stepX * 2, 0); - - impostorVertices_pos[14] = XMFLOAT3(-1, -1, 0); - impostorVertices_nor[14] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[14] = XMFLOAT2(stepX * 3, 1); - - impostorVertices_pos[15] = XMFLOAT3(-1, -1, 0); - impostorVertices_nor[15] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[15] = XMFLOAT2(stepX * 3, 1); - - impostorVertices_pos[16] = XMFLOAT3(1, 1, 0); - impostorVertices_nor[16] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[16] = XMFLOAT2(stepX * 2, 0); - - impostorVertices_pos[17] = XMFLOAT3(1, -1, 0); - impostorVertices_nor[17] = XMFLOAT3(0, 0, -1); - impostorVertices_tex[17] = XMFLOAT2(stepX * 2, 1); - - // left - impostorVertices_pos[18] = XMFLOAT3(0, 1, -1); - impostorVertices_nor[18] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[18] = XMFLOAT2(stepX * 4, 0); - - impostorVertices_pos[19] = XMFLOAT3(0, 1, 1); - impostorVertices_nor[19] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[19] = XMFLOAT2(stepX * 3, 0); - - impostorVertices_pos[20] = XMFLOAT3(0, -1, -1); - impostorVertices_nor[20] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[20] = XMFLOAT2(stepX * 4, 1); - - impostorVertices_pos[21] = XMFLOAT3(0, -1, -1); - impostorVertices_nor[21] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[21] = XMFLOAT2(stepX * 4, 1); - - impostorVertices_pos[22] = XMFLOAT3(0, 1, 1); - impostorVertices_nor[22] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[22] = XMFLOAT2(stepX * 3, 0); - - impostorVertices_pos[23] = XMFLOAT3(0, -1, 1); - impostorVertices_nor[23] = XMFLOAT3(1, 0, 0); - impostorVertices_tex[23] = XMFLOAT2(stepX * 3, 1); - - // bottom - impostorVertices_pos[24] = XMFLOAT3(-1, 0, 1); - impostorVertices_nor[24] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[24] = XMFLOAT2(stepX * 4, 0); - - impostorVertices_pos[25] = XMFLOAT3(1, 0, 1); - impostorVertices_nor[25] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[25] = XMFLOAT2(stepX * 5, 0); - - impostorVertices_pos[26] = XMFLOAT3(-1, 0, -1); - impostorVertices_nor[26] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[26] = XMFLOAT2(stepX * 4, 1); - - impostorVertices_pos[27] = XMFLOAT3(-1, 0, -1); - impostorVertices_nor[27] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[27] = XMFLOAT2(stepX * 4, 1); - - impostorVertices_pos[28] = XMFLOAT3(1, 0, 1); - impostorVertices_nor[28] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[28] = XMFLOAT2(stepX * 5, 0); - - impostorVertices_pos[29] = XMFLOAT3(1, 0, -1); - impostorVertices_nor[29] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[29] = XMFLOAT2(stepX * 5, 1); - - // top - impostorVertices_pos[30] = XMFLOAT3(-1, 0, 1); - impostorVertices_nor[30] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[30] = XMFLOAT2(stepX * 5, 0); - - impostorVertices_pos[31] = XMFLOAT3(-1, 0, -1); - impostorVertices_nor[31] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[31] = XMFLOAT2(stepX * 5, 1); - - impostorVertices_pos[32] = XMFLOAT3(1, 0, 1); - impostorVertices_nor[32] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[32] = XMFLOAT2(stepX * 6, 0); - - impostorVertices_pos[33] = XMFLOAT3(-1, 0, -1); - impostorVertices_nor[33] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[33] = XMFLOAT2(stepX * 5, 1); - - impostorVertices_pos[34] = XMFLOAT3(1, 0, -1); - impostorVertices_nor[34] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[34] = XMFLOAT2(stepX * 6, 1); - - impostorVertices_pos[35] = XMFLOAT3(1, 0, 1); - impostorVertices_nor[35] = XMFLOAT3(0, 1, 0); - impostorVertices_tex[35] = XMFLOAT2(stepX * 6, 0); - - - MeshComponent::Vertex_POS impostorVertices_POS[count]; - MeshComponent::Vertex_TEX impostorVertices_TEX[count]; - for (int i = 0; i < count; ++i) - { - impostorVertices_POS[i].FromFULL(impostorVertices_pos[i], impostorVertices_nor[i], 0); - impostorVertices_TEX[i].FromFULL(impostorVertices_tex[i]); - } - - - GPUBufferDesc bd; - ZeroMemory(&bd, sizeof(bd)); - bd.Usage = USAGE_IMMUTABLE; - bd.BindFlags = BIND_VERTEX_BUFFER; - bd.CPUAccessFlags = 0; - SubresourceData InitData; - ZeroMemory(&InitData, sizeof(InitData)); - InitData.pSysMem = impostorVertices_POS; - bd.ByteWidth = sizeof(impostorVertices_POS); - device->CreateBuffer(&bd, &InitData, &impostorVB_POS); - InitData.pSysMem = impostorVertices_TEX; - bd.ByteWidth = sizeof(impostorVertices_TEX); - device->CreateBuffer(&bd, &InitData, &impostorVB_TEX); - } - - Scene& scene = GetScene(); - - MeshComponent& mesh = *scene.meshes.GetComponent(entity); - - static const int res = 256; - - const AABB& bbox = mesh.aabb; - const XMFLOAT3 extents = bbox.getHalfWidth(); - if (!mesh.impostorTarget.IsInitialized()) - { - mesh.impostorTarget.Initialize(res * 6, res, true, RTFormat_impostor_albedo, 0); - mesh.impostorTarget.Add(RTFormat_impostor_normal); // normal, roughness - mesh.impostorTarget.Add(RTFormat_impostor_surface); // surface properties - } - - - CameraComponent impostorcamera; - TransformComponent camera_transform; - - BindPersistentState(threadID); - - const XMFLOAT4X4 __identity = XMFLOAT4X4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - struct InstBuf - { - Instance instance; - InstancePrev instancePrev; - }; - UINT instancesOffset; - volatile InstBuf* buff = (volatile InstBuf*)device->AllocateFromRingBuffer(&dynamicVertexBufferPools[threadID], sizeof(InstBuf), instancesOffset, threadID); - buff->instance.Create(__identity); - buff->instancePrev.Create(__identity); - device->InvalidateBufferAccess(&dynamicVertexBufferPools[threadID], threadID); - - GPUBuffer* vbs[] = { - mesh.IsSkinned() ? mesh.streamoutBuffer_POS.get() : mesh.vertexBuffer_POS.get(), - mesh.vertexBuffer_TEX.get(), - mesh.IsSkinned() ? mesh.streamoutBuffer_PRE.get() : mesh.vertexBuffer_POS.get(), - &dynamicVertexBufferPools[threadID] - }; - UINT strides[] = { - sizeof(MeshComponent::Vertex_POS), - sizeof(MeshComponent::Vertex_TEX), - sizeof(MeshComponent::Vertex_POS), - sizeof(InstBuf) - }; - UINT offsets[] = { - 0, - 0, - 0, - instancesOffset - }; - device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, offsets, threadID); - - device->BindIndexBuffer(mesh.indexBuffer.get(), mesh.GetIndexFormat(), 0, threadID); - - device->BindGraphicsPSO(PSO_captureimpostor, threadID); - - ViewPort savedViewPort = mesh.impostorTarget.viewPort; - mesh.impostorTarget.Activate(threadID, 0, 0, 0, 0); - for (size_t i = 0; i < 6; ++i) - { - mesh.impostorTarget.viewPort.Height = (float)res; - mesh.impostorTarget.viewPort.Width = (float)res; - mesh.impostorTarget.viewPort.TopLeftX = (float)(i*res); - mesh.impostorTarget.viewPort.TopLeftY = 0.f; - mesh.impostorTarget.Set(threadID); - - camera_transform.ClearTransform(); - camera_transform.Translate(bbox.getCenter()); - switch (i) - { - case 0: - { - // front capture - XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.y, extents.y, -extents.z, extents.z); - XMStoreFloat4x4(&impostorcamera.Projection, ortho); - } - break; - case 1: - { - // right capture - XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.z, extents.z, -extents.y, extents.y, -extents.x, extents.x); - XMStoreFloat4x4(&impostorcamera.Projection, ortho); - camera_transform.RotateRollPitchYaw(XMFLOAT3(0, -XM_PIDIV2, 0)); - } - break; - case 2: - { - // back capture - XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.y, extents.y, -extents.z, extents.z); - XMStoreFloat4x4(&impostorcamera.Projection, ortho); - camera_transform.RotateRollPitchYaw(XMFLOAT3(0, -XM_PI, 0)); - } - break; - case 3: - { - // left capture - XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.z, extents.z, -extents.y, extents.y, -extents.x, extents.x); - XMStoreFloat4x4(&impostorcamera.Projection, ortho); - camera_transform.RotateRollPitchYaw(XMFLOAT3(0, XM_PIDIV2, 0)); - } - break; - case 4: - { - // bottom capture - XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.z, extents.z, -extents.y, extents.y); - XMStoreFloat4x4(&impostorcamera.Projection, ortho); - camera_transform.RotateRollPitchYaw(XMFLOAT3(-XM_PIDIV2, 0, 0)); - } - break; - case 5: - { - // top capture - XMMATRIX ortho = XMMatrixOrthographicOffCenterLH(-extents.x, extents.x, -extents.z, extents.z, -extents.y, extents.y); - XMStoreFloat4x4(&impostorcamera.Projection, ortho); - camera_transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); - } - break; - default: - break; - } - camera_transform.UpdateTransform(); - impostorcamera.UpdateCamera(&camera_transform); - impostorcamera.UpdateProjection(); - UpdateCameraCB(impostorcamera, threadID); - - for (MeshComponent::MeshSubset& subset : mesh.subsets) - { - if (subset.indexCount == 0) - { - continue; - } - MaterialComponent& material = *GetScene().materials.GetComponent(subset.materialID); - - device->BindConstantBuffer(PS, material.constantBuffer.get(), CB_GETBINDSLOT(MaterialCB), threadID); - - device->BindResource(PS, material.GetBaseColorMap(), TEXSLOT_ONDEMAND0, threadID); - device->BindResource(PS, material.GetNormalMap(), TEXSLOT_ONDEMAND1, threadID); - device->BindResource(PS, material.GetSurfaceMap(), TEXSLOT_ONDEMAND2, threadID); - - device->DrawIndexedInstanced((int)subset.indexCount, 1, subset.indexOffset, 0, 0, threadID); - - } - - } - GenerateMipChain(mesh.impostorTarget.GetTexture(), MIPGENFILTER_LINEAR, threadID); - - mesh.impostorTarget.viewPort = savedViewPort; - UpdateCameraCB(GetCamera(), threadID); -} - void AddRenderableBox(const XMFLOAT4X4& boxMatrix, const XMFLOAT4& color) { renderableBoxes.push_back(pair(boxMatrix,color)); diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 6c583296a..9cff0c54e 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -99,6 +99,7 @@ namespace wiRenderer void DrawLensFlares(GRAPHICSTHREAD threadID); void DrawDecals(const wiSceneSystem::CameraComponent& camera, GRAPHICSTHREAD threadID); void RefreshEnvProbes(GRAPHICSTHREAD threadID); + void RefreshImpostors(GRAPHICSTHREAD threadID); void VoxelRadiance(GRAPHICSTHREAD threadID); void ComputeTiledLightCulling(bool deferred, GRAPHICSTHREAD threadID); void ResolveMSAADepthBuffer(wiGraphicsTypes::Texture2D* dst, wiGraphicsTypes::Texture2D* src, GRAPHICSTHREAD threadID); @@ -138,7 +139,6 @@ namespace wiRenderer void GenerateClouds(wiGraphicsTypes::Texture2D* dst, UINT refinementCount, float randomness, GRAPHICSTHREAD threadID); void ManageDecalAtlas(GRAPHICSTHREAD threadID); - void CreateImpostor(wiECS::Entity, GRAPHICSTHREAD threadID); void PutWaterRipple(const std::string& image, const XMFLOAT3& pos); void ManageWaterRipples(); diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 440b1a488..9d68d2233 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -824,7 +824,9 @@ namespace wiSceneSystem RunMaterialUpdateSystem(materials, dt); - RunObjectUpdateSystem(transforms, meshes, materials, objects, aabb_objects, bounds, waterPlane); + RunImpostorUpdateSystem(impostors); + + RunObjectUpdateSystem(transforms, meshes, materials, objects, aabb_objects, impostors, bounds, waterPlane); RunCameraUpdateSystem(transforms, cameras); @@ -847,6 +849,7 @@ namespace wiSceneSystem hierarchy.Clear(); materials.Clear(); meshes.Clear(); + impostors.Clear(); objects.Clear(); aabb_objects.Clear(); rigidbodies.Clear(); @@ -874,6 +877,7 @@ namespace wiSceneSystem hierarchy.Merge(other.hierarchy); materials.Merge(other.materials); meshes.Merge(other.meshes); + impostors.Merge(other.impostors); objects.Merge(other.objects); aabb_objects.Merge(other.aabb_objects); rigidbodies.Merge(other.rigidbodies); @@ -906,6 +910,7 @@ namespace wiSceneSystem entityCount = max(entityCount, hierarchy.GetCount()); entityCount = max(entityCount, materials.GetCount()); entityCount = max(entityCount, meshes.GetCount()); + entityCount = max(entityCount, impostors.GetCount()); entityCount = max(entityCount, objects.GetCount()); entityCount = max(entityCount, aabb_objects.GetCount()); entityCount = max(entityCount, rigidbodies.GetCount()); @@ -934,6 +939,7 @@ namespace wiSceneSystem hierarchy.Remove_KeepSorted(entity); materials.Remove(entity); meshes.Remove(entity); + impostors.Remove(entity); objects.Remove(entity); aabb_objects.Remove(entity); rigidbodies.Remove(entity); @@ -1500,12 +1506,22 @@ namespace wiSceneSystem } } + void RunImpostorUpdateSystem(ComponentManager& impostors) + { + for (size_t i = 0; i < impostors.GetCount(); ++i) + { + ImpostorComponent& impostor = impostors[i]; + impostor.aabb = AABB(); + impostor.instanceMatrices.clear(); + } + } void RunObjectUpdateSystem( const ComponentManager& transforms, const ComponentManager& meshes, const ComponentManager& materials, ComponentManager& objects, ComponentManager& aabb_objects, + ComponentManager& impostors, AABB& sceneBounds, XMFLOAT4& waterPlane ) @@ -1523,6 +1539,7 @@ namespace wiSceneSystem object.rendertypeMask = 0; object.SetDynamic(false); object.SetCastShadow(false); + object.SetImpostorPlacement(false); if (object.meshID != INVALID_ENTITY) { @@ -1535,7 +1552,12 @@ namespace wiSceneSystem aabb = mesh->aabb.get(transform->world); sceneBounds = AABB::Merge(sceneBounds, aabb); - object.position = transform->GetPosition(); + // This is instance bounding box matrix: + XMFLOAT4X4 meshMatrix; + XMStoreFloat4x4(&meshMatrix, mesh->aabb.getAsBoxMatrix() * XMLoadFloat4x4(&transform->world)); + + // We need sometimes the center of the instance bounding box, not the transform position (which can be outside the bounding box) + object.center = *((XMFLOAT3*)&meshMatrix._41); if (mesh->IsSkinned() || mesh->IsDynamic()) { @@ -1568,6 +1590,18 @@ namespace wiSceneSystem object.SetCastShadow(material->IsCastingShadow()); } } + + ImpostorComponent* impostor = impostors.GetComponent(object.meshID); + if (impostor != nullptr) + { + object.SetImpostorPlacement(true); + object.impostorSwapDistance = impostor->swapInDistance; + object.impostorFadeThresholdRadius = aabb.getRadius(); + + impostor->aabb = AABB::Merge(impostor->aabb, aabb); + impostor->fadeThresholdRadius = object.impostorFadeThresholdRadius; + impostor->instanceMatrices.push_back(meshMatrix); + } } } } diff --git a/WickedEngine/wiSceneSystem.h b/WickedEngine/wiSceneSystem.h index beb284035..833f289b9 100644 --- a/WickedEngine/wiSceneSystem.h +++ b/WickedEngine/wiSceneSystem.h @@ -160,9 +160,7 @@ namespace wiSceneSystem inline float GetOpacity() const { return baseColor.w; } - - inline void SetDirty() { _flags |= DIRTY; } - inline void SetClean() { _flags &= ~DIRTY; } + inline void SetDirty(bool value = true) { if (value) { _flags |= DIRTY; } else { _flags &= ~DIRTY; } } inline bool IsDirty() const { return _flags & DIRTY; } inline void SetCastShadow(bool value) { if (value) { _flags |= CAST_SHADOW; } else { _flags &= ~CAST_SHADOW; } } @@ -219,7 +217,6 @@ namespace wiSceneSystem std::vector subsets; float tessellationFactor = 0.0f; - float impostorDistance = 100.0f; wiECS::Entity armatureID = wiECS::INVALID_ENTITY; // Non-serialized attributes: @@ -232,7 +229,6 @@ namespace wiSceneSystem std::unique_ptr vertexBuffer_ATL; std::unique_ptr streamoutBuffer_POS; std::unique_ptr streamoutBuffer_PRE; - wiRenderTarget impostorTarget; inline void SetRenderable(bool value) { if (value) { _flags |= RENDERABLE; } else { _flags &= ~RENDERABLE; } } @@ -243,7 +239,6 @@ namespace wiSceneSystem inline bool IsDoubleSided() const { return _flags & DOUBLE_SIDED; } inline bool IsDynamic() const { return _flags & DYNAMIC; } - bool HasImpostor() const { return impostorTarget.IsInitialized(); } inline float GetTessellationFactor() const { return tessellationFactor; } inline wiGraphicsTypes::INDEXBUFFER_FORMAT GetIndexFormat() const { return vertex_positions.size() > 65535 ? wiGraphicsTypes::INDEXFORMAT_32BIT : wiGraphicsTypes::INDEXFORMAT_16BIT; } inline bool IsSkinned() const { return armatureID != wiECS::INVALID_ENTITY; } @@ -369,6 +364,29 @@ namespace wiSceneSystem }; + struct ImpostorComponent + { + enum FLAGS + { + EMPTY = 0, + DIRTY = 1 << 0, + }; + uint32_t _flags = DIRTY; + + float swapInDistance = 100.0f; + + // Non-serialized attributes: + AABB aabb; + wiRenderTarget rendertarget; // todo: combine all impostors into atlas/texture2darray + float fadeThresholdRadius; + std::vector instanceMatrices; + + inline void SetDirty(bool value = true) { if (value) { _flags |= DIRTY; } else { _flags &= ~DIRTY; } } + inline bool IsDirty() const { return _flags & DIRTY; } + + void Serialize(wiArchive& archive, uint32_t seed = 0); + }; + struct ObjectComponent { enum FLAGS @@ -377,6 +395,7 @@ namespace wiSceneSystem RENDERABLE = 1 << 0, CAST_SHADOW = 1 << 1, DYNAMIC = 1 << 2, + IMPOSTOR_PLACEMENT = 1 << 3, }; uint32_t _flags = RENDERABLE | CAST_SHADOW; @@ -387,7 +406,9 @@ namespace wiSceneSystem // Non-serialized attributes: - XMFLOAT3 position = XMFLOAT3(0, 0, 0); + XMFLOAT3 center = XMFLOAT3(0, 0, 0); + float impostorFadeThresholdRadius; + float impostorSwapDistance; // occlusion result history bitfield (32 bit->32 frame history) uint32_t occlusionHistory = ~0; @@ -406,10 +427,12 @@ namespace wiSceneSystem inline void SetRenderable(bool value) { if (value) { _flags |= RENDERABLE; } else { _flags &= ~RENDERABLE; } } inline void SetCastShadow(bool value) { if (value) { _flags |= CAST_SHADOW; } else { _flags &= ~CAST_SHADOW; } } inline void SetDynamic(bool value) { if (value) { _flags |= DYNAMIC; } else { _flags &= ~DYNAMIC; } } + inline void SetImpostorPlacement(bool value) { if (value) { _flags |= IMPOSTOR_PLACEMENT; } else { _flags &= ~IMPOSTOR_PLACEMENT; } } inline bool IsRenderable() const { return _flags & RENDERABLE; } inline bool IsCastingShadow() const { return _flags & CAST_SHADOW; } inline bool IsDynamic() const { return _flags & DYNAMIC; } + inline bool IsImpostorPlacement() const { return _flags & IMPOSTOR_PLACEMENT; } inline float GetTransparency() const { return 1 - color.w; } inline uint32_t GetRenderTypes() const { return rendertypeMask; } @@ -884,6 +907,7 @@ namespace wiSceneSystem wiECS::ComponentManager hierarchy; wiECS::ComponentManager materials; wiECS::ComponentManager meshes; + wiECS::ComponentManager impostors; wiECS::ComponentManager objects; wiECS::ComponentManager aabb_objects; wiECS::ComponentManager rigidbodies; @@ -1001,12 +1025,14 @@ namespace wiSceneSystem wiECS::ComponentManager& armatures ); void RunMaterialUpdateSystem(wiECS::ComponentManager& materials, float dt); + void RunImpostorUpdateSystem(wiECS::ComponentManager& impostors); void RunObjectUpdateSystem( const wiECS::ComponentManager& transforms, const wiECS::ComponentManager& meshes, const wiECS::ComponentManager& materials, wiECS::ComponentManager& objects, wiECS::ComponentManager& aabb_objects, + wiECS::ComponentManager& impostors, AABB& sceneBounds, XMFLOAT4& waterPlane ); diff --git a/WickedEngine/wiSceneSystem_Decl.h b/WickedEngine/wiSceneSystem_Decl.h index d339822de..05066697c 100644 --- a/WickedEngine/wiSceneSystem_Decl.h +++ b/WickedEngine/wiSceneSystem_Decl.h @@ -10,6 +10,7 @@ namespace wiSceneSystem struct HierarchyComponent; struct MaterialComponent; struct MeshComponent; + struct ImpostorComponent; struct ObjectComponent; struct RigidBodyPhysicsComponent; struct SoftBodyPhysicsComponent; diff --git a/WickedEngine/wiSceneSystem_Serializers.cpp b/WickedEngine/wiSceneSystem_Serializers.cpp index 8dddd5be6..39b89cac9 100644 --- a/WickedEngine/wiSceneSystem_Serializers.cpp +++ b/WickedEngine/wiSceneSystem_Serializers.cpp @@ -173,7 +173,6 @@ namespace wiSceneSystem } archive >> tessellationFactor; - archive >> impostorDistance; SerializeEntity(archive, armatureID, seed); CreateRenderData(); @@ -199,11 +198,25 @@ namespace wiSceneSystem } archive << tessellationFactor; - archive << impostorDistance; SerializeEntity(archive, armatureID, seed); } } + void ImpostorComponent::Serialize(wiArchive& archive, uint32_t seed) + { + if (archive.IsReadMode()) + { + archive >> _flags; + archive >> swapInDistance; + + SetDirty(); + } + else + { + archive << _flags; + archive << swapInDistance; + } + } void ObjectComponent::Serialize(wiArchive& archive, uint32_t seed) { if (archive.IsReadMode()) @@ -512,6 +525,7 @@ namespace wiSceneSystem hierarchy.Serialize(archive, seed); materials.Serialize(archive, seed); meshes.Serialize(archive, seed); + impostors.Serialize(archive, seed); objects.Serialize(archive, seed); aabb_objects.Serialize(archive, seed); rigidbodies.Serialize(archive, seed); @@ -602,6 +616,15 @@ namespace wiSceneSystem component.Serialize(archive, propagateSeedDeep ? seed : 0); } } + { + bool component_exists; + archive >> component_exists; + if (component_exists) + { + auto& component = impostors.Create(entity); + component.Serialize(archive, propagateSeedDeep ? seed : 0); + } + } { bool component_exists; archive >> component_exists; @@ -843,6 +866,18 @@ namespace wiSceneSystem archive << false; } } + { + auto component = impostors.GetComponent(entity); + if (component != nullptr) + { + archive << true; + component->Serialize(archive, seed); + } + else + { + archive << false; + } + } { auto component = objects.GetComponent(entity); if (component != nullptr)