Skip to content

Instantly share code, notes, and snippets.

@connorjak
Created February 27, 2023 23:02
Show Gist options
  • Save connorjak/cd2d7dd719c6aab33a16766da5871f2f to your computer and use it in GitHub Desktop.
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
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