Add parallax occlusion mapping example (#1104)

* Added example 33-pom

* Fixed warning in 33-pom example on Windows

* Deleted unused image files

* Deleted runtime textures and shaders
This commit is contained in:
Apoorva Joshi 2017-04-04 22:22:08 +05:30 committed by Branimir Karadžić
parent fc0dc6fd32
commit c50cc8493f
7 changed files with 557 additions and 0 deletions

94
examples/33-pom/fs_pom.sc Normal file
View File

@ -0,0 +1,94 @@
$input v_texcoord0, v_ts_light_pos, v_ts_view_pos, v_ts_frag_pos
#include "../common/common.sh"
SAMPLER2D(s_texColor, 0);
SAMPLER2D(s_texNormal, 1);
SAMPLER2D(s_texDepth, 2);
uniform int u_shading_type;
uniform int u_show_diffuse_texture;
uniform int u_parallax_scale;
uniform int u_num_steps;
vec2 parallax_uv(vec2 uv, vec3 view_dir)
{
float depth_scale = float(u_parallax_scale) / 1000.0;
if (u_shading_type == 2)
{
// Parallax mapping
float depth = texture2D(s_texDepth, uv).r;
vec2 p = view_dir.xy * (depth * depth_scale) / view_dir.z;
return uv - p;
}
else
{
float layer_depth = 1.0 / float(u_num_steps);
float cur_layer_depth = 0.0;
vec2 delta_uv = view_dir.xy * depth_scale / (view_dir.z * u_num_steps);
vec2 cur_uv = uv;
float depth_from_tex = texture2D(s_texDepth, cur_uv).r;
for (int i = 0; i < 32; i++)
{
cur_layer_depth += layer_depth;
cur_uv -= delta_uv;
depth_from_tex = texture2D(s_texDepth, cur_uv).r;
if (depth_from_tex < cur_layer_depth)
{
break;
}
}
if (u_shading_type == 3)
{
// Steep parallax mapping
return cur_uv;
}
else
{
// Parallax occlusion mapping
vec2 prev_uv = cur_uv + delta_uv;
float next = depth_from_tex - cur_layer_depth;
float prev = texture2D(s_texDepth, prev_uv).r - cur_layer_depth + layer_depth;
float weight = next / (next - prev);
return mix(cur_uv, prev_uv, weight);
}
}
}
void main()
{
vec3 light_dir = normalize(v_ts_light_pos - v_ts_frag_pos);
vec3 view_dir = normalize(v_ts_view_pos - v_ts_frag_pos);
// Only perturb the texture coordinates if a parallax technique is selected
vec2 uv = (u_shading_type < 2) ? v_texcoord0 : parallax_uv(v_texcoord0, view_dir);
vec3 albedo;
if (u_show_diffuse_texture == 0)
{
albedo = vec3(1.0, 1.0, 1.0);
}
else
{
albedo = texture2D(s_texColor, uv).rgb;
}
vec3 ambient = 0.3 * albedo;
vec3 norm;
if (u_shading_type == 0)
{
norm = vec3(0, 0, 1);
}
else
{
norm = normalize(texture2D(s_texNormal, uv).rgb * 2.0 - 1.0);
}
float diffuse = max(dot(light_dir, norm), 0.0);
gl_FragColor = vec4(diffuse * albedo + ambient, 1.0);
}

10
examples/33-pom/makefile Normal file
View File

@ -0,0 +1,10 @@
#
# Copyright 2011-2017 Branimir Karadzic. All rights reserved.
# License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
#
BGFX_DIR=../..
RUNTIME_DIR=$(BGFX_DIR)/examples/runtime
BUILD_DIR=../../.build
include $(BGFX_DIR)/scripts/shader.mk

394
examples/33-pom/pom.cpp Normal file
View File

@ -0,0 +1,394 @@
/*
* Copyright 2011-2017 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
#include "common.h"
#include "bgfx_utils.h"
#include <imgui/imgui.h>
struct PosTangentBitangentTexcoordVertex
{
float m_x;
float m_y;
float m_z;
uint32_t m_tangent;
uint32_t m_bitangent;
float m_u;
float m_v;
static void init()
{
ms_decl
.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true)
.add(bgfx::Attrib::Bitangent, 4, bgfx::AttribType::Uint8, true, true)
.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, true, true)
.end();
}
static bgfx::VertexDecl ms_decl;
};
bgfx::VertexDecl PosTangentBitangentTexcoordVertex::ms_decl;
uint32_t packUint32(uint8_t _x, uint8_t _y, uint8_t _z, uint8_t _w)
{
union
{
uint32_t ui32;
uint8_t arr[4];
} un;
un.arr[0] = _x;
un.arr[1] = _y;
un.arr[2] = _z;
un.arr[3] = _w;
return un.ui32;
}
uint32_t packF4u(float _x, float _y = 0.0f, float _z = 0.0f, float _w = 0.0f)
{
const uint8_t xx = uint8_t(_x*127.0f + 128.0f);
const uint8_t yy = uint8_t(_y*127.0f + 128.0f);
const uint8_t zz = uint8_t(_z*127.0f + 128.0f);
const uint8_t ww = uint8_t(_w*127.0f + 128.0f);
return packUint32(xx, yy, zz, ww);
}
static PosTangentBitangentTexcoordVertex s_cubeVertices[24] =
{
{-1, -1, 1, packF4u(-1, 0, 0), packF4u( 0, -1, 0), 1, 1 }, // Back
{ 1, 1, 1, packF4u(-1, 0, 0), packF4u( 0, -1, 0), 0, 0 },
{-1, 1, 1, packF4u(-1, 0, 0), packF4u( 0, -1, 0), 1, 0 },
{ 1, -1, 1, packF4u(-1, 0, 0), packF4u( 0, -1, 0), 0, 1 },
{-1, -1, -1, packF4u( 1, 0, 0), packF4u( 0, -1, 0), 0, 1 }, // Front
{ 1, 1, -1, packF4u( 1, 0, 0), packF4u( 0, -1, 0), 1, 0 },
{-1, 1, -1, packF4u( 1, 0, 0), packF4u( 0, -1, 0), 0, 0 },
{ 1, -1, -1, packF4u( 1, 0, 0), packF4u( 0, -1, 0), 1, 1 },
{ 1, -1, -1, packF4u( 0, 0, 1), packF4u( 0, -1, 0), 0, 1 }, // Right
{ 1, 1, 1, packF4u( 0, 0, 1), packF4u( 0, -1, 0), 1, 0 },
{ 1, -1, 1, packF4u( 0, 0, 1), packF4u( 0, -1, 0), 1, 1 },
{ 1, 1, -1, packF4u( 0, 0, 1), packF4u( 0, -1, 0), 0, 0 },
{-1, -1, -1, packF4u( 0, 0, -1), packF4u( 0, -1, 0), 1, 1 }, // Left
{-1, 1, 1, packF4u( 0, 0, -1), packF4u( 0, -1, 0), 0, 0 },
{-1, -1, 1, packF4u( 0, 0, -1), packF4u( 0, -1, 0), 0, 1 },
{-1, 1, -1, packF4u( 0, 0, -1), packF4u( 0, -1, 0), 1, 0 },
{-1, 1, -1, packF4u( 1, 0, 0), packF4u( 0, 0, -1), 0, 1 }, // Top
{ 1, 1, 1, packF4u( 1, 0, 0), packF4u( 0, 0, -1), 1, 0 },
{-1, 1, 1, packF4u( 1, 0, 0), packF4u( 0, 0, -1), 0, 0 },
{ 1, 1, -1, packF4u( 1, 0, 0), packF4u( 0, 0, -1), 1, 1 },
{-1, -1, -1, packF4u( 1, 0, 0), packF4u( 0, 0, 1), 0, 0 }, // Bottom
{ 1, -1, 1, packF4u( 1, 0, 0), packF4u( 0, 0, 1), 1, 1 },
{-1, -1, 1, packF4u( 1, 0, 0), packF4u( 0, 0, 1), 0, 1 },
{ 1, -1, -1, packF4u( 1, 0, 0), packF4u( 0, 0, 1), 1, 0 },
};
static const uint16_t s_cubeIndices[36] =
{
0 , 1 , 2 ,
0 , 3 , 1 ,
4 , 6 , 5 ,
4 , 5 , 7 ,
8 , 9 , 10,
8 , 11, 9 ,
12, 14, 13,
12, 13, 15,
16, 18, 17,
16, 17, 19,
20, 21, 22,
20, 23, 21,
};
class ExamplePom : public entry::AppI
{
void init(int _argc, char** _argv) BX_OVERRIDE
{
Args args(_argc, _argv);
m_width = 1280;
m_height = 720;
m_debug = BGFX_DEBUG_TEXT;
m_reset = BGFX_RESET_VSYNC;
bgfx::init(args.m_type, args.m_pciId);
bgfx::reset(m_width, m_height, m_reset);
// Enable debug text.
bgfx::setDebug(m_debug);
// Set view 0 clear state.
bgfx::setViewClear(0
, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
, 0x303030ff
, 1.0f
, 0
);
// Create vertex stream declaration.
PosTangentBitangentTexcoordVertex::init();
// Create static vertex buffer.
m_vbh = bgfx::createVertexBuffer(bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) ),
PosTangentBitangentTexcoordVertex::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_texDepth = bgfx::createUniform("s_texDepth", bgfx::UniformType::Int1);
u_light_pos = bgfx::createUniform("u_light_pos", bgfx::UniformType::Vec4);
u_norm_mtx = bgfx::createUniform("u_norm_mtx", bgfx::UniformType::Mat4);
u_shading_type = bgfx::createUniform("u_shading_type", bgfx::UniformType::Int1);
u_show_diffuse_texture = bgfx::createUniform("u_show_diffuse_texture", bgfx::UniformType::Int1);
u_parallax_scale = bgfx::createUniform("u_parallax_scale", bgfx::UniformType::Int1);
u_num_steps = bgfx::createUniform("u_num_steps", bgfx::UniformType::Int1);
// Create program from shaders.
m_program = loadProgram("vs_pom", "fs_pom");
// Load diffuse texture.
m_textureColor = loadTexture("textures/parallax-d.png");
// Load normal texture.
m_textureNormal = loadTexture("textures/parallax-n.png");
// Load depth texture.
m_textureDepth = loadTexture("textures/parallax-h.png");
imguiCreate();
m_timeOffset = bx::getHPCounter();
m_shading_type = 4;
m_show_diffuse_texture = true;
m_parallax_scale = 50;
m_num_steps = 4;
}
virtual int shutdown() BX_OVERRIDE
{
// Cleanup.
bgfx::destroyIndexBuffer(m_ibh);
bgfx::destroyVertexBuffer(m_vbh);
bgfx::destroyProgram(m_program);
bgfx::destroyTexture(m_textureColor);
bgfx::destroyTexture(m_textureNormal);
bgfx::destroyTexture(m_textureDepth);
bgfx::destroyUniform(s_texColor);
bgfx::destroyUniform(s_texNormal);
bgfx::destroyUniform(s_texDepth);
bgfx::destroyUniform(u_light_pos);
bgfx::destroyUniform(u_norm_mtx);
bgfx::destroyUniform(u_shading_type);
bgfx::destroyUniform(u_show_diffuse_texture);
bgfx::destroyUniform(u_parallax_scale);
bgfx::destroyUniform(u_num_steps);
imguiDestroy();
// Shutdown bgfx.
bgfx::shutdown();
return 0;
}
bool update() BX_OVERRIDE
{
if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
{
// Set view 0 default viewport.
bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(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);
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;
float time = (float)( (now-m_timeOffset)/freq);
// Use debug font to print information about this example.
bgfx::dbgTextClear();
bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/33-pom");
bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Parallax mapping.");
bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);
float at[3] = { 0.0f, 0.0f, 1.0f };
float eye[3] = { 0.0f, 0.0f, 0.0f };
// Set view and projection matrix for view 0.
const bgfx::HMD* hmd = bgfx::getHMD();
if (NULL != hmd && 0 != (hmd->flags & BGFX_HMD_RENDERING) )
{
float view[16];
bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye);
bgfx::setViewTransform(0, view, hmd->eye[0].projection, BGFX_VIEW_STEREO, hmd->eye[1].projection);
// Set view 0 default viewport.
//
// Use HMD's width/height since HMD's internal frame buffer size
// might be much larger than window size.
bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height);
}
else
{
float view[16];
bx::mtxLookAt(view, eye, at);
float proj[16];
bx::mtxProj(proj, 60.0f, float(m_width) / float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
bgfx::setViewTransform(0, view, proj);
// Set view 0 default viewport.
bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
}
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)
);
ImGui::Begin("Properties");
ImGui::RadioButton("No bump mapping", &m_shading_type, 0);
ImGui::RadioButton("Normal mapping", &m_shading_type, 1);
ImGui::RadioButton("Parallax mapping", &m_shading_type, 2);
ImGui::RadioButton("Steep parallax mapping", &m_shading_type, 3);
ImGui::RadioButton("Parallax occlusion mapping", &m_shading_type, 4);
bgfx::setUniform(u_shading_type, &m_shading_type);
ImGui::Separator();
ImGui::Checkbox("Show diffuse texture", &m_show_diffuse_texture);
bgfx::setUniform(u_show_diffuse_texture, &m_show_diffuse_texture);
if (m_shading_type > 1)
{
ImGui::Separator();
float multiplier = 1000.0f;
float x = (float)m_parallax_scale / multiplier;
ImGui::SliderFloat("Parallax scale", &x, 0.0f, 0.1f);
m_parallax_scale = (int32_t)(x * multiplier);
bgfx::setUniform(u_parallax_scale, &m_parallax_scale);
}
if (m_shading_type > 2)
{
ImGui::Separator();
ImGui::SliderInt("Number of steps", &m_num_steps, 1, 32);
bgfx::setUniform(u_num_steps, &m_num_steps);
}
ImGui::End();
imguiEndFrame();
float light_pos[4] = { 1, 2, 0, 0 };
bgfx::setUniform(u_light_pos, light_pos);
float a[16];
float b[16];
float c[16];
float d[16];
float mtx[16];
bx::mtxRotateY(a, time * 0.4f);
bx::mtxRotateX(b, 0.4f);
bx::mtxMul(c, a, b);
bx::mtxTranslate(d, 0, 0, 4);
bx::mtxMul(mtx, c, d);
// Set transform for draw call.
bgfx::setTransform(mtx);
// Set normal matrix uniform
float inv[16];
float transpose[16];
bx::mtxInverse(inv, mtx);
bx::mtxTranspose(transpose, inv);
bgfx::setUniform(u_norm_mtx, transpose);
// 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);
bgfx::setTexture(2, s_texDepth, m_textureDepth);
// 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(0, m_program);
// Advance to next frame. Rendering thread will be kicked to
// process submitted rendering primitives.
bgfx::frame();
return true;
}
return false;
}
bgfx::VertexBufferHandle m_vbh;
bgfx::IndexBufferHandle m_ibh;
bgfx::UniformHandle s_texColor;
bgfx::UniformHandle s_texNormal;
bgfx::UniformHandle s_texDepth;
bgfx::UniformHandle u_light_pos;
bgfx::UniformHandle u_norm_mtx;
bgfx::UniformHandle u_shading_type;
bgfx::UniformHandle u_show_diffuse_texture;
bgfx::UniformHandle u_parallax_scale;
bgfx::UniformHandle u_num_steps;
bgfx::ProgramHandle m_program;
bgfx::TextureHandle m_textureColor;
bgfx::TextureHandle m_textureNormal;
bgfx::TextureHandle m_textureDepth;
bool m_instancingSupported;
entry::MouseState m_mouseState;
uint32_t m_width;
uint32_t m_height;
uint32_t m_debug;
uint32_t m_reset;
int64_t m_timeOffset;
int32_t m_shading_type;
bool m_show_diffuse_texture;
int32_t m_parallax_scale;
int32_t m_num_steps;
};
ENTRY_IMPLEMENT_MAIN(ExamplePom);

View File

@ -0,0 +1,13 @@
vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
vec3 v_ts_light_pos : TEXCOORD1 = vec3(0.0, 0.0, 0.0);
vec3 v_ts_view_pos : TEXCOORD2 = vec3(0.0, 0.0, 0.0);
vec3 v_ts_frag_pos : TEXCOORD3 = vec3(0.0, 0.0, 0.0);
vec3 a_position : POSITION;
vec3 a_tangent : TANGENT;
vec3 a_bitangent : BITANGENT;
vec2 a_texcoord0 : TEXCOORD0;
vec4 i_data0 : TEXCOORD7;
vec4 i_data1 : TEXCOORD6;
vec4 i_data2 : TEXCOORD5;
vec4 i_data3 : TEXCOORD4;

44
examples/33-pom/vs_pom.sc Normal file
View File

@ -0,0 +1,44 @@
$input a_position, a_tangent, a_bitangent, a_texcoord0
$output v_texcoord0, v_ts_light_pos, v_ts_view_pos, v_ts_frag_pos
uniform mat4 u_norm_mtx;
uniform vec4 u_light_pos;
#include "../common/common.sh"
mat3 transpose(mat3 inMatrix)
{
vec3 i0 = inMatrix[0];
vec3 i1 = inMatrix[1];
vec3 i2 = inMatrix[2];
mat3 outMatrix = mat3(
vec3(i0.x, i1.x, i2.x),
vec3(i0.y, i1.y, i2.y),
vec3(i0.z, i1.z, i2.z)
);
return outMatrix;
}
void main()
{
vec3 wpos = mul(u_model[0], vec4(a_position, 1.0) ).xyz;
gl_Position = mul(u_viewProj, vec4(wpos, 1.0) );
vec3 tangent = a_tangent * 2.0 - 1.0;
vec3 bitangent = a_bitangent * 2.0 - 1.0;
vec3 normal = cross(tangent, bitangent);
vec3 t = normalize(mat3(u_norm_mtx) * tangent);
vec3 b = normalize(mat3(u_norm_mtx) * bitangent);
vec3 n = normalize(mat3(u_norm_mtx) * normal);
mat3 tbn = transpose(mat3(t, b, n));
v_ts_light_pos = tbn * u_light_pos.xyz;
// Our camera is always at the origin
v_ts_view_pos = tbn * vec3(0, 0, 0);
v_ts_frag_pos = tbn * wpos;
v_texcoord0 = a_texcoord0;
}

View File

@ -33,6 +33,7 @@ rebuild:
@make -s --no-print-directory rebuild -C 28-wireframe
@make -s --no-print-directory rebuild -C 30-picking
@make -s --no-print-directory rebuild -C 31-rsm
@make -s --no-print-directory rebuild -C 33-pom
@make -s --no-print-directory rebuild -C common/debugdraw
@make -s --no-print-directory rebuild -C common/font
@make -s --no-print-directory rebuild -C common/imgui

View File

@ -410,6 +410,7 @@ if _OPTIONS["with-examples"] then
exampleProject("30-picking")
exampleProject("31-rsm")
exampleProject("32-particles")
exampleProject("33-pom")
-- C99 source doesn't compile under WinRT settings
if not premake.vstudio.iswinrt() then