void DrawRectangle( float X, float Y, float SizeX, float SizeY, float U, float V, float SizeU, float SizeV, FIntPoint TargetSize, FIntPoint TextureSize, EDrawRectangleFlags Flags ) { float ClipSpaceQuadZ = 0.0f; DoDrawRectangleFlagOverride(Flags); // triangle if extending to left and top of the given rectangle, if it's not left top of the viewport it can cause artifacts if(X > 0.0f || Y > 0.0f) { // don't use triangle optimization Flags = EDRF_Default; } if (Flags == EDRF_UseTriangleOptimization) { // A single triangle spans the entire viewport this results in a quad that fill the viewport. This can increase rasterization efficiency // as we do not have a diagonal edge (through the center) for the rasterizer/span-dispatch. Although the actual benefit of this technique is dependent upon hardware. FFilterVertex Vertices[3]; Vertices[0].Position = FVector4(X + SizeX, Y - SizeY, ClipSpaceQuadZ, 1); Vertices[1].Position = FVector4(X + SizeX, Y + SizeY, ClipSpaceQuadZ, 1); Vertices[2].Position = FVector4(X - SizeX, Y + SizeY , ClipSpaceQuadZ, 1); Vertices[0].UV = FVector2D(U + SizeU, V - SizeV); Vertices[1].UV = FVector2D(U + SizeU, V + SizeV); Vertices[2].UV = FVector2D(U - SizeU, V + SizeV); for (int32 VertexIndex = 0; VertexIndex < 3; VertexIndex++) { Vertices[VertexIndex].Position.X = -1.0f + 2.0f * (Vertices[VertexIndex].Position.X - GPixelCenterOffset) / (float)TargetSize.X; Vertices[VertexIndex].Position.Y = (+1.0f - 2.0f * (Vertices[VertexIndex].Position.Y - GPixelCenterOffset) / (float)TargetSize.Y) * GProjectionSignY; Vertices[VertexIndex].UV.X = Vertices[VertexIndex].UV.X / (float)TextureSize.X; Vertices[VertexIndex].UV.Y = Vertices[VertexIndex].UV.Y / (float)TextureSize.Y; } static const uint16 Indices[] = { 0, 1, 2 }; RHIDrawIndexedPrimitiveUP(PT_TriangleList, 0, 3, 1, Indices, sizeof(Indices[0]), Vertices, sizeof(Vertices[0])); } else { FFilterVertex Vertices[4]; Vertices[0].Position = FVector4(X, Y, ClipSpaceQuadZ, 1); Vertices[1].Position = FVector4(X + SizeX, Y, ClipSpaceQuadZ, 1); Vertices[2].Position = FVector4(X, Y + SizeY, ClipSpaceQuadZ, 1); Vertices[3].Position = FVector4(X + SizeX, Y + SizeY, ClipSpaceQuadZ, 1); Vertices[0].UV = FVector2D(U, V); Vertices[1].UV = FVector2D(U + SizeU, V); Vertices[2].UV = FVector2D(U, V + SizeV); Vertices[3].UV = FVector2D(U + SizeU, V + SizeV); for (int32 VertexIndex = 0; VertexIndex < 4; VertexIndex++) { Vertices[VertexIndex].Position.X = -1.0f + 2.0f * (Vertices[VertexIndex].Position.X - GPixelCenterOffset) / (float)TargetSize.X; Vertices[VertexIndex].Position.Y = (+1.0f - 2.0f * (Vertices[VertexIndex].Position.Y - GPixelCenterOffset) / (float)TargetSize.Y) * GProjectionSignY; Vertices[VertexIndex].UV.X = Vertices[VertexIndex].UV.X / (float)TextureSize.X; Vertices[VertexIndex].UV.Y = Vertices[VertexIndex].UV.Y / (float)TextureSize.Y; } static const uint16 Indices[] = { 0, 1, 3, 0, 3, 2 }; RHIDrawIndexedPrimitiveUP(PT_TriangleList, 0, 4, 2, Indices, sizeof(Indices[0]), Vertices, sizeof(Vertices[0])); } }
void DrawRectangle( FRHICommandList& RHICmdList, float X, float Y, float SizeX, float SizeY, float U, float V, float SizeU, float SizeV, FIntPoint TargetSize, FIntPoint TextureSize, FShader* VertexShader, EDrawRectangleFlags Flags ) { float ClipSpaceQuadZ = 0.0f; DoDrawRectangleFlagOverride(Flags); // triangle if extending to left and top of the given rectangle, if it's not left top of the viewport it can cause artifacts if(X > 0.0f || Y > 0.0f) { // don't use triangle optimization Flags = EDRF_Default; } // Set up vertex uniform parameters for scaling and biasing the rectangle. // Note: Use DrawRectangle in the vertex shader to calculate the correct vertex position and uv. FDrawRectangleParameters Parameters; Parameters.PosScaleBias = FVector4(SizeX, SizeY, X, Y); Parameters.UVScaleBias = FVector4(SizeU, SizeV, U, V); Parameters.InvTargetSizeAndTextureSize = FVector4( 1.0f / TargetSize.X, 1.0f / TargetSize.Y, 1.0f / TextureSize.X, 1.0f / TextureSize.Y); SetUniformBufferParameterImmediate(RHICmdList, VertexShader->GetVertexShader(), VertexShader->GetUniformBufferParameter<FDrawRectangleParameters>(), Parameters); if(Flags == EDRF_UseTesselatedIndexBuffer) { // no vertex buffer needed as we compute it in VS RHICmdList.SetStreamSource(0, NULL, 0, 0); RHICmdList.DrawIndexedPrimitive( GTesselatedScreenRectangleIndexBuffer.IndexBufferRHI, PT_TriangleList, /*BaseVertexIndex=*/ 0, /*MinIndex=*/ 0, /*NumVertices=*/ GTesselatedScreenRectangleIndexBuffer.NumVertices(), /*StartIndex=*/ 0, /*NumPrimitives=*/ GTesselatedScreenRectangleIndexBuffer.NumPrimitives(), /*NumInstances=*/ 1 ); } else { RHICmdList.SetStreamSource(0, GScreenRectangleVertexBuffer.VertexBufferRHI, sizeof(FFilterVertex), 0); if (Flags == EDRF_UseTriangleOptimization) { // A single triangle spans the entire viewport this results in a quad that fill the viewport. This can increase rasterization efficiency // as we do not have a diagonal edge (through the center) for the rasterizer/span-dispatch. Although the actual benefit of this technique is dependent upon hardware. // We offset into the index buffer when using the triangle optimization to access the correct vertices. RHICmdList.DrawIndexedPrimitive( GScreenRectangleIndexBuffer.IndexBufferRHI, PT_TriangleList, /*BaseVertexIndex=*/ 0, /*MinIndex=*/ 0, /*NumVertices=*/ 3, /*StartIndex=*/ 6, /*NumPrimitives=*/ 1, /*NumInstances=*/ 1 ); } else { RHICmdList.SetStreamSource(0, GScreenRectangleVertexBuffer.VertexBufferRHI, sizeof(FFilterVertex), 0); RHICmdList.DrawIndexedPrimitive( GScreenRectangleIndexBuffer.IndexBufferRHI, PT_TriangleList, /*BaseVertexIndex=*/ 0, /*MinIndex=*/ 0, /*NumVertices=*/ 4, /*StartIndex=*/ 0, /*NumPrimitives=*/ 2, /*NumInstances=*/ 1 ); } } }