bgfx/examples/15-shadowmaps-simple/shadowmaps_simple.cpp

456 lines
12 KiB
C++
Raw Normal View History

/*
2014-01-14 02:45:18 +04:00
* Copyright 2013-2014 Dario Manesku. All rights reserved.
2016-01-01 11:11:04 +03:00
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
#include <string>
#include <vector>
#include <algorithm>
#include "common.h"
#include <bgfx/bgfx.h>
#include <bx/timer.h>
#include <bx/readerwriter.h>
2014-05-27 06:31:37 +04:00
#include <bx/fpumath.h>
#include "entry/entry.h"
2015-01-08 09:36:36 +03:00
#include "bgfx_utils.h"
2017-06-26 07:44:04 +03:00
#include "imgui/imgui.h"
namespace
{
2014-01-14 09:48:42 +04:00
#define RENDER_SHADOW_PASS_ID 0
#define RENDER_SCENE_PASS_ID 1
struct PosNormalVertex
{
float m_x;
float m_y;
float m_z;
uint32_t m_normal;
2017-06-14 08:27:22 +03:00
static void init()
{
ms_decl
.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true)
.end();
};
static bgfx::VertexDecl ms_decl;
};
2017-06-14 08:27:22 +03:00
bgfx::VertexDecl PosNormalVertex::ms_decl;
static PosNormalVertex s_hplaneVertices[] =
{
2017-04-01 07:01:08 +03:00
{ -1.0f, 0.0f, 1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f) },
{ 1.0f, 0.0f, 1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f) },
{ -1.0f, 0.0f, -1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f) },
{ 1.0f, 0.0f, -1.0f, encodeNormalRgba8(0.0f, 1.0f, 0.0f) },
};
static const uint16_t s_planeIndices[] =
{
0, 1, 2,
1, 3, 2,
};
class ExampleShadowmapsSimple : public entry::AppI
{
2017-06-26 07:44:04 +03:00
public:
ExampleShadowmapsSimple(const char* _name, const char* _description)
: entry::AppI(_name, _description)
{
}
void init(int _argc, char** _argv) BX_OVERRIDE
{
Args args(_argc, _argv);
2017-06-14 04:42:17 +03:00
m_width = 1280;
m_height = 720;
2017-06-26 07:44:04 +03:00
m_debug = BGFX_DEBUG_NONE;
m_reset = BGFX_RESET_VSYNC;
2017-06-14 04:42:17 +03:00
bgfx::init(args.m_type, args.m_pciId);
bgfx::reset(m_width, m_height, m_reset);
2017-06-14 04:42:17 +03:00
// Enable debug text.
bgfx::setDebug(m_debug);
2017-06-14 04:42:17 +03:00
// Uniforms.
u_shadowMap = bgfx::createUniform("u_shadowMap", bgfx::UniformType::Int1);
u_lightPos = bgfx::createUniform("u_lightPos", bgfx::UniformType::Vec4);
u_lightMtx = bgfx::createUniform("u_lightMtx", bgfx::UniformType::Mat4);
2017-06-14 04:42:17 +03:00
// When using GL clip space depth range [-1, 1] and packing depth into color buffer, we need to
// adjust the depth range to be [0, 1] for writing to the color buffer
u_depthScaleOffset = bgfx::createUniform("u_depthScaleOffset", bgfx::UniformType::Vec4);
2017-06-14 06:17:04 +03:00
// Get renderer capabilities info.
const bgfx::Caps* caps = bgfx::getCaps();
float depthScaleOffset[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
if (caps->homogeneousDepth)
{
depthScaleOffset[0] = 0.5f;
depthScaleOffset[1] = 0.5f;
}
bgfx::setUniform(u_depthScaleOffset, depthScaleOffset);
2017-06-14 04:42:17 +03:00
2017-06-14 08:27:22 +03:00
// Create vertex stream declaration.
PosNormalVertex::init();
2017-06-14 04:42:17 +03:00
// Meshes.
m_bunny = meshLoad("meshes/bunny.bin");
m_cube = meshLoad("meshes/cube.bin");
m_hollowcube = meshLoad("meshes/hollowcube.bin");
2017-06-14 04:42:17 +03:00
m_vbh = bgfx::createVertexBuffer(
2017-06-14 06:17:04 +03:00
bgfx::makeRef(s_hplaneVertices, sizeof(s_hplaneVertices) )
2017-06-14 08:27:22 +03:00
, PosNormalVertex::ms_decl
2017-06-14 06:17:04 +03:00
);
2017-06-14 04:42:17 +03:00
m_ibh = bgfx::createIndexBuffer(
2017-06-14 06:17:04 +03:00
bgfx::makeRef(s_planeIndices, sizeof(s_planeIndices) )
);
2017-06-14 04:42:17 +03:00
// Render targets.
m_shadowMapSize = 512;
2017-06-14 04:42:17 +03:00
// Shadow samplers are supported at least partially supported if texture
// compare less equal feature is supported.
m_shadowSamplerSupported = 0 != (caps->supported & BGFX_CAPS_TEXTURE_COMPARE_LEQUAL);
2017-06-14 04:42:17 +03:00
bgfx::TextureHandle shadowMapTexture;
2017-06-14 04:42:17 +03:00
if (m_shadowSamplerSupported)
{
// Depth textures and shadow samplers are supported.
m_progShadow = loadProgram("vs_sms_shadow", "fs_sms_shadow");
m_progMesh = loadProgram("vs_sms_mesh", "fs_sms_mesh");
2017-06-14 04:42:17 +03:00
2017-06-14 08:27:22 +03:00
bgfx::TextureHandle fbtextures[] =
{
bgfx::createTexture2D(
m_shadowMapSize
, m_shadowMapSize
, false
, 1
, bgfx::TextureFormat::D16
, BGFX_TEXTURE_RT | BGFX_TEXTURE_COMPARE_LEQUAL
),
};
shadowMapTexture = fbtextures[0];
m_shadowMapFB = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
}
else
{
// Depth textures and shadow samplers are not supported. Use float
// depth packing into color buffer instead.
m_progShadow = loadProgram("vs_sms_shadow_pd", "fs_sms_shadow_pd");
m_progMesh = loadProgram("vs_sms_mesh", "fs_sms_mesh_pd");
2017-06-14 04:42:17 +03:00
bgfx::TextureHandle fbtextures[] =
{
2017-06-14 08:27:22 +03:00
bgfx::createTexture2D(
m_shadowMapSize
, m_shadowMapSize
, false
, 1
, bgfx::TextureFormat::BGRA8
, BGFX_TEXTURE_RT
),
bgfx::createTexture2D(
m_shadowMapSize
, m_shadowMapSize
, false
, 1
, bgfx::TextureFormat::D16
, BGFX_TEXTURE_RT_WRITE_ONLY
),
};
2017-06-14 08:27:22 +03:00
shadowMapTexture = fbtextures[0];
m_shadowMapFB = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
}
2017-06-14 04:42:17 +03:00
m_state[0] = meshStateCreate();
m_state[0]->m_state = 0
2017-06-14 06:17:04 +03:00
| BGFX_STATE_RGB_WRITE
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
;
m_state[0]->m_program = m_progShadow;
m_state[0]->m_viewId = RENDER_SHADOW_PASS_ID;
m_state[0]->m_numTextures = 0;
2017-06-14 04:42:17 +03:00
m_state[1] = meshStateCreate();
m_state[1]->m_state = 0
2017-06-14 06:17:04 +03:00
| BGFX_STATE_RGB_WRITE
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
;
m_state[1]->m_program = m_progMesh;
m_state[1]->m_viewId = RENDER_SCENE_PASS_ID;
m_state[1]->m_numTextures = 1;
m_state[1]->m_textures[0].m_flags = UINT32_MAX;
m_state[1]->m_textures[0].m_stage = 0;
m_state[1]->m_textures[0].m_sampler = u_shadowMap;
m_state[1]->m_textures[0].m_texture = shadowMapTexture;
2017-06-14 04:42:17 +03:00
// Set view and projection matrices.
2017-06-14 04:42:17 +03:00
float eye[3] = { 0.0f, 30.0f, -60.0f };
float at[3] = { 0.0f, 5.0f, 0.0f };
bx::mtxLookAt(m_view, eye, at);
2017-06-14 04:42:17 +03:00
const float aspect = float(int32_t(m_width) ) / float(int32_t(m_height) );
bx::mtxProj(m_proj, 60.0f, aspect, 0.1f, 1000.0f, bgfx::getCaps()->homogeneousDepth);
2017-06-14 04:42:17 +03:00
2017-06-14 08:27:22 +03:00
m_timeOffset = bx::getHPCounter();
2017-06-26 07:44:04 +03:00
imguiCreate();
}
2017-06-14 04:42:17 +03:00
virtual int shutdown() BX_OVERRIDE
{
2017-06-26 07:44:04 +03:00
imguiDestroy();
meshUnload(m_bunny);
meshUnload(m_cube);
meshUnload(m_hollowcube);
2017-06-14 04:42:17 +03:00
meshStateDestroy(m_state[0]);
meshStateDestroy(m_state[1]);
2017-06-14 04:42:17 +03:00
bgfx::destroyVertexBuffer(m_vbh);
bgfx::destroyIndexBuffer(m_ibh);
2017-06-14 04:42:17 +03:00
bgfx::destroyProgram(m_progShadow);
bgfx::destroyProgram(m_progMesh);
2017-06-14 04:42:17 +03:00
bgfx::destroyFrameBuffer(m_shadowMapFB);
2017-06-14 04:42:17 +03:00
bgfx::destroyUniform(u_shadowMap);
bgfx::destroyUniform(u_lightPos);
bgfx::destroyUniform(u_lightMtx);
bgfx::destroyUniform(u_depthScaleOffset);
2017-06-14 04:42:17 +03:00
// Shutdown bgfx.
bgfx::shutdown();
2017-06-14 04:42:17 +03:00
return 0;
}
bool update() BX_OVERRIDE
{
2017-06-26 07:44:04 +03:00
if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
2015-01-08 09:36:36 +03:00
{
2017-06-26 07:44:04 +03:00
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_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
, m_mouseState.m_mz
, uint16_t(m_width)
, uint16_t(m_height)
);
bool restart = showExampleDialog(this);
imguiEndFrame();
int64_t now = bx::getHPCounter();
const double freq = double(bx::getHPFrequency() );
2017-06-14 08:27:22 +03:00
float time = float( (now-m_timeOffset)/freq);
2017-06-14 04:42:17 +03:00
// Setup lights.
float lightPos[4];
2017-06-14 08:27:22 +03:00
lightPos[0] = -bx::fcos(time);
lightPos[1] = -1.0f;
2017-06-14 08:27:22 +03:00
lightPos[2] = -bx::fsin(time);
lightPos[3] = 0.0f;
2017-06-14 04:42:17 +03:00
bgfx::setUniform(u_lightPos, lightPos);
2017-06-14 04:42:17 +03:00
// Setup instance matrices.
float mtxFloor[16];
bx::mtxSRT(mtxFloor
2017-06-14 06:17:04 +03:00
, 30.0f, 30.0f, 30.0f
, 0.0f, 0.0f, 0.0f
, 0.0f, 0.0f, 0.0f
);
2017-06-14 04:42:17 +03:00
float mtxBunny[16];
bx::mtxSRT(mtxBunny
2017-06-14 06:17:04 +03:00
, 5.0f, 5.0f, 5.0f
2017-06-14 08:27:22 +03:00
, 0.0f, bx::kPi - time, 0.0f
2017-06-14 06:17:04 +03:00
, 15.0f, 5.0f, 0.0f
);
2017-06-14 04:42:17 +03:00
float mtxHollowcube[16];
bx::mtxSRT(mtxHollowcube
2017-06-14 06:17:04 +03:00
, 2.5f, 2.5f, 2.5f
2017-06-14 08:27:22 +03:00
, 0.0f, 1.56f - time, 0.0f
2017-06-14 06:17:04 +03:00
, 0.0f, 10.0f, 0.0f
);
2017-06-14 04:42:17 +03:00
float mtxCube[16];
bx::mtxSRT(mtxCube
2017-06-14 06:17:04 +03:00
, 2.5f, 2.5f, 2.5f
2017-06-14 08:27:22 +03:00
, 0.0f, 1.56f - time, 0.0f
2017-06-14 06:17:04 +03:00
, -15.0f, 5.0f, 0.0f
);
2017-06-14 04:42:17 +03:00
// Define matrices.
float lightView[16];
float lightProj[16];
2017-06-14 04:42:17 +03:00
float eye[3] = { -lightPos[0], -lightPos[1], -lightPos[2] };
float at[3] = { 0.0f, 0.0f, 0.0f };
2017-06-14 04:42:17 +03:00
bx::mtxLookAt(lightView, eye, at);
2017-06-14 04:42:17 +03:00
2017-06-14 06:17:04 +03:00
const bgfx::Caps* caps = bgfx::getCaps();
const float area = 30.0f;
2017-06-14 06:17:04 +03:00
bx::mtxOrtho(lightProj, -area, area, -area, area, -100.0f, 100.0f, 0.0f, caps->homogeneousDepth);
2017-06-14 04:42:17 +03:00
bgfx::setViewRect(RENDER_SHADOW_PASS_ID, 0, 0, m_shadowMapSize, m_shadowMapSize);
bgfx::setViewFrameBuffer(RENDER_SHADOW_PASS_ID, m_shadowMapFB);
bgfx::setViewTransform(RENDER_SHADOW_PASS_ID, lightView, lightProj);
2017-06-14 04:42:17 +03:00
bgfx::setViewRect(RENDER_SCENE_PASS_ID, 0, 0, uint16_t(m_width), uint16_t(m_height) );
bgfx::setViewTransform(RENDER_SCENE_PASS_ID, m_view, m_proj);
2017-06-14 04:42:17 +03:00
// Clear backbuffer and shadowmap framebuffer at beginning.
bgfx::setViewClear(RENDER_SHADOW_PASS_ID
2017-06-14 06:17:04 +03:00
, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
, 0x303030ff, 1.0f, 0
);
2017-06-14 04:42:17 +03:00
bgfx::setViewClear(RENDER_SCENE_PASS_ID
2017-06-14 06:17:04 +03:00
, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
, 0x303030ff, 1.0f, 0
);
2017-06-14 04:42:17 +03:00
// Render.
float mtxShadow[16];
float lightMtx[16];
2017-06-14 04:42:17 +03:00
2017-06-14 06:17:04 +03:00
const float sy = caps->originBottomLeft ? 0.5f : -0.5f;
const float sz = caps->homogeneousDepth ? 0.5f : 1.0f;
const float tz = caps->homogeneousDepth ? 0.5f : 0.0f;
const float mtxCrop[16] =
{
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, sy, 0.0f, 0.0f,
2017-06-14 06:17:04 +03:00
0.0f, 0.0f, sz, 0.0f,
0.5f, 0.5f, tz, 1.0f,
};
2017-06-14 04:42:17 +03:00
float mtxTmp[16];
bx::mtxMul(mtxTmp, lightProj, mtxCrop);
bx::mtxMul(mtxShadow, lightView, mtxTmp);
2017-06-14 04:42:17 +03:00
// Floor.
bx::mtxMul(lightMtx, mtxFloor, mtxShadow);
uint32_t cached = bgfx::setTransform(mtxFloor);
for (uint32_t pass = 0; pass < 2; ++pass)
2015-01-08 09:36:36 +03:00
{
const MeshState& st = *m_state[pass];
bgfx::setTransform(cached);
for (uint8_t tex = 0; tex < st.m_numTextures; ++tex)
{
const MeshState::Texture& texture = st.m_textures[tex];
bgfx::setTexture(texture.m_stage
2017-06-14 08:27:22 +03:00
, texture.m_sampler
, texture.m_texture
, texture.m_flags
);
}
bgfx::setUniform(u_lightMtx, lightMtx);
bgfx::setIndexBuffer(m_ibh);
bgfx::setVertexBuffer(0, m_vbh);
bgfx::setState(st.m_state);
bgfx::submit(st.m_viewId, st.m_program);
2015-01-08 09:36:36 +03:00
}
2017-06-14 04:42:17 +03:00
// Bunny.
bx::mtxMul(lightMtx, mtxBunny, mtxShadow);
bgfx::setUniform(u_lightMtx, lightMtx);
meshSubmit(m_bunny, &m_state[0], 1, mtxBunny);
bgfx::setUniform(u_lightMtx, lightMtx);
meshSubmit(m_bunny, &m_state[1], 1, mtxBunny);
2017-06-14 04:42:17 +03:00
// Hollow cube.
bx::mtxMul(lightMtx, mtxHollowcube, mtxShadow);
bgfx::setUniform(u_lightMtx, lightMtx);
meshSubmit(m_hollowcube, &m_state[0], 1, mtxHollowcube);
2015-01-08 09:36:36 +03:00
bgfx::setUniform(u_lightMtx, lightMtx);
meshSubmit(m_hollowcube, &m_state[1], 1, mtxHollowcube);
2017-06-14 04:42:17 +03:00
// Cube.
bx::mtxMul(lightMtx, mtxCube, mtxShadow);
bgfx::setUniform(u_lightMtx, lightMtx);
meshSubmit(m_cube, &m_state[0], 1, mtxCube);
bgfx::setUniform(u_lightMtx, lightMtx);
meshSubmit(m_cube, &m_state[1], 1, mtxCube);
2017-06-14 04:42:17 +03:00
// Advance to next frame. Rendering thread will be kicked to
// process submitted rendering primitives.
bgfx::frame();
2017-06-14 04:42:17 +03:00
2017-06-26 07:44:04 +03:00
return !restart;
2015-01-08 09:36:36 +03:00
}
2017-06-14 04:42:17 +03:00
return false;
}
2017-06-14 04:42:17 +03:00
entry::MouseState m_mouseState;
uint32_t m_width;
uint32_t m_height;
uint32_t m_debug;
uint32_t m_reset;
2017-06-14 04:42:17 +03:00
bgfx::UniformHandle u_shadowMap;
bgfx::UniformHandle u_lightPos;
bgfx::UniformHandle u_lightMtx;
2017-06-14 04:42:17 +03:00
bgfx::UniformHandle u_depthScaleOffset;
2017-06-14 04:42:17 +03:00
Mesh* m_bunny;
Mesh* m_cube;
Mesh* m_hollowcube;
2017-06-14 04:42:17 +03:00
bgfx::VertexBufferHandle m_vbh;
bgfx::IndexBufferHandle m_ibh;
2017-06-14 04:42:17 +03:00
uint16_t m_shadowMapSize;
2017-06-14 04:42:17 +03:00
bgfx::ProgramHandle m_progShadow;
bgfx::ProgramHandle m_progMesh;
bgfx::FrameBufferHandle m_shadowMapFB;
2017-06-14 04:42:17 +03:00
bool m_shadowSamplerSupported;
2017-06-14 04:42:17 +03:00
MeshState* m_state[2];
2017-06-14 04:42:17 +03:00
float m_view[16];
float m_proj[16];
2017-06-14 08:27:22 +03:00
int64_t m_timeOffset;
};
2017-06-26 07:44:04 +03:00
} // namespace
2017-06-26 07:44:04 +03:00
ENTRY_IMPLEMENT_MAIN(ExampleShadowmapsSimple, "15-shadowmaps-simple", "Shadow maps example");