Created
February 27, 2023 23:02
-
-
Save connorjak/cd2d7dd719c6aab33a16766da5871f2f to your computer and use it in GitHub Desktop.
Additions to RuntimeMesh (RMCv4) functionality that provide somewhat more consistent simultaneous setting of multiple meshes' visibility and shadow-casting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void URuntimeMesh::SetSectionVisibility(int32 LODIndex, int32 SectionId, bool bIsVisible) | |
{ | |
RMC_LOG_VERBOSE("SetSectionVisibility called: LOD:%d Section:%d IsVisible:%d", LODIndex, SectionId, bIsVisible); | |
check(LODs.IsValidIndex(LODIndex)); | |
check(LODs[LODIndex].Sections.Contains(SectionId)); | |
FScopeLock Lock(&SyncRoot); | |
FRuntimeMeshSectionProperties* Section = LODs[LODIndex].Sections.Find(SectionId); | |
if (Section && Section->bIsVisible != bIsVisible) | |
{ | |
Section->bIsVisible = bIsVisible; | |
ESectionUpdateType& UpdateType = SectionsToUpdate.FindOrAdd(LODIndex).FindOrAdd(SectionId); | |
UpdateType |= ESectionUpdateType::Properties; | |
UpdateType = (UpdateType & ~ESectionUpdateType::ClearOrRemove); | |
QueueForMeshUpdate(); | |
} | |
} | |
void URuntimeMesh::SetSectionCastsShadow(int32 LODIndex, int32 SectionId, bool bCastsShadow) | |
{ | |
RMC_LOG_VERBOSE("SetSectionCastsShadow called: LOD:%d Section:%d CastsShadow:%d", LODIndex, SectionId, bCastsShadow); | |
check(LODs.IsValidIndex(LODIndex)); | |
check(LODs[LODIndex].Sections.Contains(SectionId)); | |
FScopeLock Lock(&SyncRoot); | |
FRuntimeMeshSectionProperties* Section = LODs[LODIndex].Sections.Find(SectionId); | |
if (Section && Section->bCastsShadow != bCastsShadow) | |
{ | |
Section->bCastsShadow = bCastsShadow; | |
ESectionUpdateType& UpdateType = SectionsToUpdate.FindOrAdd(LODIndex).FindOrAdd(SectionId); | |
UpdateType |= ESectionUpdateType::Properties; | |
UpdateType = (UpdateType & ~ESectionUpdateType::ClearOrRemove); | |
QueueForMeshUpdate(); | |
} | |
} | |
//This is a Connor addition | |
void URuntimeMesh::ForceSetSectionVisibleAndCastsShadow(int32 LODIndex, int32 SectionId, bool bIsVisible, bool bCastsShadow) | |
{ | |
RMC_LOG_VERBOSE("ForceSetSectionVisibleAndCastsShadow called: LOD:%d Section:%d IsVisible:%d CastsShadow:%d", LODIndex, SectionId, bIsVisible, bCastsShadow); | |
check(LODs.IsValidIndex(LODIndex)); | |
check(LODs[LODIndex].Sections.Contains(SectionId)); | |
FScopeLock Lock(&SyncRoot); | |
FRuntimeMeshSectionProperties* Section = LODs[LODIndex].Sections.Find(SectionId); | |
if (Section /*&& Section->bCastsShadow != bCastsShadow*/) | |
{ | |
Section->bIsVisible = bIsVisible; | |
Section->bCastsShadow = bCastsShadow; | |
ESectionUpdateType& UpdateType = SectionsToUpdate.FindOrAdd(LODIndex).FindOrAdd(SectionId); | |
UpdateType |= ESectionUpdateType::Properties; | |
UpdateType = (UpdateType & ~ESectionUpdateType::ClearOrRemove); | |
QueueForMeshUpdate(); | |
} | |
} | |
//This is a Connor addition | |
void URuntimeMesh::IMMEDIATE_ForceSetSectionVisibleAndCastsShadow(int32 LODIndex, int32 SectionId, bool bIsVisible, bool bCastsShadow) | |
{ | |
RMC_LOG_VERBOSE("IMMEDIATE_ForceSetSectionVisibleAndCastsShadow called: LOD:%d Section:%d IsVisible:%d CastsShadow:%d", LODIndex, SectionId, bIsVisible, bCastsShadow); | |
check(LODs.IsValidIndex(LODIndex)); | |
check(LODs[LODIndex].Sections.Contains(SectionId)); | |
FScopeLock Lock(&SyncRoot); | |
//FRuntimeMeshSectionProperties* Section = LODs[LODIndex].Sections.Find(SectionId); | |
auto& Section = LODs[LODIndex].Sections[SectionId]; | |
//if (Section /*&& Section->bCastsShadow != bCastsShadow*/) | |
if (true) | |
{ | |
Section.bIsVisible = bIsVisible; | |
Section.bCastsShadow = bCastsShadow; | |
// NOTE: the below was copied from HandleUpdate. | |
// TODO: this really shouldn't be necessary | |
// but editor can sometimes force a delete | |
FRuntimeMeshProxyPtr RenderProxyRef = RenderProxy; | |
if (!RenderProxyRef.IsValid()) | |
{ | |
return; | |
} | |
FReadScopeLock ProviderLock(MeshProviderLock); | |
if (MeshProviderPtr) | |
{ | |
RenderProxyRef->CreateOrUpdateSection_GameThread(LODIndex, SectionId, Section, false); | |
} | |
} | |
} | |
//This is a Connor addition | |
void URuntimeMesh::MULTI_IMMEDIATE_ForceSetSectionVisibleAndCastsShadow(TArray<URuntimeMesh*> meshes, int32 LODIndex, TArray<int32> SectionIds, TArray<bool> bIsVisibles, TArray<bool> bCastsShadows) | |
{ | |
TRACE_CPUPROFILER_EVENT_SCOPE(MULTI_IMMEDIATE_ForceSetSectionVisibleAndCastsShadow); | |
//RMC_LOG_VERBOSE("MULTI_IMMEDIATE_ForceSetSectionVisibleAndCastsShadow called: LOD:%d Section:%d IsVisible:%d CastsShadow:%d", LODIndex, SectionId, bIsVisible, bCastsShadow); | |
//check(LODs.IsValidIndex(LODIndex)); | |
//check(LODs[LODIndex].Sections.Contains(SectionId)); | |
//FScopeLock Lock(&SyncRoot); //TODO | |
TArray<TWeakPtr<FRuntimeMeshProxy, ESPMode::ThreadSafe>> ThisWeakRefs; | |
for (int itr = 0; itr < meshes.Num(); itr++) | |
{ | |
auto* mesh = meshes[itr]; | |
auto SectionId = SectionIds[itr]; | |
auto bIsVisible = bIsVisibles[itr]; | |
auto bCastsShadow = bCastsShadows[itr]; | |
auto& Section = mesh->LODs[LODIndex].Sections[SectionId]; | |
Section.bIsVisible = bIsVisible; | |
Section.bCastsShadow = bCastsShadow; | |
// TODO: this really shouldn't be necessary | |
// but editor can sometimes force a delete | |
FRuntimeMeshProxyPtr RenderProxyRef = mesh->RenderProxy; | |
if (!RenderProxyRef.IsValid()) | |
{ | |
return; | |
} | |
FReadScopeLock ProviderLock(mesh->MeshProviderLock); | |
if (mesh->MeshProviderPtr) | |
{ | |
//RenderProxyRef->CreateOrUpdateSection_GameThread(LODIndex, SectionId, Section, false); | |
RenderProxyRef->Deferred_CreateOrUpdateSection_GameThread(LODIndex, SectionId, Section, false); | |
// This differs from CreateOrUpdateSection_GameThread by not running QueueForUpdate(). | |
// This means that we can do all the FlushPendingUpdates() in one ENQUEUE_RENDER_COMMAND. | |
ThisWeakRefs.Add(RenderProxyRef); | |
} | |
} | |
// QueueForUpdate() copy paste // | |
// TODO: Is this really necessary. Enqueueing render commands fails sometimes when not called from game thread | |
// We need to correctly support asynchronus submission | |
//if (!RenderProxyRef->IsQueuedForUpdate.AtomicSet(true)/* && GRenderingThread && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed)*/) | |
//{ | |
// | |
//} | |
ENQUEUE_RENDER_COMMAND(FRuntimeMeshProxy_MultiUpdate)([ThisWeakRefs](FRHICommandListImmediate& RHICmdList) | |
{ | |
for (auto ThisWeakRef : ThisWeakRefs) | |
{ | |
auto Pinned = ThisWeakRef.Pin(); | |
if (Pinned) | |
{ | |
Pinned->FlushPendingUpdates(); | |
} | |
} | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment