// 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(VertexFactory->GetType()); DomainShader = MaterialResource->GetShader(VertexFactory->GetType()); } VertexShader = MaterialResource->GetShader(InVertexFactory->GetType()); PixelShader = MaterialResource->GetShader(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( (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 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 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 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::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(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::GetRHI()); // Draw the view's foreground elements last. DrawViewElements(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::GetRHI()); // Draw the view's foreground elements last. DrawViewElements(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::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 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 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 }