diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 6804152e7d..fa0ca5a835 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -199,16 +199,18 @@ struct RenderBatch uint32_t meshIndex; uint32_t instanceIndex; uint16_t distance; - uint16_t camera_mask; + uint8_t camera_mask; + uint8_t lod_override; // if overriding the base object LOD is needed, specify less than 0xFF in this uint32_t sort_bits; // an additional bitmask for sorting only, it should be used to reduce pipeline changes - inline void Create(uint32_t meshIndex, uint32_t instanceIndex, float distance, uint32_t sort_bits, uint16_t camera_mask = 0xFFFF) + inline void Create(uint32_t meshIndex, uint32_t instanceIndex, float distance, uint32_t sort_bits, uint8_t camera_mask = 0xFF, uint8_t lod_override = 0xFF) { this->meshIndex = meshIndex; this->instanceIndex = instanceIndex; this->distance = XMConvertFloatToHalf(distance); this->sort_bits = sort_bits; this->camera_mask = camera_mask; + this->lod_override = lod_override; } inline float GetDistance() const @@ -290,9 +292,9 @@ struct RenderQueue { batches.clear(); } - inline void add(uint32_t meshIndex, uint32_t instanceIndex, float distance, uint32_t sort_bits, uint16_t camera_mask = 0xFFFF) + inline void add(uint32_t meshIndex, uint32_t instanceIndex, float distance, uint32_t sort_bits, uint8_t camera_mask = 0xFF, uint8_t lod_override = 0xFF) { - batches.emplace_back().Create(meshIndex, instanceIndex, distance, sort_bits, camera_mask); + batches.emplace_back().Create(meshIndex, instanceIndex, distance, sort_bits, camera_mask, lod_override); } inline void sort_transparent() { @@ -2918,8 +2920,8 @@ void RenderMeshes( uint32_t dataOffset = 0; uint8_t userStencilRefOverride = 0; bool forceAlphatestForDithering = false; + uint8_t lod = 0; AABB aabb; - uint32_t lod = 0; } instancedBatch = {}; uint32_t prev_stencilref = STENCILREF_DEFAULT; @@ -3116,11 +3118,12 @@ void RenderMeshes( const ObjectComponent& instance = vis.scene->objects[instanceIndex]; const AABB& instanceAABB = vis.scene->aabb_objects[instanceIndex]; const uint8_t userStencilRefOverride = instance.userStencilRef; + const uint8_t lod = batch.lod_override == 0xFF ? (uint8_t)instance.lod : batch.lod_override; // When we encounter a new mesh inside the global instance array, we begin a new RenderBatch: if (meshIndex != instancedBatch.meshIndex || userStencilRefOverride != instancedBatch.userStencilRefOverride || - instance.lod != instancedBatch.lod + lod != instancedBatch.lod ) { batch_flush(); @@ -3132,7 +3135,7 @@ void RenderMeshes( instancedBatch.userStencilRefOverride = userStencilRefOverride; instancedBatch.forceAlphatestForDithering = 0; instancedBatch.aabb = AABB(); - instancedBatch.lod = instance.lod; + instancedBatch.lod = lod; } const float dither = std::max(instance.GetTransparency(), std::max(0.0f, batch.GetDistance() - instance.fadeDistance) / instance.radius); @@ -6171,18 +6174,21 @@ void DrawShadowmaps( if (object.IsRenderable() && object.IsCastingShadow()) { // Determine which cascades the object is contained in: - uint16_t camera_mask = 0; + uint8_t camera_mask = 0; + uint8_t shadow_lod = 0xFF; for (uint32_t cascade = 0; cascade < cascade_count; ++cascade) { if ((cascade < (cascade_count - object.cascadeMask)) && shcams[cascade].frustum.CheckBoxFast(aabb)) { camera_mask |= 1 << cascade; + uint8_t candidate_lod = (uint8_t)vis.scene->ComputeObjectLODForView(object, aabb, vis.scene->meshes[object.mesh_index], shcams[cascade].view_projection); + shadow_lod = std::min(shadow_lod, candidate_lod); } } if (camera_mask == 0) continue; - renderQueue.add(object.mesh_index, uint32_t(i), 0, object.sort_bits, camera_mask); + renderQueue.add(object.mesh_index, uint32_t(i), 0, object.sort_bits, camera_mask, shadow_lod); const uint32_t filterMask = object.GetFilterMask(); if (filterMask & FILTER_TRANSPARENT || filterMask & FILTER_WATER) @@ -6288,7 +6294,11 @@ void DrawShadowmaps( const ObjectComponent& object = vis.scene->objects[i]; if (object.IsRenderable() && object.IsCastingShadow()) { - renderQueue.add(object.mesh_index, uint32_t(i), 0, object.sort_bits); + uint8_t shadow_lod = 0xFF; + uint8_t candidate_lod = (uint8_t)vis.scene->ComputeObjectLODForView(object, aabb, vis.scene->meshes[object.mesh_index], shcam.view_projection); + shadow_lod = std::min(shadow_lod, candidate_lod); + + renderQueue.add(object.mesh_index, uint32_t(i), 0, object.sort_bits, 0xFF, shadow_lod); const uint32_t filterMask = object.GetFilterMask(); if (filterMask & FILTER_TRANSPARENT || filterMask & FILTER_WATER) @@ -6437,18 +6447,21 @@ void DrawShadowmaps( if (object.IsRenderable() && object.IsCastingShadow()) { // Check for each frustum, if object is visible from it: - uint16_t camera_mask = 0; + uint8_t camera_mask = 0; + uint8_t shadow_lod = 0xFF; for (uint32_t camera_index = 0; camera_index < camera_count; ++camera_index) { if (frusta[camera_index].CheckBoxFast(aabb)) { camera_mask |= 1 << camera_index; + uint8_t candidate_lod = (uint8_t)vis.scene->ComputeObjectLODForView(object, aabb, vis.scene->meshes[object.mesh_index], cameras[camera_index].view_projection); + shadow_lod = std::min(shadow_lod, candidate_lod); } } if (camera_mask == 0) continue; - renderQueue.add(object.mesh_index, uint32_t(i), 0, object.sort_bits, camera_mask); + renderQueue.add(object.mesh_index, uint32_t(i), 0, object.sort_bits, camera_mask, shadow_lod); const uint32_t filterMask = object.GetFilterMask(); if (filterMask & FILTER_TRANSPARENT || filterMask & FILTER_WATER) @@ -6544,7 +6557,7 @@ void DrawShadowmaps( const ObjectComponent& object = vis.scene->objects[i]; if (object.IsRenderable()) { - uint16_t camera_mask = 0; + uint8_t camera_mask = 0; if (shcam.frustum.CheckBoxFast(aabb)) { camera_mask |= 1 << 0; @@ -8649,7 +8662,7 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) const ObjectComponent& object = vis.scene->objects[i]; if (object.IsRenderable() && !object.IsNotVisibleInReflections()) { - uint16_t camera_mask = 0; + uint8_t camera_mask = 0; for (uint32_t camera_index = 0; camera_index < arraysize(cameras); ++camera_index) { if (cameras[camera_index].frustum.CheckBoxFast(aabb)) diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 23786ebbd1..115bc138f4 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -4405,14 +4405,7 @@ namespace wi::scene // LOD select: if (mesh.subsets_per_lod > 0) { - // LOD selection based on screen projection: - XMFLOAT4 rect = aabb.ProjectToScreen(camera.GetViewProjection()); - float width = rect.z - rect.x; - float height = rect.w - rect.y; - float maxdim = std::max(width, height); - float lod_max = float(mesh.GetLODCount() - 1); - float lod = clamp(std::log2(1.0f / maxdim) + object.lod_bias, 0.0f, lod_max); - object.lod = uint32_t(lod); + object.lod = ComputeObjectLODForView(object, aabb, mesh, camera.GetViewProjection()); } union SortBits @@ -7172,6 +7165,17 @@ namespace wi::scene return ocean.GetDisplacedPosition(worldPosition); } + uint32_t Scene::ComputeObjectLODForView(const ObjectComponent& object, const AABB& aabb, const MeshComponent& mesh, const XMMATRIX& ViewProjection) const + { + XMFLOAT4 rect = aabb.ProjectToScreen(ViewProjection); + float width = rect.z - rect.x; + float height = rect.w - rect.y; + float maxdim = std::max(width, height); + float lod_max = float(mesh.GetLODCount() - 1); + float lod = clamp(std::log2(1.0f / maxdim) + object.lod_bias, 0.0f, lod_max); + return uint32_t(lod); + } + bool Scene::IsWetmapProcessingRequired() const { return wetmap_fadeout_time > 0; diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index d315a188a8..3a6932f8b2 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -574,6 +574,9 @@ namespace wi::scene // Note that the input position to this function will be taken on the XZ plane and modified by the displacement map's XZ value, and the Y (vertical) position will be taken from the ocean water height and displacement map only. XMFLOAT3 GetOceanPosAt(const XMFLOAT3& worldPosition) const; + // Computes the LOD for an object AABB for a given view projection matrix + uint32_t ComputeObjectLODForView(const ObjectComponent& object, const wi::primitive::AABB& aabb, const MeshComponent& mesh, const XMMATRIX& ViewProjection) const; + private: void UpdateHumanoidFacings(); diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index b5fd57c6cf..5874023493 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -377,7 +377,6 @@ namespace wi::terrain request.y = 0; } } - locker.unlock(); } Terrain::Terrain()