a

Lorem ipsum dolor sit amet, elit eget consectetuer adipiscing aenean dolor

Image Alt

Geodesic Games

Custom Stereo-Rendering Gem in Lumberyard

Step by step guide how you could create generic lumberyard gem and do custom stereo rendering in Lumberyard engine.

Last version of gem you could find in Github https://github.com/Batname/StereoRendering

1. I hope you already downloaded and installed the latest version of Lumberyard. If not, you can find it here: https://aws.amazon.com/lumberyard/downloads/

2. Create a new gem inside StarterGame

 

3. Download and install DirectX SDK https://www.microsoft.com/en-us/download/details.aspx?id=6812 . use default installation settings. We need DirectX SDK for custom stereo rendering pipeline inside Lumberyard Engine and compilation DirectX HLSH shaders

4. Our next steps will be related to Source code of StereoRendering plugin, so please download it from Github https://github.com/Batname/StereoRendering

5. Let’s take a look into Gem configuration files first. First, start from wscript inside StereoRendering/Code. IMPORTANT: here you need to provide a path to DirectX SDK lib and include, as our gem code is the default path to SDK, which was set after installation of DirectX SDK

def build(bld):
    bld.DefineGem(

        # Compiler Specific
         win_cxxflags = [
            '/WX-'
        ],

        win_lib             = [ 'd3d11',
                                'd3dx11',
                                'd3dx10'
                            ],

        includes    = [
                        bld.Path('Code/CryEngine/CryCommon'),
                        bld.Path('Code/CryEngine/CryAction'),
                        'C:\\Program Files (x86)\\Microsoft DirectX SDK (June 2010)\\Include'
                       ],

        # General
        file_list               = ['sr.waf_files'],

        win_stlibpath = ['C:\\Program Files (x86)\\Microsoft DirectX SDK (June 2010)\\Lib\\x64'],
    )

6. Next lets look at sr.waf_files inside StereoRendering/Code. This file is responsible for the configuration for compiling C++ for your gem. This file should contain all C++ source and header files which we need to compile

{
    "none": {
        "Source": [
            "Source/SR_precompiled.cpp",
            "Source/SR_precompiled.h"
        ]
    },
    "auto": {
        "Include": [
            "Include/SR/SRBus.h"
        ],
        "Source": [
            "Source/SRGem.cpp"
        ],
        "Implementation": [
            "Source/SRDevice.h",
            "Source/SRDevice.cpp"
        ]
        ,
        "Rendering": [
            "Source/SRRenderer.h",
            "Source/SRRenderer.cpp",
            "Source/SRUtils.h",
            "Source/SRUtils.cpp"
        ]
    }
} 

7. Ok, lets try to understand all c++ source files

 

  • SRGem.ccp – this is the main gem plugin, where we defined all system components and console variables, it is the initial point for gem execution
  • SRDevice.cpp – this is the component which is responsible for running lumberyard in stereo mode, creation stereo left and right render targets, provide dynamic variables for rendering (for projection matrices, the position of the user in space, etc)
  • SRRendering.cpp – this is a Class for custom stereo rendering, it is content logic from DirectX stereo rendering pipeline, access to custom shaders. You could include your own custom shaders here and it will draw to back buffer at last moment before frame will be presented to screen.
  • If you go to StereoRendering /Assets/Shaders you could find stereorendering.cfx Shader which is responsible for Stereo Rendering. That is the place where you could write shader logic.
Texture2D LeftTexture : register(t0); // Texture from framebuffer
SamplerState LeftTextureSamplerState : register(s0);

Texture2D RightTexture : register(t1); // Texture from framebuffer
SamplerState RightTextureSamplerState : register(s1);

cbuffer cbPerObject
{
	// 1rd Group of 16 bytes
	int ScreenSize; // 8 bytes 4 * 2
	float pad1; // 4 bytes
	float pad2; // 4 bytes
};

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
	float2 TexCoord : TEXCOORD0;
};

VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD)
{
    VS_OUTPUT output;

    output.Pos = inPos;
    output.TexCoord = inTexCoord;

    return output;
}

float4 PS(VS_OUTPUT input) : SV_TARGET
{
    input.TexCoord.x*=2;
    if (input.Pos.x < ScreenSize.x / 2)
    {
    	return LeftTexture.Sample(LeftTextureSamplerState, input.TexCoord);
    }
    else
    {
    	return RightTexture.Sample(RightTextureSamplerState, input.TexCoord);
    }
}

 

Profiling stereo rendering
If you really want to understand how rendering is done you need to start profiling in SRDevice.cpp, just go to SRDevice::SubmitFrame() function, this the place where you could start debugging

	void SRDevice::SubmitFrame(const EyeTarget & left, const EyeTarget & right)
	{
		if (m_SRRenderer.get() != nullptr)
		{
			m_SRRenderer->UpdateScene();
			m_SRRenderer->DrawScene();
		}
	}

DrawScene() function contains all logic for DirectX 11 rendering pipeline

	void SRRenderer::DrawScene()
	{
		//Set the Input Layout
		d3d11DevCon->IASetInputLayout(vertLayout);

		//Set Primitive Topology
		d3d11DevCon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

		//Set the spheres index buffer
		d3d11DevCon->IASetIndexBuffer(squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

		//Set the spheres vertex buffer
		UINT stride = sizeof(Vertex);
		UINT offset = 0;
		d3d11DevCon->IASetVertexBuffers(0, 1, &squareVertBuffer, &stride, &offset);

		//Set the new VS and PS shaders
		d3d11DevCon->VSSetShader(VS, 0, 0);
		d3d11DevCon->PSSetShader(PS, 0, 0);

		// Set texture resources
		d3d11DevCon->PSSetShaderResources(0, 1, &LeftTextureRV);
		d3d11DevCon->PSSetSamplers(0, 1, &TexSamplerState);
		d3d11DevCon->PSSetShaderResources(1, 1, &RightTextureRV);
		d3d11DevCon->PSSetSamplers(1, 1, &TexSamplerState);

		// Update constant buffer
		d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
		d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);
		d3d11DevCon->PSSetConstantBuffers(0, 1, &cbPerObjectBuffer);

		//Draw the triangle
		d3d11DevCon->DrawIndexed(6, 0, 0);
	}

You can look deeper into the rendering pipeline with RenderDoc GPU debugger https://renderdoc.org/