You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
557 lines
23 KiB
C++
557 lines
23 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
SceneHitProxyRendering.cpp: Scene hit proxy rendering.
|
|
=============================================================================*/
|
|
|
|
#include "RendererPrivate.h"
|
|
#include "ScenePrivate.h"
|
|
#include "RenderResource.h"
|
|
|
|
/**
|
|
* A vertex shader for rendering the depth of a mesh.
|
|
*/
|
|
class FHitProxyVS : public FMeshMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FHitProxyVS,MeshMaterial);
|
|
|
|
public:
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FMaterialRenderProxy* MaterialRenderProxy,const FSceneView& View)
|
|
{
|
|
FMeshMaterialShader::SetParameters(RHICmdList, GetVertexShader(), MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(View.GetFeatureLevel()), View, ESceneRenderTargetsMode::SetTextures);
|
|
}
|
|
|
|
void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement, float DitheredLODTransitionValue)
|
|
{
|
|
FMeshMaterialShader::SetMesh(RHICmdList, GetVertexShader(),VertexFactory,View,Proxy,BatchElement,DitheredLODTransitionValue);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
// Only compile the hit proxy vertex shader on PC
|
|
return IsPCPlatform(Platform)
|
|
// and only compile for the default material or materials that are masked.
|
|
&& (Material->IsSpecialEngineMaterial() || !Material->WritesEveryPixel() || Material->MaterialMayModifyMeshPosition() || Material->IsTwoSided());
|
|
}
|
|
|
|
protected:
|
|
|
|
FHitProxyVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FMeshMaterialShader(Initializer)
|
|
{}
|
|
FHitProxyVS() {}
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(,FHitProxyVS,TEXT("HitProxyVertexShader"),TEXT("Main"),SF_Vertex);
|
|
|
|
/**
|
|
* A hull shader for rendering the depth of a mesh.
|
|
*/
|
|
class FHitProxyHS : public FBaseHS
|
|
{
|
|
DECLARE_SHADER_TYPE(FHitProxyHS,MeshMaterial);
|
|
protected:
|
|
|
|
FHitProxyHS() {}
|
|
|
|
FHitProxyHS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FBaseHS(Initializer)
|
|
{}
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
return FBaseHS::ShouldCache(Platform, Material, VertexFactoryType)
|
|
&& FHitProxyVS::ShouldCache(Platform,Material,VertexFactoryType);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* A domain shader for rendering the depth of a mesh.
|
|
*/
|
|
class FHitProxyDS : public FBaseDS
|
|
{
|
|
DECLARE_SHADER_TYPE(FHitProxyDS,MeshMaterial);
|
|
|
|
protected:
|
|
|
|
FHitProxyDS() {}
|
|
|
|
FHitProxyDS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FBaseDS(Initializer)
|
|
{}
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
return FBaseDS::ShouldCache(Platform, Material, VertexFactoryType)
|
|
&& FHitProxyVS::ShouldCache(Platform,Material,VertexFactoryType);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(,FHitProxyHS,TEXT("HitProxyVertexShader"),TEXT("MainHull"),SF_Hull);
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(,FHitProxyDS,TEXT("HitProxyVertexShader"),TEXT("MainDomain"),SF_Domain);
|
|
|
|
/**
|
|
* A pixel shader for rendering the HitProxyId of an object as a unique color in the scene.
|
|
*/
|
|
class FHitProxyPS : public FMeshMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FHitProxyPS,MeshMaterial);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
// Only compile the hit proxy vertex shader on PC
|
|
return IsPCPlatform(Platform)
|
|
// and only compile for default materials or materials that are masked.
|
|
&& (Material->IsSpecialEngineMaterial() || !Material->WritesEveryPixel() || Material->MaterialMayModifyMeshPosition() || Material->IsTwoSided());
|
|
}
|
|
|
|
FHitProxyPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FMeshMaterialShader(Initializer)
|
|
{
|
|
HitProxyId.Bind(Initializer.ParameterMap,TEXT("HitProxyId"), SPF_Mandatory);
|
|
}
|
|
|
|
FHitProxyPS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FMaterialRenderProxy* MaterialRenderProxy,const FSceneView& View)
|
|
{
|
|
FMeshMaterialShader::SetParameters(RHICmdList, GetPixelShader(), MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(View.GetFeatureLevel()), View, ESceneRenderTargetsMode::SetTextures);
|
|
}
|
|
|
|
void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement, float DitheredLODTransitionValue)
|
|
{
|
|
FMeshMaterialShader::SetMesh(RHICmdList, GetPixelShader(),VertexFactory,View,Proxy,BatchElement,DitheredLODTransitionValue);
|
|
}
|
|
|
|
void SetHitProxyId(FRHICommandList& RHICmdList, FHitProxyId HitProxyIdValue)
|
|
{
|
|
SetShaderValue(RHICmdList, GetPixelShader(), HitProxyId, HitProxyIdValue.GetColor().ReinterpretAsLinear());
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
|
|
Ar << HitProxyId;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FShaderParameter HitProxyId;
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(,FHitProxyPS,TEXT("HitProxyPixelShader"),TEXT("Main"),SF_Pixel);
|
|
|
|
FHitProxyDrawingPolicy::FHitProxyDrawingPolicy(
|
|
const FVertexFactory* InVertexFactory,
|
|
const FMaterialRenderProxy* InMaterialRenderProxy,
|
|
ERHIFeatureLevel::Type InFeatureLevel
|
|
):
|
|
FMeshDrawingPolicy(InVertexFactory, InMaterialRenderProxy, *InMaterialRenderProxy->GetMaterial(InFeatureLevel))
|
|
{
|
|
HullShader = NULL;
|
|
DomainShader = NULL;
|
|
|
|
EMaterialTessellationMode MaterialTessellationMode = MaterialResource->GetTessellationMode();
|
|
if (RHISupportsTessellation(GShaderPlatformForFeatureLevel[InFeatureLevel])
|
|
&& InVertexFactory->GetType()->SupportsTessellationShaders()
|
|
&& MaterialTessellationMode != MTM_NoTessellation)
|
|
{
|
|
HullShader = MaterialResource->GetShader<FHitProxyHS>(VertexFactory->GetType());
|
|
DomainShader = MaterialResource->GetShader<FHitProxyDS>(VertexFactory->GetType());
|
|
}
|
|
VertexShader = MaterialResource->GetShader<FHitProxyVS>(InVertexFactory->GetType());
|
|
PixelShader = MaterialResource->GetShader<FHitProxyPS>(InVertexFactory->GetType());
|
|
}
|
|
|
|
void FHitProxyDrawingPolicy::SetSharedState(FRHICommandList& RHICmdList, const FSceneView* View, const ContextDataType PolicyContext) const
|
|
{
|
|
// Set the depth-only shader parameters for the material.
|
|
VertexShader->SetParameters(RHICmdList, MaterialRenderProxy,*View);
|
|
PixelShader->SetParameters(RHICmdList, MaterialRenderProxy,*View);
|
|
|
|
if(HullShader && DomainShader)
|
|
{
|
|
HullShader->SetParameters(RHICmdList, MaterialRenderProxy,*View);
|
|
DomainShader->SetParameters(RHICmdList, MaterialRenderProxy,*View);
|
|
}
|
|
|
|
// Set the shared mesh resources.
|
|
FMeshDrawingPolicy::SetSharedState(RHICmdList, View, PolicyContext);
|
|
}
|
|
|
|
/**
|
|
* Create bound shader state using the vertex decl from the mesh draw policy
|
|
* as well as the shaders needed to draw the mesh
|
|
* @return new bound shader state object
|
|
*/
|
|
FBoundShaderStateInput FHitProxyDrawingPolicy::GetBoundShaderStateInput(ERHIFeatureLevel::Type InFeatureLevel)
|
|
{
|
|
return FBoundShaderStateInput(
|
|
FMeshDrawingPolicy::GetVertexDeclaration(),
|
|
VertexShader->GetVertexShader(),
|
|
GETSAFERHISHADER_HULL(HullShader),
|
|
GETSAFERHISHADER_DOMAIN(DomainShader),
|
|
PixelShader->GetPixelShader(),
|
|
FGeometryShaderRHIRef());
|
|
}
|
|
|
|
void FHitProxyDrawingPolicy::SetMeshRenderState(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
const FMeshBatch& Mesh,
|
|
int32 BatchElementIndex,
|
|
bool bBackFace,
|
|
float DitheredLODTransitionValue,
|
|
const FHitProxyId HitProxyId,
|
|
const ContextDataType PolicyContext
|
|
) const
|
|
{
|
|
EmitMeshDrawEvents(RHICmdList, PrimitiveSceneProxy, Mesh);
|
|
|
|
const FMeshBatchElement& BatchElement = Mesh.Elements[BatchElementIndex];
|
|
|
|
VertexShader->SetMesh(RHICmdList, VertexFactory, View, PrimitiveSceneProxy, BatchElement,DitheredLODTransitionValue);
|
|
|
|
if(HullShader && DomainShader)
|
|
{
|
|
HullShader->SetMesh(RHICmdList, VertexFactory, View, PrimitiveSceneProxy, BatchElement,DitheredLODTransitionValue);
|
|
DomainShader->SetMesh(RHICmdList, VertexFactory, View, PrimitiveSceneProxy, BatchElement,DitheredLODTransitionValue);
|
|
}
|
|
|
|
PixelShader->SetMesh(RHICmdList, VertexFactory, View, PrimitiveSceneProxy, BatchElement,DitheredLODTransitionValue);
|
|
// Per-instance hitproxies are supplied by the vertex factory
|
|
if( PrimitiveSceneProxy && PrimitiveSceneProxy->HasPerInstanceHitProxies() )
|
|
{
|
|
PixelShader->SetHitProxyId(RHICmdList, FColor(0) );
|
|
}
|
|
else
|
|
{
|
|
PixelShader->SetHitProxyId(RHICmdList, HitProxyId);
|
|
}
|
|
|
|
RHICmdList.SetRasterizerState(GetStaticRasterizerState<false>(
|
|
(Mesh.bWireframe || IsWireframe()) ? FM_Wireframe : FM_Solid,
|
|
((IsTwoSided() && !NeedsBackfacePass()) || Mesh.bDisableBackfaceCulling) ? CM_None :
|
|
(XOR(XOR(View.bReverseCulling,bBackFace), Mesh.ReverseCulling) ? CM_CCW : CM_CW)
|
|
));
|
|
}
|
|
|
|
void FHitProxyDrawingPolicyFactory::AddStaticMesh(FScene* Scene,FStaticMesh* StaticMesh,ContextType)
|
|
{
|
|
checkSlow( Scene->RequiresHitProxies() );
|
|
|
|
// Add the static mesh to the DPG's hit proxy draw list.
|
|
const FMaterialRenderProxy* MaterialRenderProxy = StaticMesh->MaterialRenderProxy;
|
|
const FMaterial* Material = MaterialRenderProxy->GetMaterial(Scene->GetFeatureLevel());
|
|
if (Material->WritesEveryPixel() && !Material->IsTwoSided() && !Material->MaterialModifiesMeshPosition_RenderThread())
|
|
{
|
|
// Default material doesn't handle masked, and doesn't have the correct bIsTwoSided setting.
|
|
MaterialRenderProxy = UMaterial::GetDefaultMaterial(MD_Surface)->GetRenderProxy(false);
|
|
}
|
|
|
|
Scene->HitProxyDrawList.AddMesh(
|
|
StaticMesh,
|
|
StaticMesh->BatchHitProxyId,
|
|
FHitProxyDrawingPolicy(StaticMesh->VertexFactory, MaterialRenderProxy, Scene->GetFeatureLevel()),
|
|
Scene->GetFeatureLevel()
|
|
);
|
|
|
|
#if WITH_EDITOR
|
|
// If the mesh isn't translucent then we'll also add it to the "opaque-only" draw list. Depending
|
|
// on user preferences in the editor, we may use this draw list to disallow selection of
|
|
// translucent objects in perspective viewports
|
|
if( !IsTranslucentBlendMode( Material->GetBlendMode() ) )
|
|
{
|
|
Scene->HitProxyDrawList_OpaqueOnly.AddMesh(
|
|
StaticMesh,
|
|
StaticMesh->BatchHitProxyId,
|
|
FHitProxyDrawingPolicy(StaticMesh->VertexFactory, MaterialRenderProxy, Scene->GetFeatureLevel()),
|
|
Scene->GetFeatureLevel()
|
|
);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
bool FHitProxyDrawingPolicyFactory::DrawDynamicMesh(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
ContextType DrawingContext,
|
|
const FMeshBatch& Mesh,
|
|
bool bBackFace,
|
|
bool bPreFog,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
FHitProxyId HitProxyId
|
|
)
|
|
{
|
|
if (!PrimitiveSceneProxy || PrimitiveSceneProxy->IsSelectable())
|
|
{
|
|
const FMaterialRenderProxy* MaterialRenderProxy = Mesh.MaterialRenderProxy;
|
|
const FMaterial* Material = MaterialRenderProxy->GetMaterial(View.GetFeatureLevel());
|
|
#if WITH_EDITOR
|
|
const HHitProxy* HitProxy = GetHitProxyById( HitProxyId );
|
|
// Only draw translucent primitives to the hit proxy if the user wants those objects to be selectable
|
|
if( View.bAllowTranslucentPrimitivesInHitProxy || !IsTranslucentBlendMode( Material->GetBlendMode() ) || ( HitProxy && HitProxy->AlwaysAllowsTranslucentPrimitives() ) )
|
|
#endif
|
|
{
|
|
if (Material->WritesEveryPixel() && !Material->IsTwoSided() && !Material->MaterialModifiesMeshPosition_RenderThread())
|
|
{
|
|
// Default material doesn't handle masked, and doesn't have the correct bIsTwoSided setting.
|
|
MaterialRenderProxy = UMaterial::GetDefaultMaterial(MD_Surface)->GetRenderProxy(false);
|
|
}
|
|
FHitProxyDrawingPolicy DrawingPolicy( Mesh.VertexFactory, MaterialRenderProxy, View.GetFeatureLevel() );
|
|
RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel()));
|
|
DrawingPolicy.SetSharedState(RHICmdList, &View, FHitProxyDrawingPolicy::ContextDataType());
|
|
for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++)
|
|
{
|
|
DrawingPolicy.SetMeshRenderState(RHICmdList, View, PrimitiveSceneProxy, Mesh, BatchElementIndex, bBackFace, Mesh.DitheredLODTransitionAlpha, HitProxyId, FHitProxyDrawingPolicy::ContextDataType());
|
|
DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
|
|
TRefCountPtr<IPooledRenderTarget> InitHitProxyRender(FRHICommandListImmediate& RHICmdList, const FSceneRenderer* SceneRenderer)
|
|
{
|
|
auto& ViewFamily = SceneRenderer->ViewFamily;
|
|
auto FeatureLevel = ViewFamily.Scene->GetFeatureLevel();
|
|
|
|
// Initialize global system textures (pass-through if already initialized).
|
|
GSystemTextures.InitializeTextures(RHICmdList, FeatureLevel);
|
|
|
|
// Allocate the maximum scene render target space for the current view family.
|
|
GSceneRenderTargets.Allocate(ViewFamily);
|
|
|
|
TRefCountPtr<IPooledRenderTarget> HitProxyRT;
|
|
|
|
// Create a texture to store the resolved light attenuation values, and a render-targetable surface to hold the unresolved light attenuation values.
|
|
{
|
|
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(GSceneRenderTargets.GetBufferSizeXY(), PF_B8G8R8A8, TexCreate_None, TexCreate_RenderTargetable, false));
|
|
Desc.Flags |= TexCreate_FastVRAM;
|
|
GRenderTargetPool.FindFreeElement(Desc, HitProxyRT, TEXT("HitProxy"));
|
|
}
|
|
|
|
if (!HitProxyRT)
|
|
{
|
|
// HitProxyRT==0 should never happen but better we don't crash
|
|
return HitProxyRT;
|
|
}
|
|
|
|
SetRenderTarget(RHICmdList, HitProxyRT->GetRenderTargetItem().TargetableTexture, GSceneRenderTargets.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthWrite_StencilWrite);
|
|
|
|
// Clear color for each view.
|
|
auto& Views = SceneRenderer->Views;
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
|
|
RHICmdList.Clear(true, FLinearColor::White, false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect());
|
|
}
|
|
return HitProxyRT;
|
|
}
|
|
|
|
void RenderHitProxies(FRHICommandListImmediate& RHICmdList, const FSceneRenderer* SceneRenderer, TRefCountPtr<IPooledRenderTarget> HitProxyRT)
|
|
{
|
|
auto & ViewFamily = SceneRenderer->ViewFamily;
|
|
auto & Views = SceneRenderer->Views;
|
|
|
|
const auto FeatureLevel = SceneRenderer->FeatureLevel;
|
|
|
|
// Dynamic vertex and index buffers need to be committed before rendering.
|
|
FGlobalDynamicVertexBuffer::Get().Commit();
|
|
FGlobalDynamicIndexBuffer::Get().Commit();
|
|
|
|
// Depth tests + writes, no alpha blending.
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
|
|
const bool bNeedToSwitchVerticalAxis = RHINeedsToSwitchVerticalAxis(GShaderPlatformForFeatureLevel[SceneRenderer->FeatureLevel]);
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
|
|
// Set the device viewport for the view.
|
|
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
|
|
|
|
// Clear the depth buffer for each DPG.
|
|
RHICmdList.Clear(false, FLinearColor::Black, true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect());
|
|
|
|
// Adjust the visibility map for this view
|
|
if (!View.bAllowTranslucentPrimitivesInHitProxy)
|
|
{
|
|
// Draw the scene's hit proxy draw lists. (opaque primitives only)
|
|
SceneRenderer->Scene->HitProxyDrawList_OpaqueOnly.DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility);
|
|
}
|
|
else
|
|
{
|
|
// Draw the scene's hit proxy draw lists.
|
|
SceneRenderer->Scene->HitProxyDrawList.DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility);
|
|
}
|
|
|
|
const bool bPreFog = true;
|
|
const bool bHitTesting = true;
|
|
|
|
FHitProxyDrawingPolicyFactory::ContextType DrawingContext;
|
|
|
|
for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++)
|
|
{
|
|
const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex];
|
|
const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh;
|
|
|
|
if (MeshBatch.bSelectable)
|
|
{
|
|
const FHitProxyId EffectiveHitProxyId = MeshBatch.BatchHitProxyId == FHitProxyId() ? MeshBatchAndRelevance.PrimitiveSceneProxy->GetPrimitiveSceneInfo()->DefaultDynamicHitProxyId : MeshBatch.BatchHitProxyId;
|
|
FHitProxyDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, View, DrawingContext, MeshBatch, false, bPreFog, MeshBatchAndRelevance.PrimitiveSceneProxy, EffectiveHitProxyId);
|
|
}
|
|
}
|
|
|
|
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, View, FTexture2DRHIRef(), EBlendModeFilter::All);
|
|
|
|
for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicEditorMeshElements.Num(); MeshBatchIndex++)
|
|
{
|
|
const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicEditorMeshElements[MeshBatchIndex];
|
|
const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh;
|
|
|
|
if (MeshBatch.bSelectable)
|
|
{
|
|
const FHitProxyId EffectiveHitProxyId = MeshBatch.BatchHitProxyId == FHitProxyId() ? MeshBatchAndRelevance.PrimitiveSceneProxy->GetPrimitiveSceneInfo()->DefaultDynamicHitProxyId : MeshBatch.BatchHitProxyId;
|
|
FHitProxyDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, View, DrawingContext, MeshBatch, false, bPreFog, MeshBatchAndRelevance.PrimitiveSceneProxy, EffectiveHitProxyId);
|
|
}
|
|
}
|
|
|
|
View.EditorSimpleElementCollector.DrawBatchedElements(RHICmdList, View, FTexture2DRHIRef(), EBlendModeFilter::All);
|
|
|
|
// Draw the view's elements.
|
|
DrawViewElements<FHitProxyDrawingPolicyFactory>(RHICmdList, View, FHitProxyDrawingPolicyFactory::ContextType(), SDPG_World, bPreFog);
|
|
|
|
// Draw the view's batched simple elements(lines, sprites, etc).
|
|
View.BatchedViewElements.Draw(RHICmdList, FeatureLevel, bNeedToSwitchVerticalAxis, View.ViewProjectionMatrix, View.ViewRect.Width(), View.ViewRect.Height(), true);
|
|
|
|
// Some elements should never be occluded (e.g. gizmos).
|
|
// So we render those twice, first to overwrite potentially nearer objects,
|
|
// then again to allows proper occlusion within those elements.
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
// Draw the view's foreground elements last.
|
|
DrawViewElements<FHitProxyDrawingPolicyFactory>(RHICmdList, View, FHitProxyDrawingPolicyFactory::ContextType(), SDPG_Foreground, bPreFog);
|
|
|
|
View.TopBatchedViewElements.Draw(RHICmdList, FeatureLevel, bNeedToSwitchVerticalAxis, View.ViewProjectionMatrix, View.ViewRect.Width(), View.ViewRect.Height(), true);
|
|
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI());
|
|
// Draw the view's foreground elements last.
|
|
DrawViewElements<FHitProxyDrawingPolicyFactory>(RHICmdList, View, FHitProxyDrawingPolicyFactory::ContextType(), SDPG_Foreground, bPreFog);
|
|
|
|
View.TopBatchedViewElements.Draw(RHICmdList, FeatureLevel, bNeedToSwitchVerticalAxis, View.ViewProjectionMatrix, View.ViewRect.Width(), View.ViewRect.Height(), true);
|
|
}
|
|
|
|
// Finish drawing to the hit proxy render target.
|
|
RHICmdList.CopyToResolveTarget(HitProxyRT->GetRenderTargetItem().TargetableTexture, HitProxyRT->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
|
|
// to be able to observe results with VisualizeTexture
|
|
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, HitProxyRT);
|
|
|
|
// After scene rendering, disable the depth buffer.
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
|
|
//
|
|
// Copy the hit proxy buffer into the view family's render target.
|
|
//
|
|
|
|
// Set up a FTexture that is used to draw the hit proxy buffer to the view family's render target.
|
|
FTexture HitProxyRenderTargetTexture;
|
|
HitProxyRenderTargetTexture.TextureRHI = HitProxyRT->GetRenderTargetItem().ShaderResourceTexture;
|
|
HitProxyRenderTargetTexture.SamplerStateRHI = TStaticSamplerState<>::GetRHI();
|
|
|
|
// Generate the vertices and triangles mapping the hit proxy RT pixels into the view family's RT pixels.
|
|
FBatchedElements BatchedElements;
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
|
|
FIntPoint BufferSize = GSceneRenderTargets.GetBufferSizeXY();
|
|
float InvBufferSizeX = 1.0f / BufferSize.X;
|
|
float InvBufferSizeY = 1.0f / BufferSize.Y;
|
|
|
|
const float U0 = View.ViewRect.Min.X * InvBufferSizeX;
|
|
const float V0 = View.ViewRect.Min.Y * InvBufferSizeY;
|
|
const float U1 = View.ViewRect.Max.X * InvBufferSizeX;
|
|
const float V1 = View.ViewRect.Max.Y * InvBufferSizeY;
|
|
|
|
const int32 V00 = BatchedElements.AddVertex(FVector4(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, 1),FVector2D(U0, V0), FLinearColor::White, FHitProxyId());
|
|
const int32 V10 = BatchedElements.AddVertex(FVector4(View.ViewRect.Max.X, View.ViewRect.Min.Y, 0, 1),FVector2D(U1, V0), FLinearColor::White, FHitProxyId());
|
|
const int32 V01 = BatchedElements.AddVertex(FVector4(View.ViewRect.Min.X, View.ViewRect.Max.Y, 0, 1),FVector2D(U0, V1), FLinearColor::White, FHitProxyId());
|
|
const int32 V11 = BatchedElements.AddVertex(FVector4(View.ViewRect.Max.X, View.ViewRect.Max.Y, 0, 1),FVector2D(U1, V1), FLinearColor::White, FHitProxyId());
|
|
|
|
BatchedElements.AddTriangle(V00,V10,V11,&HitProxyRenderTargetTexture,BLEND_Opaque);
|
|
BatchedElements.AddTriangle(V00,V11,V01,&HitProxyRenderTargetTexture,BLEND_Opaque);
|
|
}
|
|
|
|
// Generate a transform which maps from view family RT pixel coordinates to Normalized Device Coordinates.
|
|
FIntPoint RenderTargetSize = ViewFamily.RenderTarget->GetSizeXY();
|
|
|
|
const FMatrix PixelToView =
|
|
FTranslationMatrix(FVector(0, 0, 0)) *
|
|
FMatrix(
|
|
FPlane( 1.0f / ((float)RenderTargetSize.X / 2.0f), 0.0, 0.0f, 0.0f ),
|
|
FPlane( 0.0f, -GProjectionSignY / ((float)RenderTargetSize.Y / 2.0f), 0.0f, 0.0f ),
|
|
FPlane( 0.0f, 0.0f, 1.0f, 0.0f ),
|
|
FPlane( -1.0f, GProjectionSignY, 0.0f, 1.0f )
|
|
);
|
|
|
|
// Draw the triangles to the view family's render target.
|
|
SetRenderTarget(RHICmdList, ViewFamily.RenderTarget->GetRenderTargetTexture(), FTextureRHIRef());
|
|
BatchedElements.Draw(
|
|
RHICmdList,
|
|
FeatureLevel,
|
|
bNeedToSwitchVerticalAxis,
|
|
PixelToView,
|
|
RenderTargetSize.X,
|
|
RenderTargetSize.Y,
|
|
false,
|
|
1.0f
|
|
);
|
|
|
|
RHICmdList.EndScene();
|
|
}
|
|
#endif
|
|
|
|
void FForwardShadingSceneRenderer::RenderHitProxies(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
#if WITH_EDITOR
|
|
TRefCountPtr<IPooledRenderTarget> HitProxyRT = ::InitHitProxyRender(RHICmdList, this);
|
|
// HitProxyRT==0 should never happen but better we don't crash
|
|
if (HitProxyRT)
|
|
{
|
|
// Find the visible primitives.
|
|
InitViews(RHICmdList);
|
|
::RenderHitProxies(RHICmdList, this, HitProxyRT);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::RenderHitProxies(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
#if WITH_EDITOR
|
|
TRefCountPtr<IPooledRenderTarget> HitProxyRT = ::InitHitProxyRender(RHICmdList, this);
|
|
// HitProxyRT==0 should never happen but better we don't crash
|
|
if (HitProxyRT)
|
|
{
|
|
// Find the visible primitives.
|
|
InitViews(RHICmdList);
|
|
::RenderHitProxies(RHICmdList, this, HitProxyRT);
|
|
}
|
|
#endif
|
|
}
|