//[-------------------------------------------------------] //[ Public virtual IApplication methods ] //[-------------------------------------------------------] void FirstGeometryShader::onInitialization() { // Call the base implementation IApplicationRenderer::onInitialization(); // Get and check the renderer instance // -> Geometry shaders supported? Renderer::IRendererPtr renderer(getRenderer()); if (nullptr != renderer && renderer->getCapabilities().maximumNumberOfGsOutputVertices) { // Begin debug event RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer) // Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg") Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage()); if (nullptr != shaderLanguage) { { // Create the program // Get the shader source code (outsourced to keep an overview) const char *vertexShaderSourceCode = nullptr; const char *geometryShaderSourceCode = nullptr; const char *fragmentShaderSourceCode = nullptr; #include "FirstGeometryShader_GLSL_330.h" #include "FirstGeometryShader_HLSL_D3D10_D3D11.h" #include "FirstGeometryShader_Null.h" // Create the program mProgram = shaderLanguage->createProgram( shaderLanguage->createVertexShader(vertexShaderSourceCode), shaderLanguage->createGeometryShader(geometryShaderSourceCode, Renderer::GsInputPrimitiveTopology::POINTS, Renderer::GsOutputPrimitiveTopology::TRIANGLE_STRIP, 3), shaderLanguage->createFragmentShader(fragmentShaderSourceCode)); } // TODO(co) Attribute less rendering (aka "drawing without data") possible with OpenGL? For me it appears not to work, I see nothing and also get no error... // -> Tested with: "Radeon HD 6970M", driver "catalyst_12-7_beta_windows7_20120629.exe" // -> According to http://renderingpipeline.com/2012/03/are-vertex-shaders-obsolete/ it should work // -> Apparently there are currently some issues when using this approach: http://www.opengl.org/discussion_boards/showthread.php/177372-Rendering-simple-shapes-without-passing-vertices if (nullptr != mProgram && 0 == strcmp(renderer->getName(), "OpenGL")) { // Create the vertex buffer object (VBO) static const float VERTEX_POSITION[] = { // Vertex ID 42.0f // 0 }; Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW)); // Create vertex array object (VAO) // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO) // -> This means that there's no need to keep an own vertex buffer object (VBO) reference // -> When the vertex array object (VAO) is destroyed, it automatically decreases the // reference of the used vertex buffer objects (VBO). If the reference counter of a // vertex buffer object (VBO) reaches zero, it's automatically destroyed. const Renderer::VertexArrayAttribute vertexArray[] = { { // Attribute 0 // Data destination Renderer::VertexArrayFormat::FLOAT_1, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "Position", // name[64] (char) "POSITION", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) 0, // offset (unsigned int) sizeof(float), // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) } }; mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray); } } // End debug event RENDERER_END_DEBUG_EVENT(renderer) }
//[-------------------------------------------------------] //[ Public virtual IApplication methods ] //[-------------------------------------------------------] void FirstTriangle::onInitialization() { // Call the base implementation IApplicationRenderer::onInitialization(); // Get and check the renderer instance Renderer::IRendererPtr renderer(getRenderer()); if (nullptr != renderer) { // Begin debug event RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer) // Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg") Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage()); if (nullptr != shaderLanguage) { { // Create the program // Get the shader source code (outsourced to keep an overview) const char *vertexShaderSourceCode = nullptr; const char *fragmentShaderSourceCode = nullptr; #include "FirstTriangle_Cg.h" #include "FirstTriangle_GLSL_110.h" #include "FirstTriangle_GLSL_ES2.h" #include "FirstTriangle_HLSL_D3D9_D3D10_D3D11.h" #include "FirstTriangle_Null.h" // Create the vertex shader Renderer::IVertexShader *vertexShader = shaderLanguage->createVertexShader(vertexShaderSourceCode); RENDERER_SET_RESOURCE_DEBUG_NAME(vertexShader, "Triangle VS") // Create the fragment shader Renderer::IFragmentShader *fragmentShader = shaderLanguage->createFragmentShader(fragmentShaderSourceCode); RENDERER_SET_RESOURCE_DEBUG_NAME(fragmentShader, "Triangle FS") // Create the program mProgram = shaderLanguage->createProgram(vertexShader, fragmentShader); RENDERER_SET_RESOURCE_DEBUG_NAME(mProgram, "Triangle program") } // Is there a valid program? if (nullptr != mProgram) { // Create the vertex buffer object (VBO) // -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1) static const float VERTEX_POSITION[] = { // Vertex ID Triangle on screen 0.0f, 1.0f, // 0 0 1.0f, 0.0f, // 1 . . -0.5f, 0.0f // 2 2.......1 }; Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW)); RENDERER_SET_RESOURCE_DEBUG_NAME(vertexBuffer, "Triangle VBO") // Create vertex array object (VAO) // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO) // -> This means that there's no need to keep an own vertex buffer object (VBO) reference // -> When the vertex array object (VAO) is destroyed, it automatically decreases the // reference of the used vertex buffer objects (VBO). If the reference counter of a // vertex buffer object (VBO) reaches zero, it's automatically destroyed. const Renderer::VertexArrayAttribute vertexArray[] = { { // Attribute 0 // Data destination Renderer::VertexArrayFormat::FLOAT_2, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "Position", // name[64] (char) "POSITION", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) 0, // offset (unsigned int) sizeof(float) * 2, // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) } }; mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray); RENDERER_SET_RESOURCE_DEBUG_NAME(mVertexArray, "Triangle VAO") } }
//[-------------------------------------------------------] //[ Public virtual IApplication methods ] //[-------------------------------------------------------] void Fxaa::onInitialization() { // Call the base implementation IApplicationRenderer::onInitialization(); // Get and check the renderer instance Renderer::IRendererPtr renderer(getRenderer()); if (nullptr != renderer) { // Begin debug event RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer) // Create the framebuffer object (FBO) instance by using the current window size recreateFramebuffer(); { // Create sampler state // -> Our texture does not have any mipmaps, set "Renderer::SamplerState::maxLOD" to zero // in order to ensure a correct behaviour across the difference graphics APIs // -> When not doing this you usually have no issues when using OpenGL, OpenGL ES 2, Direct 10, // Direct3D 11 or Direct3D 9 with the "ps_2_0"-profile, but when using Direct3D 9 with the // "ps_3_0"-profile you might get into trouble due to another internal graphics API behaviour Renderer::SamplerState samplerState = Renderer::ISamplerState::getDefaultSamplerState(); samplerState.maxLOD = 0.0f; // We don't use mipmaps mSamplerState = renderer->createSamplerState(samplerState); } { // Depth stencil state // -> By default depth test is enabled // -> In this simple example we don't need depth test, so, disable it so we don't need to care about the depth buffer // Create depth stencil state Renderer::DepthStencilState depthStencilState = Renderer::IDepthStencilState::getDefaultDepthStencilState(); depthStencilState.depthEnable = false; mDepthStencilState = renderer->createDepthStencilState(depthStencilState); // Set the depth stencil state directly within this initialization phase, we don't change it later on renderer->omSetDepthStencilState(mDepthStencilState); } // Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg") Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage()); if (nullptr != shaderLanguage) { { // Create the program for scene rendering // Get the shader source code (outsourced to keep an overview) const char *vertexShaderSourceCode = nullptr; const char *fragmentShaderSourceCode = nullptr; #include "Fxaa_SceneRendering_Cg.h" #include "Fxaa_SceneRendering_GLSL_120.h" #include "Fxaa_SceneRendering_GLSL_ES2.h" #include "Fxaa_SceneRendering_HLSL_D3D9_D3D10_D3D11.h" #include "Fxaa_SceneRendering_Null.h" // Create the program for scene rendering mProgramSceneRendering = shaderLanguage->createProgram(shaderLanguage->createVertexShader(vertexShaderSourceCode), shaderLanguage->createFragmentShader(fragmentShaderSourceCode)); } // Is there a valid program for scene rendering? if (nullptr != mProgramSceneRendering) { // Create the vertex buffer object (VBO) // -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1) static const float VERTEX_POSITION[] = { // Vertex ID Triangle on screen 0.0f, 1.0f, // 0 0 1.0f, 0.0f, // 1 . . -0.5f, 0.0f // 2 2.......1 }; Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW)); // Create vertex array object (VAO) // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO) // -> This means that there's no need to keep an own vertex buffer object (VBO) reference // -> When the vertex array object (VAO) is destroyed, it automatically decreases the // reference of the used vertex buffer objects (VBO). If the reference counter of a // vertex buffer object (VBO) reaches zero, it's automatically destroyed. const Renderer::VertexArrayAttribute vertexArray[] = { { // Attribute 0 // Data destination Renderer::VertexArrayFormat::FLOAT_2, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "Position", // name[64] (char) "POSITION", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) 0, // offset (unsigned int) sizeof(float) * 2, // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) } }; mVertexArraySceneRendering = mProgramSceneRendering->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray); } // Create the post-processing program instance by using the current window size recreatePostProcessingProgram(); // Is there a valid program for post-processing? if (nullptr != mProgramPostProcessing) { // Create the vertex buffer object (VBO) // -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1) static const float VERTEX_POSITION[] = { // Vertex ID Triangle strip on screen -1.0f, -1.0f, // 0 1.......3 -1.0f, 1.0f, // 1 . . . 1.0f, -1.0f, // 2 0.......2 1.0f, 1.0f // 3 }; Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW)); // Create vertex array object (VAO) // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO) // -> This means that there's no need to keep an own vertex buffer object (VBO) reference // -> When the vertex array object (VAO) is destroyed, it automatically decreases the // reference of the used vertex buffer objects (VBO). If the reference counter of a // vertex buffer object (VBO) reaches zero, it's automatically destroyed. const Renderer::VertexArrayAttribute vertexArray[] = { { // Attribute 0 // Data destination Renderer::VertexArrayFormat::FLOAT_2, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "Position", // name[64] (char) "POSITION", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) 0, // offset (unsigned int) sizeof(float) * 2, // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) } }; mVertexArrayPostProcessing = mProgramSceneRendering->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray); } } // End debug event RENDERER_END_DEBUG_EVENT(renderer) }
//[-------------------------------------------------------] //[ Public virtual IApplication methods ] //[-------------------------------------------------------] void FirstMesh::onInitialization() { // Call the base implementation IApplicationRendererRuntime::onInitialization(); // Get and check the renderer runtime instance RendererRuntime::IRendererRuntime* rendererRuntime = getRendererRuntime(); if (nullptr != rendererRuntime) { Renderer::IRendererPtr renderer(getRenderer()); // Create uniform buffers // -> Direct3D 9 and OpenGL ES 2 do not support uniform buffers // -> Direct3D 10, 11 and 12 do not support individual uniforms // -> The renderer is just a light weight abstraction layer, so we need to handle the differences if ((0 == strcmp(renderer->getName(), "Direct3D10") || 0 == strcmp(renderer->getName(), "Direct3D11") || 0 == strcmp(renderer->getName(), "Direct3D12"))) { // Allocate enough memory for two 4x4 floating point matrices mUniformBuffer = rendererRuntime->getBufferManager().createUniformBuffer(2 * 4 * 4 * sizeof(float), nullptr, Renderer::BufferUsage::DYNAMIC_DRAW); } // Decide which shader language should be used (for example "GLSL" or "HLSL") Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage()); if (nullptr != shaderLanguage) { // Vertex input layout const Renderer::VertexAttribute vertexAttributesLayout[] = { { // Attribute 0 // Data destination Renderer::VertexAttributeFormat::FLOAT_3, // vertexAttributeFormat (Renderer::VertexAttributeFormat) "Position", // name[32] (char) "POSITION", // semanticName[32] (char) 0, // semanticIndex (uint32_t) // Data source 0, // inputSlot (uint32_t) 0, // alignedByteOffset (uint32_t) // Data source, instancing part 0 // instancesPerElement (uint32_t) }, { // Attribute 1 // Data destination Renderer::VertexAttributeFormat::SHORT_2, // vertexAttributeFormat (Renderer::VertexAttributeFormat) "TexCoord", // name[32] (char) "TEXCOORD", // semanticName[32] (char) 0, // semanticIndex (uint32_t) // Data source 0, // inputSlot (uint32_t) sizeof(float) * 3, // alignedByteOffset (uint32_t) // Data source, instancing part 0 // instancesPerElement (uint32_t) }, { // Attribute 2 // Data destination Renderer::VertexAttributeFormat::SHORT_4, // vertexAttributeFormat (Renderer::VertexAttributeFormat) "QTangent", // name[32] (char) "TEXCOORD", // semanticName[32] (char) 1, // semanticIndex (uint32_t) // Data source 0, // inputSlot (uint32_t) sizeof(float) * 3 + sizeof(short) * 2, // alignedByteOffset (uint32_t) // Data source, instancing part 0 // instancesPerElement (uint32_t) } }; const Renderer::VertexAttributes vertexAttributes(glm::countof(vertexAttributesLayout), vertexAttributesLayout); { // Create the root signature Renderer::DescriptorRangeBuilder ranges[6]; ranges[0].initialize(Renderer::DescriptorRangeType::UBV, 1, 0, "UniformBlockDynamicVs", 0); ranges[1].initializeSampler(1, 0); ranges[2].initialize(Renderer::DescriptorRangeType::SRV, 1, 0, "DiffuseMap", 1); ranges[3].initialize(Renderer::DescriptorRangeType::SRV, 1, 1, "EmissiveMap", 1); ranges[4].initialize(Renderer::DescriptorRangeType::SRV, 1, 2, "NormalMap", 1); ranges[5].initialize(Renderer::DescriptorRangeType::SRV, 1, 3, "SpecularMap", 1); Renderer::RootParameterBuilder rootParameters[6]; rootParameters[0].initializeAsDescriptorTable(1, &ranges[0], Renderer::ShaderVisibility::VERTEX); rootParameters[1].initializeAsDescriptorTable(1, &ranges[1], Renderer::ShaderVisibility::FRAGMENT); rootParameters[2].initializeAsDescriptorTable(1, &ranges[2], Renderer::ShaderVisibility::FRAGMENT); rootParameters[3].initializeAsDescriptorTable(1, &ranges[3], Renderer::ShaderVisibility::FRAGMENT); rootParameters[4].initializeAsDescriptorTable(1, &ranges[4], Renderer::ShaderVisibility::FRAGMENT); rootParameters[5].initializeAsDescriptorTable(1, &ranges[5], Renderer::ShaderVisibility::FRAGMENT); // Setup Renderer::RootSignatureBuilder rootSignature; rootSignature.initialize(glm::countof(rootParameters), rootParameters, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); // Create the instance mRootSignature = renderer->createRootSignature(rootSignature); } // Create the program Renderer::IProgramPtr program; { // Get the shader source code (outsourced to keep an overview) const char *vertexShaderProfile = nullptr; const char *vertexShaderSourceCode = nullptr; const char *fragmentShaderProfile = nullptr; const char *fragmentShaderSourceCode = nullptr; #include "FirstMesh_GLSL_410.h" #include "FirstMesh_GLSL_ES2.h" #include "FirstMesh_HLSL_D3D9.h" #include "FirstMesh_HLSL_D3D10_D3D11_D3D12.h" #include "FirstMesh_Null.h" // Create the program mProgram = program = shaderLanguage->createProgram( *mRootSignature, vertexAttributes, shaderLanguage->createVertexShaderFromSourceCode(vertexAttributes, vertexShaderSourceCode, vertexShaderProfile), shaderLanguage->createFragmentShaderFromSourceCode(fragmentShaderSourceCode, fragmentShaderProfile)); } // Is there a valid program? if (nullptr != program) { // Create the pipeline state object (PSO) mPipelineState = renderer->createPipelineState(Renderer::PipelineStateBuilder(mRootSignature, program, vertexAttributes)); // Optimization: Cached data to not bother the renderer API too much if (nullptr == mUniformBuffer) { mObjectSpaceToClipSpaceMatrixUniformHandle = program->getUniformHandle("ObjectSpaceToClipSpaceMatrix"); mObjectSpaceToViewSpaceMatrixUniformHandle = program->getUniformHandle("ObjectSpaceToViewSpaceMatrix"); } } // Create mesh instance mMeshResourceId = rendererRuntime->getMeshResourceManager().loadMeshResourceByAssetId("Example/Mesh/Character/Imrod"); { // Load in the diffuse, emissive, normal and specular texture // -> The tangent space normal map is stored with three components, two would be enough to recalculate the third component within the fragment shader // -> The specular map could be put into the alpha channel of the diffuse map instead of storing it as an individual texture RendererRuntime::TextureResourceManager& textureResourceManager = rendererRuntime->getTextureResourceManager(); mDiffuseTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodDiffuseMap"); mNormalTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodEmissiveMap"); mSpecularTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodNormalMap"); mEmissiveTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodSpecularMap"); } { // Create sampler state Renderer::SamplerState samplerStateSettings = Renderer::ISamplerState::getDefaultSamplerState(); samplerStateSettings.addressU = Renderer::TextureAddressMode::WRAP; samplerStateSettings.addressV = Renderer::TextureAddressMode::WRAP; mSamplerState = renderer->createSamplerState(samplerStateSettings); } } } }
//[-------------------------------------------------------] //[ Public virtual IApplication methods ] //[-------------------------------------------------------] void FirstGeometryShader::onInitialization() { // Call the base implementation IApplicationRenderer::onInitialization(); // Get and check the renderer instance // -> Geometry shaders supported? Renderer::IRendererPtr renderer(getRenderer()); if (nullptr != renderer && renderer->getCapabilities().maximumNumberOfGsOutputVertices) { // Create the buffer manager mBufferManager = renderer->createBufferManager(); { // Create the root signature // Setup Renderer::RootSignatureBuilder rootSignature; rootSignature.initialize(0, nullptr, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); // Create the instance mRootSignature = renderer->createRootSignature(rootSignature); } // Vertex input layout const Renderer::VertexAttribute vertexAttributesLayout[] = { { // Attribute 0 // Data destination Renderer::VertexAttributeFormat::FLOAT_1, // vertexAttributeFormat (Renderer::VertexAttributeFormat) "Position", // name[32] (char) "POSITION", // semanticName[32] (char) 0, // semanticIndex (uint32_t) // Data source 0, // inputSlot (uint32_t) 0, // alignedByteOffset (uint32_t) // Data source, instancing part 0 // instancesPerElement (uint32_t) } }; const Renderer::VertexAttributes vertexAttributes(glm::countof(vertexAttributesLayout), vertexAttributesLayout); { // Create vertex array object (VAO) // Create the vertex buffer object (VBO) static const float VERTEX_POSITION[] = { // Vertex ID 42.0f // 0 }; Renderer::IVertexBufferPtr vertexBuffer(mBufferManager->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW)); // Create vertex array object (VAO) // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO) // -> This means that there's no need to keep an own vertex buffer object (VBO) reference // -> When the vertex array object (VAO) is destroyed, it automatically decreases the // reference of the used vertex buffer objects (VBO). If the reference counter of a // vertex buffer object (VBO) reaches zero, it's automatically destroyed. const Renderer::VertexArrayVertexBuffer vertexArrayVertexBuffers[] = { { // Vertex buffer 0 vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) sizeof(float) // strideInBytes (uint32_t) } }; mVertexArray = mBufferManager->createVertexArray(vertexAttributes, glm::countof(vertexArrayVertexBuffers), vertexArrayVertexBuffers); } // Create the program: Decide which shader language should be used (for example "GLSL" or "HLSL") Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage()); if (nullptr != shaderLanguage) { // Create the program Renderer::IProgramPtr program; { // Get the shader source code (outsourced to keep an overview) const char *vertexShaderSourceCode = nullptr; const char *geometryShaderSourceCode = nullptr; const char *fragmentShaderSourceCode = nullptr; #include "FirstGeometryShader_GLSL_410.h" #include "FirstGeometryShader_HLSL_D3D10_D3D11_D3D12.h" #include "FirstGeometryShader_Null.h" // Create the program program = shaderLanguage->createProgram( *mRootSignature, vertexAttributes, shaderLanguage->createVertexShaderFromSourceCode(vertexAttributes, vertexShaderSourceCode), shaderLanguage->createGeometryShaderFromSourceCode(geometryShaderSourceCode, Renderer::GsInputPrimitiveTopology::POINTS, Renderer::GsOutputPrimitiveTopology::TRIANGLE_STRIP, 3), shaderLanguage->createFragmentShaderFromSourceCode(fragmentShaderSourceCode)); } // Create the pipeline state object (PSO) if (nullptr != program) { Renderer::PipelineState pipelineState = Renderer::PipelineStateBuilder(mRootSignature, program, vertexAttributes); pipelineState.primitiveTopologyType = Renderer::PrimitiveTopologyType::POINT; mPipelineState = renderer->createPipelineState(pipelineState); } } // Since we're always submitting the same commands to the renderer, we can fill the command buffer once during initialization and then reuse it multiple times during runtime fillCommandBuffer(); } }
//[-------------------------------------------------------] //[ Public methods ] //[-------------------------------------------------------] CubeRendererDrawInstanced::CubeRendererDrawInstanced(Renderer::IRenderer &renderer, unsigned int numberOfTextures, unsigned int sceneRadius) : mRenderer(&renderer), mNumberOfTextures(numberOfTextures), mSceneRadius(sceneRadius), mMaximumNumberOfInstancesPerBatch(0), mNumberOfBatches(0), mBatches(nullptr) { // Begin debug event RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(&renderer) // Check number of textures (limit of this implementation and renderer limit) if (mNumberOfTextures > MAXIMUM_NUMBER_OF_TEXTURES) { mNumberOfTextures = MAXIMUM_NUMBER_OF_TEXTURES; } if (mNumberOfTextures > mRenderer->getCapabilities().maximumNumberOf2DTextureArraySlices) { mNumberOfTextures = mRenderer->getCapabilities().maximumNumberOf2DTextureArraySlices; } // Get the maximum number of instances per batch // -> In this application, this depends on the maximum texture buffer size // -> /2 -> One instance requires two texels mMaximumNumberOfInstancesPerBatch = mRenderer->getCapabilities().maximumTextureBufferSize / 2; { // Create the textures static const unsigned int TEXTURE_WIDTH = 128; static const unsigned int TEXTURE_HEIGHT = 128; static const unsigned int NUMBER_OF_BYTES = TEXTURE_WIDTH * TEXTURE_HEIGHT * 4; // Allocate memory for the 2D texture array unsigned char *data = new unsigned char[NUMBER_OF_BYTES * mNumberOfTextures]; { // Fill the texture content // TODO(co) Be a little bit more creative while filling the texture data unsigned char *dataCurrent = data; const float colors[][MAXIMUM_NUMBER_OF_TEXTURES] = { { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.1f, 0.0f}, { 0.0f, 0.0f, 0.1f}, { 0.5f, 0.5f, 0.5f}, { 1.0f, 1.0f, 1.0f}, { 0.1f, 0.2f, 0.2f}, { 0.2f, 0.5f, 0.5f}, { 0.1f, 0.8f, 0.2f} }; for (unsigned int j = 0; j < mNumberOfTextures; ++j) { // Random content for (unsigned int i = 0; i < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++i) { *dataCurrent = static_cast<unsigned char>((rand() % 255) * colors[j][0]); ++dataCurrent; *dataCurrent = static_cast<unsigned char>((rand() % 255) * colors[j][1]); ++dataCurrent; *dataCurrent = static_cast<unsigned char>((rand() % 255) * colors[j][2]); ++dataCurrent; *dataCurrent = 255; ++dataCurrent; } } } // Create the texture instance // -> By using 2D array textures together with OpenGL/Direct3D 11 instancing we get a handy implementation // -> This limits of course the cross platform support, fallback solutions might be a good idea in productive code // -> A fallback is not really required in our example situation because we're using draw instanced which already requires a more modern graphics card mTexture2DArray = mRenderer->createTexture2DArray(TEXTURE_WIDTH, TEXTURE_HEIGHT, mNumberOfTextures, Renderer::TextureFormat::R8G8B8A8, data, Renderer::TextureFlag::MIPMAPS); // Free texture memory delete [] data; } // Create sampler state mSamplerState = mRenderer->createSamplerState(Renderer::ISamplerState::getDefaultSamplerState()); // Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg") Renderer::IShaderLanguagePtr shaderLanguage(mRenderer->getShaderLanguage()); if (nullptr != shaderLanguage) { // Uniform buffer object (UBO, "constant buffer" in Direct3D terminology) supported? // -> If they are there, we really want to use them (performance and ease of use) if (mRenderer->getCapabilities().uniformBuffer) { { // Create and set constant program uniform buffer at once // TODO(co) Uggly fixed hacked in model-view-projection matrix // TODO(co) OpenGL matrix, Direct3D has minor differences within the projection matrix we have to compensate static const float MVP[] = { 1.2803299f, -0.97915620f, -0.58038759f, -0.57922798f, 0.0f, 1.9776078f, -0.57472473f, -0.573576453f, -1.2803299f, -0.97915620f, -0.58038759f, -0.57922798f, 0.0f, 0.0f, 9.8198195f, 10.0f }; mUniformBufferStaticVs = shaderLanguage->createUniformBuffer(sizeof(MVP), MVP, Renderer::BufferUsage::STATIC_DRAW); } // Create dynamic uniform buffers mUniformBufferDynamicVs = shaderLanguage->createUniformBuffer(sizeof(float) * 2, nullptr, Renderer::BufferUsage::DYNAMIC_DRAW); mUniformBufferDynamicFs = shaderLanguage->createUniformBuffer(sizeof(float) * 3, nullptr, Renderer::BufferUsage::DYNAMIC_DRAW); } { // Create the program // Get the shader source code (outsourced to keep an overview) const char *vertexShaderSourceCode = nullptr; const char *fragmentShaderSourceCode = nullptr; #include "CubeRendererDrawInstanced_GLSL_140.h" #include "CubeRendererDrawInstanced_HLSL_D3D10_D3D11.h" #include "CubeRendererDrawInstanced_Null.h" // Create the program mProgram = shaderLanguage->createProgram( shaderLanguage->createVertexShader(vertexShaderSourceCode), shaderLanguage->createFragmentShader(fragmentShaderSourceCode)); } // Is there a valid program? if (nullptr != mProgram) { // Create the vertex buffer object (VBO) static const float VERTEX_POSITION[] = { // Front face // Position TexCoord Normal // Vertex ID -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, // 0 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // 1 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 2 -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 3 // Back face -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f,-1.0f, // 4 -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f,-1.0f, // 5 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,-1.0f, // 6 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f,-1.0f, // 7 // Top face -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 8 -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, // 9 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // 10 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 11 // Bottom face -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f,-1.0f, 0.0f, // 12 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,-1.0f, 0.0f, // 13 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, // 14 -0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,-1.0f, 0.0f, // 15 // Right face 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 16 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // 17 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, // 18 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 19 // Left face -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // 20 -0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, // 21 -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, // 22 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f // 23 }; Renderer::IVertexBufferPtr vertexBuffer(mRenderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW)); // Create the index buffer object (IBO) static const unsigned short INDICES[] = { // Front face Triangle ID 1, 0, 2, // 0 3, 2, 0, // 1 // Back face 6, 5, 4, // 2 4, 7, 6, // 3 // Top face 9, 8, 10, // 4 11, 10, 8, // 5 // Bottom face 13, 12, 14, // 6 15, 14, 12, // 7 // Right face 17, 16, 18, // 8 19, 18, 16, // 9 // Left face 21, 20, 22, // 10 23, 22, 20 // 11 }; Renderer::IIndexBuffer *indexBuffer = mRenderer->createIndexBuffer(sizeof(INDICES), Renderer::IndexBufferFormat::UNSIGNED_SHORT, INDICES, Renderer::BufferUsage::STATIC_DRAW); // Create vertex array object (VAO) // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO) // -> This means that there's no need to keep an own vertex buffer object (VBO) reference // -> When the vertex array object (VAO) is destroyed, it automatically decreases the // reference of the used vertex buffer objects (VBO). If the reference counter of a // vertex buffer object (VBO) reaches zero, it's automatically destroyed. const Renderer::VertexArrayAttribute vertexArray[] = { { // Attribute 0 // Data destination Renderer::VertexArrayFormat::FLOAT_3, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "Position", // name[64] (char) "POSITION", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) 0, // offset (unsigned int) sizeof(float) * (3 + 2 + 3), // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) }, { // Attribute 1 // Data destination Renderer::VertexArrayFormat::FLOAT_2, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "TexCoord", // name[64] (char) "TEXCOORD", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) sizeof(float) * 3, // offset (unsigned int) sizeof(float) * (3 + 2 + 3), // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) }, { // Attribute 2 // Data destination Renderer::VertexArrayFormat::FLOAT_3, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "Normal", // name[64] (char) "NORMAL", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // pertexBuffer (Renderer::IVertexBuffer *) sizeof(float) * (3 + 2), // offset (unsigned int) sizeof(float) * (3 + 2 + 3), // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) } }; mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray, indexBuffer); } } // End debug event RENDERER_END_DEBUG_EVENT(&renderer) }
//[-------------------------------------------------------] //[ Public virtual IApplication methods ] //[-------------------------------------------------------] void IcosahedronTessellation::onInitialization() { // Call the base implementation IApplicationRenderer::onInitialization(); // Get and check the renderer instance // -> Uniform buffer object (UBO, "constant buffer" in Direct3D terminology) supported? // -> Geometry shaders supported? // -> Tessellation control and tessellation evaluation shaders supported? Renderer::IRendererPtr renderer(getRenderer()); if (nullptr != renderer && renderer->getCapabilities().uniformBuffer && renderer->getCapabilities().maximumNumberOfGsOutputVertices > 0 && renderer->getCapabilities().maximumNumberOfPatchVertices > 0) { // Begin debug event RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer) // Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg") Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage()); if (nullptr != shaderLanguage) { // Create uniform buffers and fill the static buffers at once mUniformBufferDynamicTcs = shaderLanguage->createUniformBuffer(sizeof(float) * 2, nullptr, Renderer::BufferUsage::DYNAMIC_DRAW); { // "ObjectSpaceToClipSpaceMatrix" // TODO(co) Cleanup, correct aspect ratio glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f)); glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f)); glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.001f, 1000.0f); glm::mat4 MVP = Projection * View; // glm::mat4 MVP = Projection * View * Model; mUniformBufferStaticTes = shaderLanguage->createUniformBuffer(sizeof(float) * 4 * 4, glm::value_ptr(MVP), Renderer::BufferUsage::STATIC_DRAW); { // "NormalMatrix" View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); Model = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f)); Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.001f, 1000.0f); MVP = Projection * View; glm::mat3 nMVP(MVP); glm::mat4 tMVP(nMVP); mUniformBufferStaticGs = shaderLanguage->createUniformBuffer(sizeof(float) * 4 * 4, glm::value_ptr(tMVP), Renderer::BufferUsage::STATIC_DRAW); } } { // Light and material static const float LIGHT_AND_MATERIAL[] = { 0.25f, 0.25f, 1.0f, 1.0, // "LightPosition" 0.0f, 0.75f, 0.75f,1.0, // "DiffuseMaterial" 0.04f, 0.04f, 0.04f,1.0, // "AmbientMaterial" }; mUniformBufferStaticFs = shaderLanguage->createUniformBuffer(sizeof(LIGHT_AND_MATERIAL), LIGHT_AND_MATERIAL, Renderer::BufferUsage::STATIC_DRAW); } { // Create the program // Get the shader source code (outsourced to keep an overview) const char *vertexShaderSourceCode = nullptr; const char *tessellationControlShaderSourceCode = nullptr; const char *tessellationEvaluationShaderSourceCode = nullptr; const char *geometryShaderSourceCode = nullptr; const char *fragmentShaderSourceCode = nullptr; #include "IcosahedronTessellation_GLSL_400.h" #include "IcosahedronTessellation_HLSL_D3D11.h" #include "IcosahedronTessellation_Null.h" // Create the program mProgram = shaderLanguage->createProgram( shaderLanguage->createVertexShader(vertexShaderSourceCode), shaderLanguage->createTessellationControlShader(tessellationControlShaderSourceCode), shaderLanguage->createTessellationEvaluationShader(tessellationEvaluationShaderSourceCode), shaderLanguage->createGeometryShader(geometryShaderSourceCode, Renderer::GsInputPrimitiveTopology::TRIANGLES, Renderer::GsOutputPrimitiveTopology::TRIANGLE_STRIP, 3), shaderLanguage->createFragmentShader(fragmentShaderSourceCode)); } // Is there a valid program? if (nullptr != mProgram) { // Create the vertex buffer object (VBO) // -> Geometry is from: http://prideout.net/blog/?p=48 (Philip Rideout, "The Little Grasshopper - Graphics Programming Tips") static const float VERTEX_POSITION[] = { // Vertex ID 0.000f, 0.000f, 1.000f, // 0 0.894f, 0.000f, 0.447f, // 1 0.276f, 0.851f, 0.447f, // 2 -0.724f, 0.526f, 0.447f, // 3 -0.724f, -0.526f, 0.447f, // 4 0.276f, -0.851f, 0.447f, // 5 0.724f, 0.526f, -0.447f, // 6 -0.276f, 0.851f, -0.447f, // 7 -0.894f, 0.000f, -0.447f, // 8 -0.276f, -0.851f, -0.447f, // 9 0.724f, -0.526f, -0.447f, // 10 0.000f, 0.000f, -1.000f // 11 }; Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW)); // Create the index buffer object (IBO) // -> Geometry is from: http://prideout.net/blog/?p=48 (Philip Rideout, "The Little Grasshopper - Graphics Programming Tips") static const unsigned short INDICES[] = { // Triangle ID 2, 1, 0, // 0 3, 2, 0, // 1 4, 3, 0, // 2 5, 4, 0, // 3 1, 5, 0, // 4 11, 6, 7, // 5 11, 7, 8, // 6 11, 8, 9, // 7 11, 9, 10, // 8 11, 10, 6, // 9 1, 2, 6, // 10 2, 3, 7, // 11 3, 4, 8, // 12 4, 5, 9, // 13 5, 1, 10, // 14 2, 7, 6, // 15 3, 8, 7, // 16 4, 9, 8, // 17 5, 10, 9, // 18 1, 6, 10 // 19 }; Renderer::IIndexBuffer *indexBuffer = renderer->createIndexBuffer(sizeof(INDICES), Renderer::IndexBufferFormat::UNSIGNED_SHORT, INDICES, Renderer::BufferUsage::STATIC_DRAW); // Create vertex array object (VAO) // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO) // -> This means that there's no need to keep an own vertex buffer object (VBO) reference // -> When the vertex array object (VAO) is destroyed, it automatically decreases the // reference of the used vertex buffer objects (VBO). If the reference counter of a // vertex buffer object (VBO) reaches zero, it's automatically destroyed. const Renderer::VertexArrayAttribute vertexArray[] = { { // Attribute 0 // Data destination Renderer::VertexArrayFormat::FLOAT_3, // vertexArrayFormat (Renderer::VertexArrayFormat::Enum) "Position", // name[64] (char) "POSITION", // semantic[64] (char) 0, // semanticIndex (unsigned int) // Data source vertexBuffer, // vertexBuffer (Renderer::IVertexBuffer *) 0, // offset (unsigned int) sizeof(float) * 3, // stride (unsigned int) // Data source, instancing part 0 // instancesPerElement (unsigned int) } }; mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray, indexBuffer); } } // End debug event RENDERER_END_DEBUG_EVENT(renderer) }