UE5 Nanite 渲染流程
UE5 Nanite 支持静态网格Mesh。
启用Nanite
启用和弃用Nanite,对比发现顶点和三角形的个数明显少了很多。
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Developer\AssetTools\Private\AssetTypeActions\AssetTypeActions_StaticMesh.cpp
启用和弃用Nanite
功能主要是涉及相关UStaticMesh
的重新构建过程。
void FAssetTypeActions_StaticMesh::ExecuteNaniteEnable(TArray<TWeakObjectPtr<UStaticMesh>> Objects)
{
for (auto StaticMeshPtr : Objects)
{
UStaticMesh* Mesh = StaticMeshPtr.Get();
if (Mesh)
{
Mesh->NaniteSettings.bEnabled = true;
Mesh->Build();
Mesh->MarkPackageDirty();
Mesh->OnMeshChanged.Broadcast();
}
}
}
void FAssetTypeActions_StaticMesh::ExecuteNaniteDisable(TArray<TWeakObjectPtr<UStaticMesh>> Objects)
{
for (auto StaticMeshPtr : Objects)
{
UStaticMesh* Mesh = StaticMeshPtr.Get();
if (Mesh)
{
Mesh->NaniteSettings.bEnabled = false;
Mesh->Build();
Mesh->MarkPackageDirty();
Mesh->OnMeshChanged.Broadcast();
}
}
}
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Private\StaticMeshBuild.cpp
目前Nanite功能仅支持编辑器模式下启用。
void UStaticMesh::Build(bool bInSilent, TArray<FText>* OutErrors)
{
#if WITH_EDITOR
#endif // #if WITH_EDITOR
BatchBuild({ this }, bInSilent, nullptr, OutErrors);
}
void UStaticMesh::BatchBuild(const TArray<UStaticMesh*>& InStaticMeshes, bool bInSilent, TFunction<bool(UStaticMesh*)> InProgressCallback, TArray<FText>* OutErrors)
{
#if WITH_EDITOR
#else
UE_LOG(LogStaticMesh, Fatal, TEXT("UStaticMesh::Build should not be called on non-editor builds."));
#endif
}
渲染过程
与其他UPrimitiveComponent
类似,通过创建FPrimitiveSceneProxy
类来执行具体渲染。
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Classes\Components\StaticMeshComponent.h
class ENGINE_API UStaticMeshComponent : public UMeshComponent{
/** For nanite enabled meshes, we'll only show the proxy mesh if this is true */
UPROPERTY()
uint8 bDisplayNaniteProxyMesh:1;
}
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Classes\Engine\StaticMesh.h
class UStaticMesh : public UStreamableRenderAsset, public IInterface_CollisionDataProvider, public IInterface_AssetUserData, public IInterface_AsyncCompilation
{
/** Settings related to building Nanite data. */
UPROPERTY()
FMeshNaniteSettings NaniteSettings;
/**
* Returns true if thee mesh has valid Nanite render data.
*/
ENGINE_API bool HasValidNaniteData() const;
}
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Private\StaticMesh.cpp
bool UStaticMesh::HasValidNaniteData() const
{
if (const FStaticMeshRenderData* SMRenderData = GetRenderData())
{
return SMRenderData->NaniteResources.PageStreamingStates.Num() > 0;
}
return false;
}
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Public\StaticMeshResources.h
/**
* FStaticMeshRenderData - All data needed to render a static mesh.
*/
class FStaticMeshRenderData
{
Nanite::FResources NaniteResources;
}
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Private\StaticMesh.cpp
void FStaticMeshRenderData::InitResources(ERHIFeatureLevel::Type InFeatureLevel, UStaticMesh* Owner)
{
NaniteResources.InitResources();
}
void FStaticMeshRenderData::ReleaseResources()
{
NaniteResources.ReleaseResources();
}
FPrimitiveSceneProxy* UStaticMeshComponent::CreateSceneProxy()
{
// Is Nanite supported, and is there built Nanite data for this static mesh?
if (UseNanite(GetScene()->GetShaderPlatform()) && GetStaticMesh()->HasValidNaniteData()
#if WITH_EDITORONLY_DATA
&& !bDisplayNaniteProxyMesh
#endif
)
{
LLM_SCOPE(ELLMTag::StaticMesh);
// Nanite is fully supported
return ::new Nanite::FSceneProxy(this);
}
FPrimitiveSceneProxy* Proxy = ::new FStaticMeshSceneProxy(this, false);
#if STATICMESH_ENABLE_DEBUG_RENDERING
SendRenderDebugPhysics(Proxy);
#endif
return Proxy;
}
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Private\InstancedStaticMesh.cpp
class ENGINE_API UInstancedStaticMeshComponent : public UStaticMeshComponent
FPrimitiveSceneProxy* UInstancedStaticMeshComponent::CreateSceneProxy()
{
// Is Nanite supported, and is there built Nanite data for this static mesh?
if (UseNanite(GetScene()->GetShaderPlatform()) && GetStaticMesh()->HasValidNaniteData())
{
return ::new Nanite::FSceneProxy(this);
}
// If we didn't get a proxy, but Nanite was enabled on the asset when it was built, evaluate proxy creation
else if (GetStaticMesh()->HasValidNaniteData() && NaniteProxyRenderMode != 0)
{
// Do not render Nanite proxy
return nullptr;
}
else
{
return ::new FInstancedStaticMeshSceneProxy(this, GetWorld()->FeatureLevel);
}
}
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Private\HierarchicalInstancedStaticMesh.cpp
class ENGINE_API UHierarchicalInstancedStaticMeshComponent : public UInstancedStaticMeshComponent:public UStaticMeshComponent
FPrimitiveSceneProxy* UHierarchicalInstancedStaticMeshComponent::CreateSceneProxy(){
// Is Nanite supported, and is there built Nanite data for this static mesh?
if (UseNanite(GetScene()->GetShaderPlatform()) && GetStaticMesh()->HasValidNaniteData())
{
return ::new Nanite::FSceneProxy(this);
}
// If we didn't get a proxy, but Nanite was enabled on the asset when it was built, evaluate proxy creation
else if (GetStaticMesh()->HasValidNaniteData() && NaniteProxyRenderMode != 0)
{
// Do not render Nanite proxy
return nullptr;
}
else
{
return ::new FHierarchicalStaticMeshSceneProxy(this, GetWorld()->FeatureLevel);
}
}
其他
其他涉及Nanite渲染的相关类。
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Public\Rendering\NaniteResources.h
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Public\NaniteSceneProxy.h
Root:\Program Files\Epic Games\UE_5.0EA\Engine\Source\Runtime\Engine\Public\Rendering\NaniteStreamingManager.h
Root::\Program Files\Epic Games\UE_5.0EA\Engine\Source\Developer\NaniteBuilder\Public\NaniteBuilder.h