Use a trick to make skinned mesh shader branchless

This commit is contained in:
Benau 2017-10-22 13:03:45 +08:00
parent 7252a38da1
commit fc2e05c0a6
7 changed files with 57 additions and 110 deletions

View File

@ -63,34 +63,17 @@ void main(void)
vec4 skinned_normal = vec4(0.);
vec4 skinned_tangent = vec4(0.);
vec4 skinned_bitangent = vec4(0.);
if (Weight[0] < 0.01)
for (int i = 0; i < 4; i++)
{
skinned_position = idle_position;
skinned_normal = idle_normal;
skinned_tangent = idle_tangent;
skinned_bitangent = idle_bitangent;
}
else
{
for (int i = 0; i < 4; i++)
{
// Logically we should break if the weight is (almost) zero
// given the fact that it's sorted from high to low,
// but GT240 will cause glitches
//if (Weight[i] < 0.01)
//{
// break;
//}
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 1),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 2),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 3));
skinned_position += Weight[i] * joint_matrix * idle_position;
skinned_normal += Weight[i] * joint_matrix * idle_normal;
skinned_tangent += Weight[i] * joint_matrix * idle_tangent;
skinned_bitangent += Weight[i] * joint_matrix * idle_bitangent;
}
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 1),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 2),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 3));
skinned_position += Weight[i] * joint_matrix * idle_position;
skinned_normal += Weight[i] * joint_matrix * idle_normal;
skinned_tangent += Weight[i] * joint_matrix * idle_tangent;
skinned_bitangent += Weight[i] * joint_matrix * idle_bitangent;
}
gl_Position = ProjectionViewMatrix * ModelMatrix * skinned_position;

View File

@ -45,28 +45,14 @@ void main(void)
mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale);
vec4 idle_position = vec4(Position, 1.);
vec4 skinned_position = vec4(0.);
if (Weight[0] < 0.01)
for (int i = 0; i < 4; i++)
{
skinned_position = idle_position;
}
else
{
for (int i = 0; i < 4; i++)
{
// Logically we should break if the weight is (almost) zero
// given the fact that it's sorted from high to low,
// but GT240 will cause glitches
//if (Weight[i] < 0.01)
//{
// break;
//}
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 1),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 2),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 3));
skinned_position += Weight[i] * joint_matrix * idle_position;
}
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 1),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 2),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 3));
skinned_position += Weight[i] * joint_matrix * idle_position;
}
#ifdef VSLayer

View File

@ -60,42 +60,26 @@ void main(void)
vec4 skinned_normal = vec4(0.);
vec4 skinned_tangent = vec4(0.);
vec4 skinned_bitangent = vec4(0.);
if (Weight[0] < 0.01)
for (int i = 0; i < 4; i++)
{
skinned_position = idle_position;
skinned_normal = idle_normal;
skinned_tangent = idle_tangent;
skinned_bitangent = idle_bitangent;
}
else
{
for (int i = 0; i < 4; i++)
{
// Logically we should break if the weight is (almost) zero
// given the fact that it's sorted from high to low,
// but GT240 will cause glitches
//if (Weight[i] < 0.01)
//{
// break;
//}
#ifdef GL_ES
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, ivec2(0, skinning_offset + Joint[i]), 0),
texelFetch(skinning_tex, ivec2(1, skinning_offset + Joint[i]), 0),
texelFetch(skinning_tex, ivec2(2, skinning_offset + Joint[i]), 0),
texelFetch(skinning_tex, ivec2(3, skinning_offset + Joint[i]), 0));
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, ivec2(0, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0),
texelFetch(skinning_tex, ivec2(1, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0),
texelFetch(skinning_tex, ivec2(2, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0),
texelFetch(skinning_tex, ivec2(3, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0));
#else
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 1),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 2),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 3));
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 1),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 2),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 3));
#endif
skinned_position += Weight[i] * joint_matrix * idle_position;
skinned_normal += Weight[i] * joint_matrix * idle_normal;
skinned_tangent += Weight[i] * joint_matrix * idle_tangent;
skinned_bitangent += Weight[i] * joint_matrix * idle_bitangent;
}
skinned_position += Weight[i] * joint_matrix * idle_position;
skinned_normal += Weight[i] * joint_matrix * idle_normal;
skinned_tangent += Weight[i] * joint_matrix * idle_tangent;
skinned_bitangent += Weight[i] * joint_matrix * idle_bitangent;
}
gl_Position = ProjectionViewMatrix * ModelMatrix * skinned_position;

View File

@ -30,36 +30,23 @@ void main(void)
{
vec4 idle_position = vec4(Position, 1.);
vec4 skinned_position = vec4(0.);
if (Weight[0] < 0.01)
for (int i = 0; i < 4; i++)
{
skinned_position = idle_position;
}
else
{
for (int i = 0; i < 4; i++)
{
// Logically we should break if the weight is (almost) zero
// given the fact that it's sorted from high to low,
// but GT240 will cause glitches
//if (Weight[i] < 0.01)
//{
// break;
//}
#ifdef GL_ES
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, ivec2(0, skinning_offset + Joint[i]), 0),
texelFetch(skinning_tex, ivec2(1, skinning_offset + Joint[i]), 0),
texelFetch(skinning_tex, ivec2(2, skinning_offset + Joint[i]), 0),
texelFetch(skinning_tex, ivec2(3, skinning_offset + Joint[i]), 0));
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, ivec2(0, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0),
texelFetch(skinning_tex, ivec2(1, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0),
texelFetch(skinning_tex, ivec2(2, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0),
texelFetch(skinning_tex, ivec2(3, clamp(Joint[i] + skinning_offset, 0, MAX_BONES)), 0));
#else
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 1),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 2),
texelFetch(skinning_tex, (Joint[i] + skinning_offset) * 4 + 3));
mat4 joint_matrix = mat4(
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 1),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 2),
texelFetch(skinning_tex, clamp(Joint[i] + skinning_offset, 0, MAX_BONES) * 4 + 3));
#endif
skinned_position += Weight[i] * joint_matrix * idle_position;
}
}
#ifdef VSLayer

View File

@ -1502,8 +1502,8 @@ void CSkinnedMesh::convertForSkinning()
for (u32 j = 0; j < 4; j++)
{
JointInfluence influence;
influence.joint_idx = 0;
influence.weight = 0.0f;
influence.joint_idx = -32768;
influence.weight = j == 0 ? 1.0f : 0.0f;
this_influence.push_back(influence);
}
float total_weight = 0.0f;

View File

@ -259,7 +259,7 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
(!culled_for_cams[0] || !culled_for_cams[1] || !culled_for_cams[2] ||
!culled_for_cams[3] || !culled_for_cams[4] || !culled_for_cams[5]))
{
skinning_offset = getSkinningOffset();
skinning_offset = getSkinningOffset() + 1/*reserved identity matrix*/;
if (skinning_offset + am->getTotalJoints() >
(int)stk_config->m_max_skinning_bones)
{

View File

@ -35,6 +35,8 @@ GLuint SharedGPUObjects::m_skinning_tex;
GLuint SharedGPUObjects::m_skinning_buf;
bool SharedGPUObjects::m_has_been_initialised = false;
#include "matrix4.h"
/** Initialises m_full_screen_quad_vbo.
*/
void SharedGPUObjects::initQuadVBO()
@ -159,6 +161,8 @@ void SharedGPUObjects::initLightingDataUBO()
void SharedGPUObjects::initSkinning()
{
glGenTextures(1, &m_skinning_tex);
// Reserve 1 identity matrix for non-weighted vertices
const irr::core::matrix4 m;
int max_size = 0;
#ifdef USE_GLES2
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
@ -180,6 +184,8 @@ void SharedGPUObjects::initSkinning()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16,
stk_config->m_max_skinning_bones, 0, GL_RGBA, GL_FLOAT, NULL);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 16, 1, GL_RGBA, GL_FLOAT,
m.pointer());
glBindTexture(GL_TEXTURE_2D, 0);
#else
@ -195,8 +201,9 @@ void SharedGPUObjects::initSkinning()
"max bones: %u", stk_config->m_max_skinning_bones);
glBindBuffer(GL_TEXTURE_BUFFER, m_skinning_buf);
glBufferData(GL_TEXTURE_BUFFER, stk_config->m_max_skinning_bones * 64, NULL,
GL_DYNAMIC_DRAW);
glBufferData(GL_TEXTURE_BUFFER, stk_config->m_max_skinning_bones * 64,
NULL, GL_DYNAMIC_DRAW);
glBufferSubData(GL_TEXTURE_BUFFER, 0, 16 * sizeof(float), m.pointer());
glBindTexture(GL_TEXTURE_BUFFER, m_skinning_tex);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_skinning_buf);
glBindTexture(GL_TEXTURE_BUFFER, 0);