Error: appError called: Assertion failed: Count > 0 [File:D:\_NOAV\BLUE-PACKAGE-MAIN\Engine\Source\Runtime\Engine\Private\Rendering\ColorVertexBuffer.cpp]

We are encountering an assert during real-time SkeletalMeshMerge processing with the following call stack.

To guard against this assert, we applied the code modification shown below.

From our analysis, GetHasVertexColors() is determined by the mesh settings, while MergedColorBuffer is built on a per-LOD basis. If merging is skipped for a particular LOD, MergedColorBuffer.Count can become 0, which appears to lead to this issue.

Could you please let us know whether a similar fix has already been implemented or included in any recent updates?

#if 1 
	if( MergeMesh->GetHasVertexColors() && MergedColorBuffer.Num() > 0 )
#else
	if( MergeMesh->GetHasVertexColors() )
#endif
	{
		MergeLODData.StaticVertexBuffers.ColorVertexBuffer.InitFromColorArray(MergedColorBuffer);
	}



[Attachment Removed]

#if 1 
	if( MergeMesh->GetHasVertexColors() && MergedColorBuffer.Num() > 0 )
#else
	if( MergeMesh->GetHasVertexColors() )
#endif
	{
		MergeLODData.StaticVertexBuffers.ColorVertexBuffer.InitFromColorArray(MergedColorBuffer);
	}

Would there be any problems if I make the changes as shown in the code above

[Attachment Removed]

안녕하세요 이중기님

전사 휴무 및 내부 시스템의 오류로 문의 주신 내용의 답변이 지체되고 있습니다.

최대한 빠르게 정리하여 답변드릴 수 있도록 하겠습니다.

너른 양해 부탁드립니다.

감사합니다.

[Attachment Removed]

안녕하세요.

현재 문의해주신 어서트 관련 엔진 수정사항은 없는 것으로 확인됩니다.

FSkeletalMeshMerge는 병합하려는 LOD의 상태를 확인하지 않고 LODRenderData를 처리합니다. 이 때 대상 LOD의 로드 또는 스트리밍이 완료되지 않거나 쿠킹 과정에서 제거된 LOD가 포함되면 정점이 복사되지 않아 MergedColorBuffer가 빈 상태가 되어 어서트가 발생할 수 있습니다.

추가하신 조건은 어서트 방지에는 적절하지만 빈 LOD 생성까지 막지는 못하기 때문에 빈 LOD가 생성되면 LOD 전환 시 메시가 렌더링되지 않을 수 있습니다. 추가적으로 MergedColorBuffer.Num()과 MergedVertexBuffer.Num()의 불일치 및 빈 LOD 생성 여부를 별도로 확인할 필요가 있습니다.

아래의 예시와 같이 병합 전 모든 소스 메시의 초기화와 LOD를 로드시키고 필요한 LOD를 로드하지 못하면 병합을 중단하거나 StripTopLODs를 조정해 모든 소스 메시에서 사용할 수 있는 LOD만 병합하는 방법을 권장드립니다.

for (USkeletalMesh* SourceMesh : SrcMeshList)
{
	if (SourceMesh)
	{
		SourceMesh->WaitForPendingInitOrStreaming();
		SourceMesh->SetForceMipLevelsToBeResident(30.0f);
		if (SourceMesh->RenderResourceSupportsStreaming())
		{
			SourceMesh->StreamIn(FStreamableRenderResourceState::MAX_LOD_COUNT, true);
		}
	}
}
 
for (USkeletalMesh* SourceMesh : SrcMeshList)
{
	if (SourceMesh)
	{
		SourceMesh->WaitForPendingInitOrStreaming();
		const FStreamableRenderResourceState& ResourceState = SourceMesh->GetStreamableResourceState();
		if (ResourceState.bSupportsStreaming && ResourceState.NumResidentLODs < ResourceState.MaxNumLODs)
		{
			return false;
		}
	}
}

StreamIn()은 게임 스레드 전용이며 WaitForPendingInitOrStreaming()은 IO와 렌더 명령 완료까지 대기하여 히치가 발생할 수 있으므로 SetForceMipLevelsToBeResident() 또는 PrestreamMeshLODs()로 로드를 요청하고 RegisterMipLevelChangeCallback 또는 RegisterLODStreamingCallback 완료 결과를 게임 스레드에서 병합하는 방식으로 비동기 처리할 수 있습니다.

Override LOD Streaming Settings를 활성화하고 Stream LODs를 비활성화하여 소스 메시의 LOD 스트리밍을 비활성화시키는 방법도 있으며 이 경우 LOD 버퍼가 인라인으로 포함되어 메모리 사용량이 증가할 수 있습니다.

해당 이슈에 대해 프로젝트에서 LOD 스트리밍 설정이나 상태와 같은 현재 상황이나 이슈 재현 스텝, 샘플 프로젝트 등을 첨부해주시면 문제 해결에 많은 도움이 될 것으로 보입니다.

감사합니다.

[Attachment Removed]

안녕하세요.

질문해주신 이슈의 버그 리포트가 등록되어 안내드립니다.

아래 링크를 참고해주시면 감사하겠습니다.

https://issues.unrealengine.com/issue/UE\-388107

감사합니다.

[Attachment Removed]