Created
December 12, 2021 12:40
-
-
Save blueroseslol/5ff2c26fc3b77305a88b2378772527ac to your computer and use it in GitHub Desktop.
This file contains 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
#pragma once | |
#include "Engine/Private/SkeletalRenderGPUSkin.h" | |
class FOutlineSkeletalMeshObjectGPUSkin : public FSkeletalMeshObjectGPUSkin | |
{ | |
public: | |
FOutlineSkeletalMeshObjectGPUSkin(USkinnedMeshComponent* InMeshComponent, FSkeletalMeshRenderData* InSkelMeshRenderData, ERHIFeatureLevel::Type InFeatureLevel):FSkeletalMeshObjectGPUSkin(InMeshComponent,InSkelMeshRenderData,InFeatureLevel){} | |
FGPUSkinCacheEntry* GetGPUSkinCacheEntry(){return SkinCacheEntry;} | |
}; | |
static int32 GForceRecomputeTangents = 0; | |
int32 GSkinCacheRecomputeTangents = 2; | |
static int32 GBlendUsingVertexColorForRecomputeTangents = 0; | |
class FGPUSkinCacheEntry | |
{ | |
public: | |
FGPUSkinCacheEntry(FGPUSkinCache* InSkinCache, FSkeletalMeshObjectGPUSkin* InGPUSkin, FGPUSkinCache::FRWBuffersAllocation* InPositionAllocation) | |
: PositionAllocation(InPositionAllocation) | |
, SkinCache(InSkinCache) | |
, GPUSkin(InGPUSkin) | |
, MorphBuffer(0) | |
, LOD(InGPUSkin->GetLOD()) | |
{ | |
const TArray<FSkelMeshRenderSection>& Sections = InGPUSkin->GetRenderSections(LOD); | |
DispatchData.AddDefaulted(Sections.Num()); | |
BatchElementsUserData.AddZeroed(Sections.Num()); | |
for (int32 Index = 0; Index < Sections.Num(); ++Index) | |
{ | |
BatchElementsUserData[Index].Entry = this; | |
BatchElementsUserData[Index].Section = Index; | |
} | |
UpdateSkinWeightBuffer(); | |
} | |
~FGPUSkinCacheEntry() | |
{ | |
check(!PositionAllocation); | |
} | |
struct FSectionDispatchData | |
{ | |
FGPUSkinCache::FRWBufferTracker PositionTracker; | |
FGPUBaseSkinVertexFactory* SourceVertexFactory = nullptr; | |
FGPUSkinPassthroughVertexFactory* TargetVertexFactory = nullptr; | |
// triangle index buffer (input for the RecomputeSkinTangents, might need special index buffer unique to position and normal, not considering UV/vertex color) | |
FRHIShaderResourceView* IndexBuffer = nullptr; | |
const FSkelMeshRenderSection* Section = nullptr; | |
// for debugging / draw events, -1 if not set | |
uint32 SectionIndex = -1; | |
// 0:normal, 1:with morph target, 2:with APEX cloth (not yet implemented) | |
uint16 SkinType = 0; | |
// See EGPUSkinCacheDispatchFlags | |
uint16 DispatchFlags = 0; | |
// | |
uint32 NumBoneInfluences = 0; | |
// in floats (4 bytes) | |
uint32 OutputStreamStart = 0; | |
uint32 NumVertices = 0; | |
// in vertices | |
uint32 InputStreamStart = 0; | |
uint32 NumTexCoords = 1; | |
uint32 SelectedTexCoord = 0; | |
FShaderResourceViewRHIRef TangentBufferSRV = nullptr; | |
FShaderResourceViewRHIRef UVsBufferSRV = nullptr; | |
FShaderResourceViewRHIRef ColorBufferSRV = nullptr; | |
FShaderResourceViewRHIRef PositionBufferSRV = nullptr; | |
FShaderResourceViewRHIRef ClothPositionsAndNormalsBuffer = nullptr; | |
// skin weight input | |
uint32 InputWeightStart = 0; | |
// morph input | |
uint32 MorphBufferOffset = 0; | |
// cloth input | |
uint32 ClothBufferOffset = 0; | |
float ClothBlendWeight = 0.0f; | |
FMatrix ClothLocalToWorld = FMatrix::Identity; | |
FMatrix ClothWorldToLocal = FMatrix::Identity; | |
// triangle index buffer (input for the RecomputeSkinTangents, might need special index buffer unique to position and normal, not considering UV/vertex color) | |
uint32 IndexBufferOffsetValue = 0; | |
uint32 NumTriangles = 0; | |
FRWBuffer* TangentBuffer = nullptr; | |
FRWBuffer* IntermediateTangentBuffer = nullptr; | |
FRWBuffer* PositionBuffer = nullptr; | |
FRWBuffer* PreviousPositionBuffer = nullptr; | |
// Handle duplicates | |
FShaderResourceViewRHIRef DuplicatedIndicesIndices = nullptr; | |
FShaderResourceViewRHIRef DuplicatedIndices = nullptr; | |
FSectionDispatchData() = default; | |
inline FRWBuffer* GetPreviousPositionRWBuffer() | |
{ | |
check(PreviousPositionBuffer); | |
return PreviousPositionBuffer; | |
} | |
inline FRWBuffer* GetPositionRWBuffer() | |
{ | |
check(PositionBuffer); | |
return PositionBuffer; | |
} | |
inline FRHIShaderResourceView* GetPreSkinPositionSRV() | |
{ | |
check(SourceVertexFactory); | |
check(SourceVertexFactory->GetPositionsSRV()); | |
return SourceVertexFactory->GetPositionsSRV().GetReference(); | |
} | |
inline FRWBuffer* GetTangentRWBuffer() | |
{ | |
return TangentBuffer; | |
} | |
FRWBuffer* GetActiveTangentRWBuffer() | |
{ | |
bool bUseIntermediateTangentBuffer = IndexBuffer && GBlendUsingVertexColorForRecomputeTangents > 0; | |
if (bUseIntermediateTangentBuffer) | |
{ | |
return IntermediateTangentBuffer; | |
} | |
else | |
{ | |
return TangentBuffer; | |
} | |
} | |
void UpdateVertexFactoryDeclaration() | |
{ | |
TargetVertexFactory->UpdateVertexDeclaration(SourceVertexFactory, GetPositionRWBuffer(), GetPreSkinPositionSRV(), GetTangentRWBuffer()); | |
} | |
}; | |
void UpdateVertexFactoryDeclaration(int32 Section) | |
{ | |
DispatchData[Section].UpdateVertexFactoryDeclaration(); | |
} | |
inline FCachedGeometry::Section GetCachedGeometry(int32 SectionIndex) const | |
{ | |
FCachedGeometry::Section MeshSection; | |
const FSkelMeshRenderSection& Section = *DispatchData[SectionIndex].Section; | |
MeshSection.PositionBuffer = DispatchData[SectionIndex].PositionBuffer->SRV; | |
MeshSection.UVsBuffer = DispatchData[SectionIndex].UVsBufferSRV; | |
MeshSection.TotalVertexCount= DispatchData[SectionIndex].PositionBuffer->NumBytes / (sizeof(float)*3); | |
MeshSection.NumPrimitives = Section.NumTriangles; | |
MeshSection.NumVertices = Section.NumVertices; | |
MeshSection.IndexBaseIndex = Section.BaseIndex; | |
MeshSection.VertexBaseIndex = Section.BaseVertexIndex; | |
MeshSection.IndexBuffer = nullptr; | |
MeshSection.TotalIndexCount = 0; | |
MeshSection.LODIndex = 0; | |
MeshSection.SectionIndex = SectionIndex; | |
return MeshSection; | |
} | |
bool IsSectionValid(int32 Section) const | |
{ | |
const FSectionDispatchData& SectionData = DispatchData[Section]; | |
return SectionData.SectionIndex == Section; | |
} | |
bool IsSourceFactoryValid(int32 Section, FGPUBaseSkinVertexFactory* SourceVertexFactory) const | |
{ | |
const FSectionDispatchData& SectionData = DispatchData[Section]; | |
return SectionData.SourceVertexFactory == SourceVertexFactory; | |
} | |
bool IsValid(FSkeletalMeshObjectGPUSkin* InSkin) const | |
{ | |
return GPUSkin == InSkin && GPUSkin->GetLOD() == LOD; | |
} | |
void UpdateSkinWeightBuffer() | |
{ | |
FSkinWeightVertexBuffer* WeightBuffer = GPUSkin->GetSkinWeightVertexBuffer(LOD); | |
bUse16BitBoneIndex = WeightBuffer->Use16BitBoneIndex(); | |
InputWeightIndexSize = WeightBuffer->GetBoneIndexByteSize(); | |
InputWeightStride = WeightBuffer->GetConstantInfluencesVertexStride(); | |
InputWeightStreamSRV = WeightBuffer->GetDataVertexBuffer()->GetSRV(); | |
InputWeightLookupStreamSRV = WeightBuffer->GetLookupVertexBuffer()->GetSRV(); | |
if (WeightBuffer->GetBoneInfluenceType() == GPUSkinBoneInfluenceType::DefaultBoneInfluence) | |
{ | |
int32 MaxBoneInfluences = WeightBuffer->GetMaxBoneInfluences(); | |
BoneInfluenceType = MaxBoneInfluences > MAX_INFLUENCES_PER_STREAM ? 1 : 0; | |
} | |
else | |
{ | |
BoneInfluenceType = 2; | |
} | |
} | |
void SetupSection(int32 SectionIndex, FGPUSkinCache::FRWBuffersAllocation* InPositionAllocation, FSkelMeshRenderSection* Section, const FMorphVertexBuffer* MorphVertexBuffer, const FSkeletalMeshVertexClothBuffer* ClothVertexBuffer, | |
uint32 NumVertices, uint32 InputStreamStart, FGPUBaseSkinVertexFactory* InSourceVertexFactory, FGPUSkinPassthroughVertexFactory* InTargetVertexFactory) | |
{ | |
//UE_LOG(LogSkinCache, Warning, TEXT("*** SetupSection E %p Alloc %p Sec %d(%p) LOD %d"), this, InAllocation, SectionIndex, Section, LOD); | |
FSectionDispatchData& Data = DispatchData[SectionIndex]; | |
check(!Data.PositionTracker.Allocation || Data.PositionTracker.Allocation == InPositionAllocation); | |
Data.PositionTracker.Allocation = InPositionAllocation; | |
Data.SectionIndex = SectionIndex; | |
Data.Section = Section; | |
check(GPUSkin->GetLOD() == LOD); | |
FSkeletalMeshRenderData& SkelMeshRenderData = GPUSkin->GetSkeletalMeshRenderData(); | |
FSkeletalMeshLODRenderData& LodData = SkelMeshRenderData.LODRenderData[LOD]; | |
check(Data.SectionIndex == LodData.FindSectionIndex(*Section)); | |
Data.NumVertices = NumVertices; | |
const bool bMorph = MorphVertexBuffer && MorphVertexBuffer->SectionIds.Contains(SectionIndex); | |
if (bMorph) | |
{ | |
// in bytes | |
const uint32 MorphStride = sizeof(FMorphGPUSkinVertex); | |
// see GPU code "check(MorphStride == sizeof(float) * 6);" | |
check(MorphStride == sizeof(float) * 6); | |
Data.MorphBufferOffset = Section->BaseVertexIndex; | |
} | |
if (ClothVertexBuffer && ClothVertexBuffer->GetClothIndexMapping().Num() > SectionIndex) | |
{ | |
Data.ClothBufferOffset = (ClothVertexBuffer->GetClothIndexMapping()[SectionIndex] & 0xFFFFFFFF); | |
} | |
//INC_DWORD_STAT(STAT_GPUSkinCache_TotalNumChunks); | |
// SkinType 0:normal, 1:with morph target, 2:with cloth | |
Data.SkinType = ClothVertexBuffer ? 2 : (bMorph ? 1 : 0); | |
Data.InputStreamStart = InputStreamStart; | |
Data.OutputStreamStart = Section->BaseVertexIndex; | |
Data.TangentBufferSRV = InSourceVertexFactory->GetTangentsSRV(); | |
Data.UVsBufferSRV = InSourceVertexFactory->GetTextureCoordinatesSRV(); | |
Data.ColorBufferSRV = InSourceVertexFactory->GetColorComponentsSRV(); | |
Data.NumTexCoords = InSourceVertexFactory->GetNumTexCoords(); | |
Data.PositionBufferSRV = InSourceVertexFactory->GetPositionsSRV(); | |
Data.NumBoneInfluences = InSourceVertexFactory->GetNumBoneInfluences(); | |
check(Data.TangentBufferSRV && Data.PositionBufferSRV); | |
// weight buffer | |
Data.InputWeightStart = (InputWeightStride * Section->BaseVertexIndex) / sizeof(float); | |
Data.SourceVertexFactory = InSourceVertexFactory; | |
Data.TargetVertexFactory = InTargetVertexFactory; | |
InTargetVertexFactory->InvalidateStreams(); | |
int32 RecomputeTangentsMode = GForceRecomputeTangents > 0 ? 1 : GSkinCacheRecomputeTangents; | |
if (RecomputeTangentsMode > 0) | |
{ | |
if (Section->bRecomputeTangent || RecomputeTangentsMode == 1) | |
{ | |
FRawStaticIndexBuffer16or32Interface* IndexBuffer = LodData.MultiSizeIndexContainer.GetIndexBuffer(); | |
Data.IndexBuffer = IndexBuffer->GetSRV(); | |
if (Data.IndexBuffer) | |
{ | |
Data.NumTriangles = Section->NumTriangles; | |
Data.IndexBufferOffsetValue = Section->BaseIndex; | |
} | |
} | |
} | |
} | |
#if RHI_RAYTRACING | |
void GetRayTracingSegmentVertexBuffers(TArrayView<FRayTracingGeometrySegment> OutSegments) const | |
{ | |
check(OutSegments.Num() == DispatchData.Num()); | |
for (int32 SectionIdx = 0; SectionIdx < DispatchData.Num(); SectionIdx++) | |
{ | |
const FSectionDispatchData& SectionData = DispatchData[SectionIdx]; | |
FRayTracingGeometrySegment& Segment = OutSegments[SectionIdx]; | |
Segment.VertexBuffer = SectionData.PositionBuffer->Buffer; | |
Segment.VertexBufferOffset = 0; | |
check(SectionData.Section->NumTriangles == Segment.NumPrimitives); | |
} | |
} | |
#endif // RHI_RAYTRACING | |
protected: | |
public: | |
FGPUSkinCache::FRWBuffersAllocation* PositionAllocation; | |
FGPUSkinCache* SkinCache; | |
TArray<FGPUSkinBatchElementUserData> BatchElementsUserData; | |
TArray<FSectionDispatchData> DispatchData; | |
FSkeletalMeshObjectGPUSkin* GPUSkin; | |
int BoneInfluenceType; | |
bool bUse16BitBoneIndex; | |
uint32 InputWeightIndexSize; | |
uint32 InputWeightStride; | |
uint32 VertexOffsetUsage = 0; | |
FShaderResourceViewRHIRef InputWeightStreamSRV; | |
FShaderResourceViewRHIRef InputWeightLookupStreamSRV; | |
FRHIShaderResourceView* PreSkinningVertexOffsetSRV = nullptr; | |
FRHIShaderResourceView* PostSkinningVertexOffsetSRV = nullptr; | |
FRHIShaderResourceView* MorphBuffer; | |
FShaderResourceViewRHIRef ClothBuffer; | |
int32 LOD; | |
bool bMultipleClothSkinInfluences; | |
friend class FGPUSkinCache; | |
friend class FBaseGPUSkinCacheCS; | |
friend class FBaseRecomputeTangentsPerTriangleShader; | |
}; |
This file contains 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
FOutlineSkeletalMeshSceneProxy::FOutlineSkeletalMeshSceneProxy(const USkinnedMeshComponent* Component, FSkeletalMeshRenderData* InSkelMeshRenderData): | |
FSkeletalMeshSceneProxy(Component,InSkelMeshRenderData),ComponentPtr(Component) | |
{ | |
} | |
class FSkeletalMeshSectionIter | |
{ | |
public: | |
FSkeletalMeshSectionIter(const int32 InLODIdx, const FSkeletalMeshObject& InMeshObject, const FSkeletalMeshLODRenderData& InLODData, const FSkeletalMeshSceneProxy::FLODSectionElements& InLODSectionElements) | |
: SectionIndex(0) | |
, MeshObject(InMeshObject) | |
, LODSectionElements(InLODSectionElements) | |
, Sections(InLODData.RenderSections) | |
#if WITH_EDITORONLY_DATA | |
, SectionIndexPreview(InMeshObject.SectionIndexPreview) | |
, MaterialIndexPreview(InMeshObject.MaterialIndexPreview) | |
#endif | |
{ | |
while (NotValidPreviewSection()) | |
{ | |
SectionIndex++; | |
} | |
} | |
FORCEINLINE FSkeletalMeshSectionIter& operator++() | |
{ | |
do | |
{ | |
SectionIndex++; | |
} while (NotValidPreviewSection()); | |
return *this; | |
} | |
FORCEINLINE operator bool() const | |
{ | |
return ((SectionIndex < Sections.Num()) && LODSectionElements.SectionElements.IsValidIndex(GetSectionElementIndex())); | |
} | |
FORCEINLINE const FSkelMeshRenderSection& GetSection() const | |
{ | |
return Sections[SectionIndex]; | |
} | |
FORCEINLINE const int32 GetSectionElementIndex() const | |
{ | |
return SectionIndex; | |
} | |
FORCEINLINE const FSkeletalMeshSceneProxy::FSectionElementInfo& GetSectionElementInfo() const | |
{ | |
int32 SectionElementInfoIndex = GetSectionElementIndex(); | |
return LODSectionElements.SectionElements[SectionElementInfoIndex]; | |
} | |
FORCEINLINE bool NotValidPreviewSection() | |
{ | |
#if WITH_EDITORONLY_DATA | |
if (MaterialIndexPreview == INDEX_NONE) | |
{ | |
int32 ActualPreviewSectionIdx = SectionIndexPreview; | |
return (SectionIndex < Sections.Num()) && | |
((ActualPreviewSectionIdx >= 0) && (ActualPreviewSectionIdx != SectionIndex)); | |
} | |
else | |
{ | |
int32 ActualPreviewMaterialIdx = MaterialIndexPreview; | |
int32 ActualPreviewSectionIdx = INDEX_NONE; | |
if (ActualPreviewMaterialIdx != INDEX_NONE && Sections.IsValidIndex(SectionIndex)) | |
{ | |
const FSkeletalMeshSceneProxy::FSectionElementInfo& SectionInfo = LODSectionElements.SectionElements[SectionIndex]; | |
if (SectionInfo.UseMaterialIndex == ActualPreviewMaterialIdx) | |
{ | |
ActualPreviewSectionIdx = SectionIndex; | |
} | |
} | |
return (SectionIndex < Sections.Num()) && | |
((ActualPreviewMaterialIdx >= 0) && (ActualPreviewSectionIdx != SectionIndex)); | |
} | |
#else | |
return false; | |
#endif | |
} | |
private: | |
int32 SectionIndex; | |
const FSkeletalMeshObject& MeshObject; | |
const FSkeletalMeshSceneProxy::FLODSectionElements& LODSectionElements; | |
const TArray<FSkelMeshRenderSection>& Sections; | |
#if WITH_EDITORONLY_DATA | |
const int32 SectionIndexPreview; | |
const int32 MaterialIndexPreview; | |
#endif | |
}; | |
void FOutlineSkeletalMeshSceneProxy::GetDynamicElementsSection(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, | |
const FSkeletalMeshLODRenderData& LODData, const int32 LODIndex, const int32 SectionIndex, bool bSectionSelected, | |
const FSectionElementInfo& SectionElementInfo, bool bInSelectable, FMeshElementCollector& Collector ) const | |
{ | |
const FSkelMeshRenderSection& Section = LODData.RenderSections[SectionIndex]; | |
//// If hidden skip the draw | |
//if (Section.bDisabled || MeshObject->IsMaterialHidden(LODIndex,SectionElementInfo.UseMaterialIndex)) | |
//{ | |
// return; | |
//} | |
#if !WITH_EDITOR | |
const bool bIsSelected = false; | |
#else // #if !WITH_EDITOR | |
bool bIsSelected = IsSelected(); | |
// if the mesh isn't selected but the mesh section is selected in the AnimSetViewer, find the mesh component and make sure that it can be highlighted (ie. are we rendering for the AnimSetViewer or not?) | |
if( !bIsSelected && bSectionSelected && bCanHighlightSelectedSections ) | |
{ | |
bIsSelected = true; | |
} | |
#endif // #if WITH_EDITOR | |
const bool bIsWireframe = ViewFamily.EngineShowFlags.Wireframe; | |
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) | |
{ | |
if (VisibilityMap & (1 << ViewIndex)) | |
{ | |
const FSceneView* View = Views[ViewIndex]; | |
FMeshBatch& Mesh = Collector.AllocateMesh(); | |
CreateBaseMeshBatch(View, LODData, LODIndex, SectionIndex, SectionElementInfo, Mesh); | |
if(!Mesh.VertexFactory) | |
{ | |
// hide this part | |
continue; | |
} | |
Mesh.bWireframe |= bForceWireframe; | |
Mesh.Type = PT_TriangleList; | |
Mesh.bSelectable = bInSelectable; | |
FMeshBatchElement& BatchElement = Mesh.Elements[0]; | |
const bool bRequiresAdjacencyInformation = RequiresAdjacencyInformation( SectionElementInfo.Material, Mesh.VertexFactory->GetType(), ViewFamily.GetFeatureLevel() ); | |
if ( bRequiresAdjacencyInformation ) | |
{ | |
check(LODData.AdjacencyMultiSizeIndexContainer.IsIndexBufferValid() ); | |
BatchElement.IndexBuffer = LODData.AdjacencyMultiSizeIndexContainer.GetIndexBuffer(); | |
Mesh.Type = PT_12_ControlPointPatchList; | |
BatchElement.FirstIndex *= 4; | |
} | |
#if WITH_EDITOR | |
Mesh.BatchHitProxyId = SectionElementInfo.HitProxy ? SectionElementInfo.HitProxy->Id : FHitProxyId(); | |
if (bSectionSelected && bCanHighlightSelectedSections) | |
{ | |
Mesh.bUseSelectionOutline = true; | |
} | |
else | |
{ | |
Mesh.bUseSelectionOutline = !bCanHighlightSelectedSections && bIsSelected; | |
} | |
#endif | |
#if WITH_EDITORONLY_DATA | |
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) | |
if (bIsSelected) | |
{ | |
if (ViewFamily.EngineShowFlags.VertexColors && AllowDebugViewmodes()) | |
{ | |
// Override the mesh's material with our material that draws the vertex colors | |
UMaterial* VertexColorVisualizationMaterial = NULL; | |
switch (GVertexColorViewMode) | |
{ | |
case EVertexColorViewMode::Color: | |
VertexColorVisualizationMaterial = GEngine->VertexColorViewModeMaterial_ColorOnly; | |
break; | |
case EVertexColorViewMode::Alpha: | |
VertexColorVisualizationMaterial = GEngine->VertexColorViewModeMaterial_AlphaAsColor; | |
break; | |
case EVertexColorViewMode::Red: | |
VertexColorVisualizationMaterial = GEngine->VertexColorViewModeMaterial_RedOnly; | |
break; | |
case EVertexColorViewMode::Green: | |
VertexColorVisualizationMaterial = GEngine->VertexColorViewModeMaterial_GreenOnly; | |
break; | |
case EVertexColorViewMode::Blue: | |
VertexColorVisualizationMaterial = GEngine->VertexColorViewModeMaterial_BlueOnly; | |
break; | |
} | |
check(VertexColorVisualizationMaterial != NULL); | |
auto VertexColorVisualizationMaterialInstance = new FColoredMaterialRenderProxy( | |
VertexColorVisualizationMaterial->GetRenderProxy(), | |
GetSelectionColor(FLinearColor::White, bSectionSelected, IsHovered()) | |
); | |
Collector.RegisterOneFrameMaterialProxy(VertexColorVisualizationMaterialInstance); | |
Mesh.MaterialRenderProxy = VertexColorVisualizationMaterialInstance; | |
} | |
} | |
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) | |
#endif // WITH_EDITORONLY_DATA | |
BatchElement.MinVertexIndex = Section.BaseVertexIndex; | |
Mesh.CastShadow = SectionElementInfo.bEnableShadowCasting; | |
Mesh.bCanApplyViewModeOverrides = true; | |
Mesh.bUseWireframeSelectionColoring = bIsSelected; | |
Mesh.ReverseCulling = !Mesh.ReverseCulling; | |
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) | |
BatchElement.VisualizeElementIndex = SectionIndex; | |
Mesh.VisualizeLODIndex = LODIndex; | |
#endif | |
if (ensureMsgf(Mesh.MaterialRenderProxy, TEXT("GetDynamicElementsSection with invalid MaterialRenderProxy. Owner:%s LODIndex:%d UseMaterialIndex:%d"), *GetOwnerName().ToString(), LODIndex, SectionElementInfo.UseMaterialIndex)) | |
{ | |
Collector.AddMesh(ViewIndex, Mesh); | |
} | |
// const int32 NumVertices = Section.GetNumVertices(); | |
// INC_DWORD_STAT_BY(STAT_GPUSkinVertices,(uint32)(bIsCPUSkinned ? 0 : NumVertices)); | |
// INC_DWORD_STAT_BY(STAT_SkelMeshTriangles,Mesh.GetNumPrimitives()); | |
// INC_DWORD_STAT(STAT_SkelMeshDrawCalls); | |
} | |
} | |
} | |
void FOutlineSkeletalMeshSceneProxy::CreateBaseMeshBatch(const FSceneView* View, const FSkeletalMeshLODRenderData& LODData, const int32 LODIndex, const int32 SectionIndex, const FSectionElementInfo& SectionElementInfo, FMeshBatch& Mesh) const | |
{ | |
Mesh.VertexFactory = MeshObject->GetSkinVertexFactory(View, LODIndex, SectionIndex); | |
Mesh.MaterialRenderProxy = SectionElementInfo.Material->GetRenderProxy(); | |
#if RHI_RAYTRACING | |
Mesh.SegmentIndex = SectionIndex; | |
Mesh.CastRayTracedShadow = SectionElementInfo.bEnableShadowCasting && bCastDynamicShadow; | |
#endif | |
FMeshBatchElement& BatchElement = Mesh.Elements[0]; | |
BatchElement.FirstIndex = LODData.RenderSections[SectionIndex].BaseIndex; | |
BatchElement.IndexBuffer = LODData.MultiSizeIndexContainer.GetIndexBuffer(); | |
BatchElement.MinVertexIndex = LODData.RenderSections[SectionIndex].GetVertexBufferIndex(); | |
BatchElement.MaxVertexIndex = LODData.RenderSections[SectionIndex].GetVertexBufferIndex() + LODData.RenderSections[SectionIndex].GetNumVertices() - 1; | |
FOutlineSkeletalMeshObjectGPUSkin* MeshObjectGPUSkin=static_cast<FOutlineSkeletalMeshObjectGPUSkin*>(MeshObject); | |
FGPUSkinCacheEntry* GPUSkinCacheEntry=MeshObjectGPUSkin->GetGPUSkinCacheEntry(); | |
BatchElement.VertexFactoryUserData = GPUSkinCacheEntry ? &GPUSkinCacheEntry->BatchElementsUserData[SectionIndex] : nullptr; | |
BatchElement.PrimitiveUniformBuffer = GetUniformBuffer(); | |
BatchElement.NumPrimitives = LODData.RenderSections[SectionIndex].NumTriangles; | |
} |
This file contains 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 GetDynamicElementsSection(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, | |
const FSkeletalMeshLODRenderData& LODData, const int32 LODIndex, const int32 SectionIndex, bool bSectionSelected, | |
const FSectionElementInfo& SectionElementInfo, bool bInSelectable, FMeshElementCollector& Collector ) const; | |
void CreateBaseMeshBatch(const FSceneView* View, const FSkeletalMeshLODRenderData& LODData, const int32 LODIndex, const int32 SectionIndex, const FSectionElementInfo& SectionElementInfo, FMeshBatch& Mesh) const; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment