diff --git a/examples/21-deferred/deferred.cpp b/examples/21-deferred/deferred.cpp index f93dcd6e..813c1f84 100644 --- a/examples/21-deferred/deferred.cpp +++ b/examples/21-deferred/deferred.cpp @@ -15,6 +15,7 @@ #define RENDER_PASS_DEBUG_LIGHTS_ID 3 #define RENDER_PASS_DEBUG_GBUFFER_ID 4 +static float s_texelHalf = 0.0f; static bool s_originBottomLeft = false; inline void mtxProj(float* _result, float _fovy, float _aspect, float _near, float _far) @@ -217,516 +218,580 @@ void screenSpaceQuad(float _textureWidth, float _textureHeight, float _texelHalf } } -int _main_(int /*_argc*/, char** /*_argv*/) +class Deferred : public entry::AppI { - uint32_t width = 1280; - uint32_t height = 720; - uint32_t debug = BGFX_DEBUG_TEXT; - uint32_t reset = BGFX_RESET_VSYNC; - - bgfx::init(); - bgfx::reset(width, height, reset); - - // Enable debug text. - bgfx::setDebug(debug); - - // Set clear color palette for index 0 - bgfx::setClearColor(0, UINT32_C(0x00000000) ); - - // Set clear color palette for index 1 - bgfx::setClearColor(1, UINT32_C(0x303030ff) ); - - // Set geometry pass view clear state. - bgfx::setViewClear(RENDER_PASS_GEOMETRY_ID - , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH - , 1.0f - , 0 - , 1 - ); - - // Set light pass view clear state. - bgfx::setViewClear(RENDER_PASS_LIGHT_ID - , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH - , 1.0f - , 0 - , 0 - ); - - // Create vertex stream declaration. - PosNormalTangentTexcoordVertex::init(); - PosTexCoord0Vertex::init(); - DebugVertex::init(); - - calcTangents(s_cubeVertices - , BX_COUNTOF(s_cubeVertices) - , PosNormalTangentTexcoordVertex::ms_decl - , s_cubeIndices - , BX_COUNTOF(s_cubeIndices) - ); - - // Create static vertex buffer. - bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer( - bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) ) - , PosNormalTangentTexcoordVertex::ms_decl - ); - - // Create static index buffer. - bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer(bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) ) ); - - // Create texture sampler uniforms. - bgfx::UniformHandle s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1); - bgfx::UniformHandle s_texNormal = bgfx::createUniform("s_texNormal", bgfx::UniformType::Int1); - - bgfx::UniformHandle s_albedo = bgfx::createUniform("s_albedo", bgfx::UniformType::Int1); - bgfx::UniformHandle s_normal = bgfx::createUniform("s_normal", bgfx::UniformType::Int1); - bgfx::UniformHandle s_depth = bgfx::createUniform("s_depth", bgfx::UniformType::Int1); - bgfx::UniformHandle s_light = bgfx::createUniform("s_light", bgfx::UniformType::Int1); - - bgfx::UniformHandle u_mtx = bgfx::createUniform("u_mtx", bgfx::UniformType::Mat4); - bgfx::UniformHandle u_lightPosRadius = bgfx::createUniform("u_lightPosRadius", bgfx::UniformType::Vec4); - bgfx::UniformHandle u_lightRgbInnerR = bgfx::createUniform("u_lightRgbInnerR", bgfx::UniformType::Vec4); - - // Create program from shaders. - bgfx::ProgramHandle geomProgram = loadProgram("vs_deferred_geom", "fs_deferred_geom"); - bgfx::ProgramHandle lightProgram = loadProgram("vs_deferred_light", "fs_deferred_light"); - bgfx::ProgramHandle combineProgram = loadProgram("vs_deferred_combine", "fs_deferred_combine"); - bgfx::ProgramHandle debugProgram = loadProgram("vs_deferred_debug", "fs_deferred_debug"); - bgfx::ProgramHandle lineProgram = loadProgram("vs_deferred_debug_line", "fs_deferred_debug_line"); - - // Load diffuse texture. - bgfx::TextureHandle textureColor = loadTexture("fieldstone-rgba.dds"); - - // Load normal texture. - bgfx::TextureHandle textureNormal = loadTexture("fieldstone-n.dds"); - - bgfx::TextureHandle gbufferTex[3] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE }; - bgfx::FrameBufferHandle gbuffer = BGFX_INVALID_HANDLE; - bgfx::FrameBufferHandle lightBuffer = BGFX_INVALID_HANDLE; - - // Imgui. - imguiCreate(); - - const int64_t timeOffset = bx::getHPCounter(); - const bgfx::RendererType::Enum renderer = bgfx::getRendererType(); - const float texelHalf = bgfx::RendererType::Direct3D9 == renderer ? 0.5f : 0.0f; - s_originBottomLeft = bgfx::RendererType::OpenGL == renderer || bgfx::RendererType::OpenGLES == renderer; - - // Get renderer capabilities info. - const bgfx::Caps* caps = bgfx::getCaps(); - - uint32_t oldWidth = 0; - uint32_t oldHeight = 0; - uint32_t oldReset = reset; - - int32_t scrollArea = 0; - int32_t numLights = 512; - float lightAnimationSpeed = 0.3f; - bool animateMesh = true; - bool showScissorRects = false; - bool showGBuffer = true; - - float view[16]; - float initialPos[3] = { 0.0f, 0.0f, -15.0f }; - cameraCreate(); - cameraSetPosition(initialPos); - cameraSetVerticalAngle(0.0f); - cameraGetViewMtx(view); - - entry::MouseState mouseState; - while (!entry::processEvents(width, height, debug, reset, &mouseState) ) + void init(int /*_argc*/, char** /*_argv*/) BX_OVERRIDE { - int64_t now = bx::getHPCounter(); - static int64_t last = now; - const int64_t frameTime = now - last; - last = now; - const double freq = double(bx::getHPFrequency() ); - const double toMs = 1000.0/freq; - const float deltaTime = float(frameTime/freq); + m_width = 1280; + m_height = 720; + m_debug = BGFX_DEBUG_TEXT; + m_reset = BGFX_RESET_VSYNC; - float time = (float)( (now-timeOffset)/freq); + bgfx::init(); + bgfx::reset(m_width, m_height, m_reset); - // Use debug font to print information about this example. - bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/21-deferred"); - bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: MRT rendering and deferred shading."); - bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + // Enable m_debug text. + bgfx::setDebug(m_debug); - if (2 > caps->maxFBAttachments) - { - // When multiple render targets (MRT) is not supported by GPU, - // implement alternative code path that doesn't use MRT. - bool blink = uint32_t(time*3.0f)&1; - bgfx::dbgTextPrintf(0, 5, blink ? 0x1f : 0x01, " MRT not supported by GPU. "); + // Set clear color palette for index 0 + bgfx::setClearColor(0, UINT32_C(0x00000000) ); - // Set view 0 default viewport. - bgfx::setViewRect(0, 0, 0, width, height); + // Set clear color palette for index 1 + bgfx::setClearColor(1, UINT32_C(0x303030ff) ); - // This dummy draw call is here to make sure that view 0 is cleared - // if no other draw calls are submitted to view 0. - bgfx::touch(0); - } - else - { - if (oldWidth != width - || oldHeight != height - || oldReset != reset - || !bgfx::isValid(gbuffer) ) - { - // Recreate variable size render targets when resolution changes. - oldWidth = width; - oldHeight = height; - oldReset = reset; - - if (bgfx::isValid(gbuffer) ) - { - bgfx::destroyFrameBuffer(gbuffer); - } - - const uint32_t samplerFlags = 0 - | BGFX_TEXTURE_RT - | BGFX_TEXTURE_MIN_POINT - | BGFX_TEXTURE_MAG_POINT - | BGFX_TEXTURE_MIP_POINT - | BGFX_TEXTURE_U_CLAMP - | BGFX_TEXTURE_V_CLAMP - ; - gbufferTex[0] = bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::BGRA8, samplerFlags); - gbufferTex[1] = bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::BGRA8, samplerFlags); - gbufferTex[2] = bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::D24, samplerFlags); - gbuffer = bgfx::createFrameBuffer(BX_COUNTOF(gbufferTex), gbufferTex, true); - - if (bgfx::isValid(lightBuffer) ) - { - bgfx::destroyFrameBuffer(lightBuffer); - } - - lightBuffer = bgfx::createFrameBuffer(width, height, bgfx::TextureFormat::BGRA8, samplerFlags); - } - - imguiBeginFrame(mouseState.m_mx - , mouseState.m_my - , (mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0) - | (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0) - , mouseState.m_mz - , width - , height + // Set geometry pass view clear state. + bgfx::setViewClear(RENDER_PASS_GEOMETRY_ID + , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH + , 1.0f + , 0 + , 1 ); - imguiBeginScrollArea("Settings", width - width / 5 - 10, 10, width / 5, height / 3, &scrollArea); - imguiSeparatorLine(); + // Set light pass view clear state. + bgfx::setViewClear(RENDER_PASS_LIGHT_ID + , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH + , 1.0f + , 0 + , 0 + ); - imguiSlider("Num lights", numLights, 1, 2048); + // Create vertex stream declaration. + PosNormalTangentTexcoordVertex::init(); + PosTexCoord0Vertex::init(); + DebugVertex::init(); - if (imguiCheck("Show G-Buffer.", showGBuffer) ) + calcTangents(s_cubeVertices + , BX_COUNTOF(s_cubeVertices) + , PosNormalTangentTexcoordVertex::ms_decl + , s_cubeIndices + , BX_COUNTOF(s_cubeIndices) + ); + + // Create static vertex buffer. + m_vbh = bgfx::createVertexBuffer( + bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) ) + , PosNormalTangentTexcoordVertex::ms_decl + ); + + // Create static index buffer. + m_ibh = bgfx::createIndexBuffer(bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) ) ); + + // Create texture sampler uniforms. + s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1); + s_texNormal = bgfx::createUniform("s_texNormal", bgfx::UniformType::Int1); + + s_albedo = bgfx::createUniform("s_albedo", bgfx::UniformType::Int1); + s_normal = bgfx::createUniform("s_normal", bgfx::UniformType::Int1); + s_depth = bgfx::createUniform("s_depth", bgfx::UniformType::Int1); + s_light = bgfx::createUniform("s_light", bgfx::UniformType::Int1); + + u_mtx = bgfx::createUniform("u_mtx", bgfx::UniformType::Mat4); + u_lightPosRadius = bgfx::createUniform("u_lightPosRadius", bgfx::UniformType::Vec4); + u_lightRgbInnerR = bgfx::createUniform("u_lightRgbInnerR", bgfx::UniformType::Vec4); + + // Create program from shaders. + m_geomProgram = loadProgram("vs_deferred_geom", "fs_deferred_geom"); + m_lightProgram = loadProgram("vs_deferred_light", "fs_deferred_light"); + m_combineProgram = loadProgram("vs_deferred_combine", "fs_deferred_combine"); + m_debugProgram = loadProgram("vs_deferred_debug", "fs_deferred_debug"); + m_lineProgram = loadProgram("vs_deferred_debug_line", "fs_deferred_debug_line"); + + // Load diffuse texture. + m_textureColor = loadTexture("fieldstone-rgba.dds"); + + // Load normal texture. + m_textureNormal = loadTexture("fieldstone-n.dds"); + + m_gbufferTex[0].idx = bgfx::invalidHandle; + m_gbufferTex[1].idx = bgfx::invalidHandle; + m_gbufferTex[2].idx = bgfx::invalidHandle; + m_gbuffer.idx = bgfx::invalidHandle; + m_lightBuffer.idx = bgfx::invalidHandle; + + // Imgui. + imguiCreate(); + + m_timeOffset = bx::getHPCounter(); + const bgfx::RendererType::Enum renderer = bgfx::getRendererType(); + s_texelHalf = bgfx::RendererType::Direct3D9 == renderer ? 0.5f : 0.0f; + s_originBottomLeft = bgfx::RendererType::OpenGL == renderer || bgfx::RendererType::OpenGLES == renderer; + + // Get renderer capabilities info. + m_caps = bgfx::getCaps(); + + m_oldWidth = 0; + m_oldHeight = 0; + m_oldReset = m_reset; + + m_scrollArea = 0; + m_numLights = 512; + m_lightAnimationSpeed = 0.3f; + m_animateMesh = true; + m_showScissorRects = false; + m_showGBuffer = true; + + cameraCreate(); + + const float initialPos[3] = { 0.0f, 0.0f, -15.0f }; + cameraSetPosition(initialPos); + cameraSetVerticalAngle(0.0f); + } + + virtual int shutdown() BX_OVERRIDE + { + // Cleanup. + cameraDestroy(); + imguiDestroy(); + + if (bgfx::isValid(m_gbuffer) ) + { + bgfx::destroyFrameBuffer(m_gbuffer); + bgfx::destroyFrameBuffer(m_lightBuffer); + } + + bgfx::destroyIndexBuffer(m_ibh); + bgfx::destroyVertexBuffer(m_vbh); + + bgfx::destroyProgram(m_geomProgram); + bgfx::destroyProgram(m_lightProgram); + bgfx::destroyProgram(m_combineProgram); + bgfx::destroyProgram(m_debugProgram); + bgfx::destroyProgram(m_lineProgram); + + bgfx::destroyTexture(m_textureColor); + bgfx::destroyTexture(m_textureNormal); + bgfx::destroyUniform(s_texColor); + bgfx::destroyUniform(s_texNormal); + + bgfx::destroyUniform(s_albedo); + bgfx::destroyUniform(s_normal); + bgfx::destroyUniform(s_depth); + bgfx::destroyUniform(s_light); + + bgfx::destroyUniform(u_lightPosRadius); + bgfx::destroyUniform(u_lightRgbInnerR); + bgfx::destroyUniform(u_mtx); + + // Shutdown bgfx. + bgfx::shutdown(); + + return 0; + } + + bool update() BX_OVERRIDE + { + if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) ) + { + int64_t now = bx::getHPCounter(); + static int64_t last = now; + const int64_t frameTime = now - last; + last = now; + const double freq = double(bx::getHPFrequency() ); + const double toMs = 1000.0/freq; + const float deltaTime = float(frameTime/freq); + + float time = (float)( (now-m_timeOffset)/freq); + + // Use m_debug font to print information about this example. + bgfx::dbgTextClear(); + bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/21-deferred"); + bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: MRT rendering and deferred shading."); + bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + + if (2 > m_caps->maxFBAttachments) { - showGBuffer = !showGBuffer; + // When multiple render targets (MRT) is not supported by GPU, + // implement alternative code path that doesn't use MRT. + bool blink = uint32_t(time*3.0f)&1; + bgfx::dbgTextPrintf(0, 5, blink ? 0x1f : 0x01, " MRT not supported by GPU. "); + + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, m_width, m_height); + + // This dummy draw call is here to make sure that view 0 is cleared + // if no other draw calls are submitted to view 0. + bgfx::touch(0); } - - if (imguiCheck("Show light scissor.", showScissorRects) ) + else { - showScissorRects = !showScissorRects; - } - - if (imguiCheck("Animate mesh.", animateMesh) ) - { - animateMesh = !animateMesh; - } - - imguiSlider("Lights animation speed", lightAnimationSpeed, 0.0f, 0.4f, 0.01f); - - imguiEndScrollArea(); - imguiEndFrame(); - - // Update camera. - cameraUpdate(deltaTime, mouseState); - cameraGetViewMtx(view); - - // Setup views - float vp[16]; - float invMvp[16]; - { - bgfx::setViewRect(RENDER_PASS_GEOMETRY_ID, 0, 0, width, height); - bgfx::setViewRect(RENDER_PASS_LIGHT_ID, 0, 0, width, height); - bgfx::setViewRect(RENDER_PASS_COMBINE_ID, 0, 0, width, height); - bgfx::setViewRect(RENDER_PASS_DEBUG_LIGHTS_ID, 0, 0, width, height); - bgfx::setViewRect(RENDER_PASS_DEBUG_GBUFFER_ID, 0, 0, width, height); - - bgfx::setViewFrameBuffer(RENDER_PASS_LIGHT_ID, lightBuffer); - - float proj[16]; - mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f); - - bgfx::setViewFrameBuffer(RENDER_PASS_GEOMETRY_ID, gbuffer); - bgfx::setViewTransform(RENDER_PASS_GEOMETRY_ID, view, proj); - - bx::mtxMul(vp, view, proj); - bx::mtxInverse(invMvp, vp); - - bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f); - bgfx::setViewTransform(RENDER_PASS_LIGHT_ID, NULL, proj); - bgfx::setViewTransform(RENDER_PASS_COMBINE_ID, NULL, proj); - - const float aspectRatio = float(height)/float(width); - const float size = 10.0f; - bx::mtxOrtho(proj, -size, size, size*aspectRatio, -size*aspectRatio, 0.0f, 1000.0f); - bgfx::setViewTransform(RENDER_PASS_DEBUG_GBUFFER_ID, NULL, proj); - - bx::mtxOrtho(proj, 0.0f, (float)width, 0.0f, (float)height, 0.0f, 1000.0f); - bgfx::setViewTransform(RENDER_PASS_DEBUG_LIGHTS_ID, NULL, proj); - } - - const uint32_t dim = 11; - const float offset = (float(dim-1) * 3.0f) * 0.5f; - - // Draw into geometry pass. - for (uint32_t yy = 0; yy < dim; ++yy) - { - for (uint32_t xx = 0; xx < dim; ++xx) + if (m_oldWidth != m_width + || m_oldHeight != m_height + || m_oldReset != m_reset + || !bgfx::isValid(m_gbuffer) ) { - float mtx[16]; - if (animateMesh) + // Recreate variable size render targets when resolution changes. + m_oldWidth = m_width; + m_oldHeight = m_height; + m_oldReset = m_reset; + + if (bgfx::isValid(m_gbuffer) ) { - bx::mtxRotateXY(mtx, time*1.023f + xx*0.21f, time*0.03f + yy*0.37f); + bgfx::destroyFrameBuffer(m_gbuffer); } - else + + const uint32_t samplerFlags = 0 + | BGFX_TEXTURE_RT + | BGFX_TEXTURE_MIN_POINT + | BGFX_TEXTURE_MAG_POINT + | BGFX_TEXTURE_MIP_POINT + | BGFX_TEXTURE_U_CLAMP + | BGFX_TEXTURE_V_CLAMP + ; + m_gbufferTex[0] = bgfx::createTexture2D(m_width, m_height, 1, bgfx::TextureFormat::BGRA8, samplerFlags); + m_gbufferTex[1] = bgfx::createTexture2D(m_width, m_height, 1, bgfx::TextureFormat::BGRA8, samplerFlags); + m_gbufferTex[2] = bgfx::createTexture2D(m_width, m_height, 1, bgfx::TextureFormat::D24, samplerFlags); + m_gbuffer = bgfx::createFrameBuffer(BX_COUNTOF(m_gbufferTex), m_gbufferTex, true); + + if (bgfx::isValid(m_lightBuffer) ) { - bx::mtxIdentity(mtx); + bgfx::destroyFrameBuffer(m_lightBuffer); } - mtx[12] = -offset + float(xx)*3.0f; - mtx[13] = -offset + float(yy)*3.0f; - mtx[14] = 0.0f; - // Set transform for draw call. - bgfx::setTransform(mtx); + m_lightBuffer = bgfx::createFrameBuffer(m_width, m_height, bgfx::TextureFormat::BGRA8, samplerFlags); + } - // Set vertex and index buffer. - bgfx::setVertexBuffer(vbh); - bgfx::setIndexBuffer(ibh); - - // Bind textures. - bgfx::setTexture(0, s_texColor, textureColor); - bgfx::setTexture(1, s_texNormal, textureNormal); - - // Set render states. - bgfx::setState(0 - | BGFX_STATE_RGB_WRITE - | BGFX_STATE_ALPHA_WRITE - | BGFX_STATE_DEPTH_WRITE - | BGFX_STATE_DEPTH_TEST_LESS - | BGFX_STATE_MSAA + imguiBeginFrame(m_mouseState.m_mx + , m_mouseState.m_my + , (m_mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0) + | (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0) + , m_mouseState.m_mz + , m_width + , m_height ); - // Submit primitive for rendering to view 0. - bgfx::submit(RENDER_PASS_GEOMETRY_ID, geomProgram); - } - } + imguiBeginScrollArea("Settings", m_width - m_width / 5 - 10, 10, m_width / 5, m_height / 3, &m_scrollArea); + imguiSeparatorLine(); - // Draw lights into light buffer. - for (int32_t light = 0; light < numLights; ++light) - { - Sphere lightPosRadius; + imguiSlider("Num lights", m_numLights, 1, 2048); - float lightTime = time * lightAnimationSpeed * (sinf(light/float(numLights) * bx::piHalf ) * 0.5f + 0.5f); - lightPosRadius.m_center[0] = sinf( ( (lightTime + light*0.47f) + bx::piHalf*1.37f ) )*offset; - lightPosRadius.m_center[1] = cosf( ( (lightTime + light*0.69f) + bx::piHalf*1.49f ) )*offset; - lightPosRadius.m_center[2] = sinf( ( (lightTime + light*0.37f) + bx::piHalf*1.57f ) )*2.0f; - lightPosRadius.m_radius = 2.0f; - - Aabb aabb; - sphereToAabb(aabb, lightPosRadius); - - float box[8][3] = + if (imguiCheck("Show G-Buffer.", m_showGBuffer) ) { - { aabb.m_min[0], aabb.m_min[1], aabb.m_min[2] }, - { aabb.m_min[0], aabb.m_min[1], aabb.m_max[2] }, - { aabb.m_min[0], aabb.m_max[1], aabb.m_min[2] }, - { aabb.m_min[0], aabb.m_max[1], aabb.m_max[2] }, - { aabb.m_max[0], aabb.m_min[1], aabb.m_min[2] }, - { aabb.m_max[0], aabb.m_min[1], aabb.m_max[2] }, - { aabb.m_max[0], aabb.m_max[1], aabb.m_min[2] }, - { aabb.m_max[0], aabb.m_max[1], aabb.m_max[2] }, - }; - - float xyz[3]; - bx::vec3MulMtxH(xyz, box[0], vp); - float minx = xyz[0]; - float miny = xyz[1]; - float maxx = xyz[0]; - float maxy = xyz[1]; - float maxz = xyz[2]; - - for (uint32_t ii = 1; ii < 8; ++ii) - { - bx::vec3MulMtxH(xyz, box[ii], vp); - minx = bx::fmin(minx, xyz[0]); - miny = bx::fmin(miny, xyz[1]); - maxx = bx::fmax(maxx, xyz[0]); - maxy = bx::fmax(maxy, xyz[1]); - maxz = bx::fmax(maxz, xyz[2]); + m_showGBuffer = !m_showGBuffer; } - // Cull light if it's fully behind camera. - if (maxz >= 0.0f) + if (imguiCheck("Show light scissor.", m_showScissorRects) ) { - float x0 = bx::fclamp( (minx * 0.5f + 0.5f) * width, 0.0f, (float)width); - float y0 = bx::fclamp( (miny * 0.5f + 0.5f) * height, 0.0f, (float)height); - float x1 = bx::fclamp( (maxx * 0.5f + 0.5f) * width, 0.0f, (float)width); - float y1 = bx::fclamp( (maxy * 0.5f + 0.5f) * height, 0.0f, (float)height); + m_showScissorRects = !m_showScissorRects; + } - if (showScissorRects) + if (imguiCheck("Animate mesh.", m_animateMesh) ) + { + m_animateMesh = !m_animateMesh; + } + + imguiSlider("Lights animation speed", m_lightAnimationSpeed, 0.0f, 0.4f, 0.01f); + + imguiEndScrollArea(); + imguiEndFrame(); + + // Update camera. + cameraUpdate(deltaTime, m_mouseState); + + float view[16]; + cameraGetViewMtx(view); + + // Setup views + float vp[16]; + float invMvp[16]; + { + bgfx::setViewRect(RENDER_PASS_GEOMETRY_ID, 0, 0, m_width, m_height); + bgfx::setViewRect(RENDER_PASS_LIGHT_ID, 0, 0, m_width, m_height); + bgfx::setViewRect(RENDER_PASS_COMBINE_ID, 0, 0, m_width, m_height); + bgfx::setViewRect(RENDER_PASS_DEBUG_LIGHTS_ID, 0, 0, m_width, m_height); + bgfx::setViewRect(RENDER_PASS_DEBUG_GBUFFER_ID, 0, 0, m_width, m_height); + + bgfx::setViewFrameBuffer(RENDER_PASS_LIGHT_ID, m_lightBuffer); + + float proj[16]; + mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f); + + bgfx::setViewFrameBuffer(RENDER_PASS_GEOMETRY_ID, m_gbuffer); + bgfx::setViewTransform(RENDER_PASS_GEOMETRY_ID, view, proj); + + bx::mtxMul(vp, view, proj); + bx::mtxInverse(invMvp, vp); + + bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f); + bgfx::setViewTransform(RENDER_PASS_LIGHT_ID, NULL, proj); + bgfx::setViewTransform(RENDER_PASS_COMBINE_ID, NULL, proj); + + const float aspectRatio = float(m_height)/float(m_width); + const float size = 10.0f; + bx::mtxOrtho(proj, -size, size, size*aspectRatio, -size*aspectRatio, 0.0f, 1000.0f); + bgfx::setViewTransform(RENDER_PASS_DEBUG_GBUFFER_ID, NULL, proj); + + bx::mtxOrtho(proj, 0.0f, (float)m_width, 0.0f, (float)m_height, 0.0f, 1000.0f); + bgfx::setViewTransform(RENDER_PASS_DEBUG_LIGHTS_ID, NULL, proj); + } + + const uint32_t dim = 11; + const float offset = (float(dim-1) * 3.0f) * 0.5f; + + // Draw into geometry pass. + for (uint32_t yy = 0; yy < dim; ++yy) + { + for (uint32_t xx = 0; xx < dim; ++xx) { - bgfx::TransientVertexBuffer tvb; - bgfx::TransientIndexBuffer tib; - if (bgfx::allocTransientBuffers(&tvb, DebugVertex::ms_decl, 4, &tib, 8) ) + float mtx[16]; + if (m_animateMesh) { - uint32_t abgr = 0x8000ff00; - - DebugVertex* vertex = (DebugVertex*)tvb.data; - vertex->m_x = x0; - vertex->m_y = y0; - vertex->m_z = 0.0f; - vertex->m_abgr = abgr; - ++vertex; - - vertex->m_x = x1; - vertex->m_y = y0; - vertex->m_z = 0.0f; - vertex->m_abgr = abgr; - ++vertex; - - vertex->m_x = x1; - vertex->m_y = y1; - vertex->m_z = 0.0f; - vertex->m_abgr = abgr; - ++vertex; - - vertex->m_x = x0; - vertex->m_y = y1; - vertex->m_z = 0.0f; - vertex->m_abgr = abgr; - - uint16_t* indices = (uint16_t*)tib.data; - *indices++ = 0; - *indices++ = 1; - *indices++ = 1; - *indices++ = 2; - *indices++ = 2; - *indices++ = 3; - *indices++ = 3; - *indices++ = 0; - - bgfx::setVertexBuffer(&tvb); - bgfx::setIndexBuffer(&tib); - bgfx::setState(0 - | BGFX_STATE_RGB_WRITE - | BGFX_STATE_PT_LINES - | BGFX_STATE_BLEND_ALPHA - ); - bgfx::submit(RENDER_PASS_DEBUG_LIGHTS_ID, lineProgram); + bx::mtxRotateXY(mtx, time*1.023f + xx*0.21f, time*0.03f + yy*0.37f); } - } + else + { + bx::mtxIdentity(mtx); + } + mtx[12] = -offset + float(xx)*3.0f; + mtx[13] = -offset + float(yy)*3.0f; + mtx[14] = 0.0f; - uint8_t val = light&7; - float lightRgbInnerR[4] = + // Set transform for draw call. + bgfx::setTransform(mtx); + + // Set vertex and index buffer. + bgfx::setVertexBuffer(m_vbh); + bgfx::setIndexBuffer(m_ibh); + + // Bind textures. + bgfx::setTexture(0, s_texColor, m_textureColor); + bgfx::setTexture(1, s_texNormal, m_textureNormal); + + // Set render states. + bgfx::setState(0 + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_ALPHA_WRITE + | BGFX_STATE_DEPTH_WRITE + | BGFX_STATE_DEPTH_TEST_LESS + | BGFX_STATE_MSAA + ); + + // Submit primitive for rendering to view 0. + bgfx::submit(RENDER_PASS_GEOMETRY_ID, m_geomProgram); + } + } + + // Draw lights into light buffer. + for (int32_t light = 0; light < m_numLights; ++light) + { + Sphere lightPosRadius; + + float lightTime = time * m_lightAnimationSpeed * (sinf(light/float(m_numLights) * bx::piHalf ) * 0.5f + 0.5f); + lightPosRadius.m_center[0] = sinf( ( (lightTime + light*0.47f) + bx::piHalf*1.37f ) )*offset; + lightPosRadius.m_center[1] = cosf( ( (lightTime + light*0.69f) + bx::piHalf*1.49f ) )*offset; + lightPosRadius.m_center[2] = sinf( ( (lightTime + light*0.37f) + bx::piHalf*1.57f ) )*2.0f; + lightPosRadius.m_radius = 2.0f; + + Aabb aabb; + sphereToAabb(aabb, lightPosRadius); + + float box[8][3] = { - val & 0x1 ? 1.0f : 0.25f, - val & 0x2 ? 1.0f : 0.25f, - val & 0x4 ? 1.0f : 0.25f, - 0.8f, + { aabb.m_min[0], aabb.m_min[1], aabb.m_min[2] }, + { aabb.m_min[0], aabb.m_min[1], aabb.m_max[2] }, + { aabb.m_min[0], aabb.m_max[1], aabb.m_min[2] }, + { aabb.m_min[0], aabb.m_max[1], aabb.m_max[2] }, + { aabb.m_max[0], aabb.m_min[1], aabb.m_min[2] }, + { aabb.m_max[0], aabb.m_min[1], aabb.m_max[2] }, + { aabb.m_max[0], aabb.m_max[1], aabb.m_min[2] }, + { aabb.m_max[0], aabb.m_max[1], aabb.m_max[2] }, }; - // Draw light. - bgfx::setUniform(u_lightPosRadius, &lightPosRadius); - bgfx::setUniform(u_lightRgbInnerR, lightRgbInnerR); - bgfx::setUniform(u_mtx, invMvp); - const uint16_t scissorHeight = uint16_t(y1-y0); - bgfx::setScissor(uint16_t(x0), height-scissorHeight-uint16_t(y0), uint16_t(x1-x0), scissorHeight); - bgfx::setTexture(0, s_normal, gbuffer, 1); - bgfx::setTexture(1, s_depth, gbuffer, 2); - bgfx::setState(0 + float xyz[3]; + bx::vec3MulMtxH(xyz, box[0], vp); + float minx = xyz[0]; + float miny = xyz[1]; + float maxx = xyz[0]; + float maxy = xyz[1]; + float maxz = xyz[2]; + + for (uint32_t ii = 1; ii < 8; ++ii) + { + bx::vec3MulMtxH(xyz, box[ii], vp); + minx = bx::fmin(minx, xyz[0]); + miny = bx::fmin(miny, xyz[1]); + maxx = bx::fmax(maxx, xyz[0]); + maxy = bx::fmax(maxy, xyz[1]); + maxz = bx::fmax(maxz, xyz[2]); + } + + // Cull light if it's fully behind camera. + if (maxz >= 0.0f) + { + float x0 = bx::fclamp( (minx * 0.5f + 0.5f) * m_width, 0.0f, (float)m_width); + float y0 = bx::fclamp( (miny * 0.5f + 0.5f) * m_height, 0.0f, (float)m_height); + float x1 = bx::fclamp( (maxx * 0.5f + 0.5f) * m_width, 0.0f, (float)m_width); + float y1 = bx::fclamp( (maxy * 0.5f + 0.5f) * m_height, 0.0f, (float)m_height); + + if (m_showScissorRects) + { + bgfx::TransientVertexBuffer tvb; + bgfx::TransientIndexBuffer tib; + if (bgfx::allocTransientBuffers(&tvb, DebugVertex::ms_decl, 4, &tib, 8) ) + { + uint32_t abgr = 0x8000ff00; + + DebugVertex* vertex = (DebugVertex*)tvb.data; + vertex->m_x = x0; + vertex->m_y = y0; + vertex->m_z = 0.0f; + vertex->m_abgr = abgr; + ++vertex; + + vertex->m_x = x1; + vertex->m_y = y0; + vertex->m_z = 0.0f; + vertex->m_abgr = abgr; + ++vertex; + + vertex->m_x = x1; + vertex->m_y = y1; + vertex->m_z = 0.0f; + vertex->m_abgr = abgr; + ++vertex; + + vertex->m_x = x0; + vertex->m_y = y1; + vertex->m_z = 0.0f; + vertex->m_abgr = abgr; + + uint16_t* indices = (uint16_t*)tib.data; + *indices++ = 0; + *indices++ = 1; + *indices++ = 1; + *indices++ = 2; + *indices++ = 2; + *indices++ = 3; + *indices++ = 3; + *indices++ = 0; + + bgfx::setVertexBuffer(&tvb); + bgfx::setIndexBuffer(&tib); + bgfx::setState(0 + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_PT_LINES + | BGFX_STATE_BLEND_ALPHA + ); + bgfx::submit(RENDER_PASS_DEBUG_LIGHTS_ID, m_lineProgram); + } + } + + uint8_t val = light&7; + float lightRgbInnerR[4] = + { + val & 0x1 ? 1.0f : 0.25f, + val & 0x2 ? 1.0f : 0.25f, + val & 0x4 ? 1.0f : 0.25f, + 0.8f, + }; + + // Draw light. + bgfx::setUniform(u_lightPosRadius, &lightPosRadius); + bgfx::setUniform(u_lightRgbInnerR, lightRgbInnerR); + bgfx::setUniform(u_mtx, invMvp); + const uint16_t scissorHeight = uint16_t(y1-y0); + bgfx::setScissor(uint16_t(x0), m_height-scissorHeight-uint16_t(y0), uint16_t(x1-x0), scissorHeight); + bgfx::setTexture(0, s_normal, m_gbuffer, 1); + bgfx::setTexture(1, s_depth, m_gbuffer, 2); + bgfx::setState(0 + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_ALPHA_WRITE + | BGFX_STATE_BLEND_ADD + ); + screenSpaceQuad( (float)m_width, (float)m_height, s_texelHalf, s_originBottomLeft); + bgfx::submit(RENDER_PASS_LIGHT_ID, m_lightProgram); + } + } + + // Combine color and light buffers. + bgfx::setTexture(0, s_albedo, m_gbuffer, 0); + bgfx::setTexture(1, s_light, m_lightBuffer, 0); + bgfx::setState(0 | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE - | BGFX_STATE_BLEND_ADD ); - screenSpaceQuad( (float)width, (float)height, texelHalf, s_originBottomLeft); - bgfx::submit(RENDER_PASS_LIGHT_ID, lightProgram); - } - } + screenSpaceQuad( (float)m_width, (float)m_height, s_texelHalf, s_originBottomLeft); + bgfx::submit(RENDER_PASS_COMBINE_ID, m_combineProgram); - // Combine color and light buffers. - bgfx::setTexture(0, s_albedo, gbuffer, 0); - bgfx::setTexture(1, s_light, lightBuffer, 0); - bgfx::setState(0 - | BGFX_STATE_RGB_WRITE - | BGFX_STATE_ALPHA_WRITE - ); - screenSpaceQuad( (float)width, (float)height, texelHalf, s_originBottomLeft); - bgfx::submit(RENDER_PASS_COMBINE_ID, combineProgram); - - if (showGBuffer) - { - const float aspectRatio = float(width)/float(height); - - // Draw debug GBuffer. - for (uint32_t ii = 0; ii < BX_COUNTOF(gbufferTex); ++ii) + if (m_showGBuffer) { - float mtx[16]; - bx::mtxSRT(mtx - , aspectRatio, 1.0f, 1.0f - , 0.0f, 0.0f, 0.0f - , -7.9f - BX_COUNTOF(gbufferTex)*0.1f*0.5f + ii*2.1f*aspectRatio, 4.0f, 0.0f - ); + const float aspectRatio = float(m_width)/float(m_height); - bgfx::setTransform(mtx); - bgfx::setVertexBuffer(vbh); - bgfx::setIndexBuffer(ibh, 0, 6); - bgfx::setTexture(0, s_texColor, gbufferTex[ii]); - bgfx::setState(BGFX_STATE_RGB_WRITE); - bgfx::submit(RENDER_PASS_DEBUG_GBUFFER_ID, debugProgram); + // Draw m_debug m_gbuffer. + for (uint32_t ii = 0; ii < BX_COUNTOF(m_gbufferTex); ++ii) + { + float mtx[16]; + bx::mtxSRT(mtx + , aspectRatio, 1.0f, 1.0f + , 0.0f, 0.0f, 0.0f + , -7.9f - BX_COUNTOF(m_gbufferTex)*0.1f*0.5f + ii*2.1f*aspectRatio, 4.0f, 0.0f + ); + + bgfx::setTransform(mtx); + bgfx::setVertexBuffer(m_vbh); + bgfx::setIndexBuffer(m_ibh, 0, 6); + bgfx::setTexture(0, s_texColor, m_gbufferTex[ii]); + bgfx::setState(BGFX_STATE_RGB_WRITE); + bgfx::submit(RENDER_PASS_DEBUG_GBUFFER_ID, m_debugProgram); + } } } + + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); + + return true; } - // Advance to next frame. Rendering thread will be kicked to - // process submitted rendering primitives. - bgfx::frame(); + return false; } - // Cleanup. - cameraDestroy(); - imguiDestroy(); + bgfx::VertexBufferHandle m_vbh; + bgfx::IndexBufferHandle m_ibh; + bgfx::UniformHandle s_texColor; + bgfx::UniformHandle s_texNormal; - if (bgfx::isValid(gbuffer) ) - { - bgfx::destroyFrameBuffer(gbuffer); - bgfx::destroyFrameBuffer(lightBuffer); - } + bgfx::UniformHandle s_albedo; + bgfx::UniformHandle s_normal; + bgfx::UniformHandle s_depth; + bgfx::UniformHandle s_light; - bgfx::destroyIndexBuffer(ibh); - bgfx::destroyVertexBuffer(vbh); + bgfx::UniformHandle u_mtx; + bgfx::UniformHandle u_lightPosRadius; + bgfx::UniformHandle u_lightRgbInnerR; - bgfx::destroyProgram(geomProgram); - bgfx::destroyProgram(lightProgram); - bgfx::destroyProgram(combineProgram); - bgfx::destroyProgram(debugProgram); - bgfx::destroyProgram(lineProgram); + bgfx::ProgramHandle m_geomProgram; + bgfx::ProgramHandle m_lightProgram; + bgfx::ProgramHandle m_combineProgram; + bgfx::ProgramHandle m_debugProgram; + bgfx::ProgramHandle m_lineProgram; + bgfx::TextureHandle m_textureColor; + bgfx::TextureHandle m_textureNormal; - bgfx::destroyTexture(textureColor); - bgfx::destroyTexture(textureNormal); - bgfx::destroyUniform(s_texColor); - bgfx::destroyUniform(s_texNormal); + bgfx::TextureHandle m_gbufferTex[3]; + bgfx::FrameBufferHandle m_gbuffer; + bgfx::FrameBufferHandle m_lightBuffer; - bgfx::destroyUniform(s_albedo); - bgfx::destroyUniform(s_normal); - bgfx::destroyUniform(s_depth); - bgfx::destroyUniform(s_light); + uint32_t m_width; + uint32_t m_height; + uint32_t m_debug; + uint32_t m_reset; - bgfx::destroyUniform(u_lightPosRadius); - bgfx::destroyUniform(u_lightRgbInnerR); - bgfx::destroyUniform(u_mtx); + uint32_t m_oldWidth; + uint32_t m_oldHeight; + uint32_t m_oldReset; - // Shutdown bgfx. - bgfx::shutdown(); + int32_t m_scrollArea; + int32_t m_numLights; + float m_lightAnimationSpeed; + bool m_animateMesh; + bool m_showScissorRects; + bool m_showGBuffer; - return 0; -} + entry::MouseState m_mouseState; + + const bgfx::Caps* m_caps; + int64_t m_timeOffset; +}; + +ENTRY_IMPLEMENT_MAIN(Deferred); diff --git a/examples/common/camera.cpp b/examples/common/camera.cpp index 63ed98aa..4d0a4716 100644 --- a/examples/common/camera.cpp +++ b/examples/common/camera.cpp @@ -53,7 +53,7 @@ static void cmd(const void* _userData) cmdExec( (const char*)_userData); } -static const InputBinding s_camBindings[] = +static const InputBinding s_camBindings[] = { { entry::Key::KeyW, entry::Modifier::None, 0, cmd, "move forward" }, { entry::Key::GamepadUp, entry::Modifier::None, 0, cmd, "move forward" }, @@ -258,7 +258,7 @@ struct Camera bx::mtxLookAt(_viewMtx, m_eye, m_at, m_up); } - void setPosition(float* _pos) + void setPosition(const float* _pos) { memcpy(m_eye, _pos, sizeof(float)*3); } @@ -267,7 +267,7 @@ struct Camera { m_verticalAngle = _verticalAngle; } - + void setHorizontalAngle(float _horizontalAngle) { m_horizontalAngle = _horizontalAngle; @@ -303,7 +303,7 @@ void cameraDestroy() s_camera = NULL; } -void cameraSetPosition(float* _pos) +void cameraSetPosition(const float* _pos) { s_camera->setPosition(_pos); } diff --git a/examples/common/camera.h b/examples/common/camera.h index 946ff6e2..2619d1ba 100644 --- a/examples/common/camera.h +++ b/examples/common/camera.h @@ -22,7 +22,7 @@ void cameraCreate(); void cameraDestroy(); /// -void cameraSetPosition(float* _pos); +void cameraSetPosition(const float* _pos); /// void cameraSetHorizontalAngle(float _horizontalAngle);