OpenGL2: Add GPU vertex skinning for IQM models

Using GPU vertex skinning is significantly faster than CPU vertex
skinning. Especially since OpenGL2 has to run R_VaoPackNormal() and
R_VaoPackTangent() each vertex each frame which causes CPU vertex
skinning to be significantly slower than OpenGL1 renderer.
This commit is contained in:
Zack Middleton 2018-07-27 17:40:25 -05:00
parent cccd283be8
commit 11337c9fa2
10 changed files with 533 additions and 34 deletions

View File

@ -6,6 +6,9 @@ attribute vec4 attr_TexCoord0;
#if defined(USE_VERTEX_ANIMATION)
attribute vec3 attr_Position2;
attribute vec3 attr_Normal2;
#elif defined(USE_BONE_ANIMATION)
attribute vec4 attr_BoneIndexes;
attribute vec4 attr_BoneWeights;
#endif
uniform vec4 u_FogDistance;
@ -22,6 +25,8 @@ uniform mat4 u_ModelViewProjectionMatrix;
#if defined(USE_VERTEX_ANIMATION)
uniform float u_VertexLerp;
#elif defined(USE_BONE_ANIMATION)
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
#endif
uniform vec4 u_Color;
@ -102,6 +107,15 @@ void main()
#if defined(USE_VERTEX_ANIMATION)
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
#elif defined(USE_BONE_ANIMATION)
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
vec3 normal = normalize(nrmMat * attr_Normal);
#else
vec3 position = attr_Position;
vec3 normal = attr_Normal;

View File

@ -4,6 +4,9 @@ attribute vec3 attr_Normal;
#if defined(USE_VERTEX_ANIMATION)
attribute vec3 attr_Position2;
attribute vec3 attr_Normal2;
#elif defined(USE_BONE_ANIMATION)
attribute vec4 attr_BoneIndexes;
attribute vec4 attr_BoneWeights;
#endif
attribute vec4 attr_Color;
@ -54,6 +57,8 @@ uniform float u_PortalRange;
#if defined(USE_VERTEX_ANIMATION)
uniform float u_VertexLerp;
#elif defined(USE_BONE_ANIMATION)
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
#endif
varying vec2 var_DiffuseTex;
@ -204,6 +209,15 @@ void main()
#if defined(USE_VERTEX_ANIMATION)
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
#elif defined(USE_BONE_ANIMATION)
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
vec3 normal = normalize(nrmMat * attr_Normal);
#else
vec3 position = attr_Position;
vec3 normal = attr_Normal;

View File

@ -12,6 +12,9 @@ attribute vec4 attr_Tangent;
attribute vec3 attr_Position2;
attribute vec3 attr_Normal2;
attribute vec4 attr_Tangent2;
#elif defined(USE_BONE_ANIMATION)
attribute vec4 attr_BoneIndexes;
attribute vec4 attr_BoneWeights;
#endif
#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR)
@ -48,6 +51,8 @@ uniform mat4 u_ModelMatrix;
#if defined(USE_VERTEX_ANIMATION)
uniform float u_VertexLerp;
#elif defined(USE_BONE_ANIMATION)
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
#endif
#if defined(USE_LIGHT_VECTOR)
@ -151,6 +156,18 @@ void main()
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp);
#endif
#elif defined(USE_BONE_ANIMATION)
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
vec3 normal = normalize(nrmMat * attr_Normal);
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
vec3 tangent = normalize(nrmMat * attr_Tangent.xyz);
#endif
#else
vec3 position = attr_Position;
vec3 normal = attr_Normal;

View File

@ -2,10 +2,13 @@ attribute vec3 attr_Position;
attribute vec3 attr_Normal;
attribute vec4 attr_TexCoord0;
//#if defined(USE_VERTEX_ANIMATION)
#if defined(USE_VERTEX_ANIMATION)
attribute vec3 attr_Position2;
attribute vec3 attr_Normal2;
//#endif
#elif defined(USE_BONE_ANIMATION)
attribute vec4 attr_BoneIndexes;
attribute vec4 attr_BoneWeights;
#endif
//#if defined(USE_DEFORM_VERTEXES)
uniform int u_DeformGen;
@ -17,9 +20,11 @@ uniform mat4 u_ModelViewProjectionMatrix;
uniform mat4 u_ModelMatrix;
//#if defined(USE_VERTEX_ANIMATION)
#if defined(USE_VERTEX_ANIMATION)
uniform float u_VertexLerp;
//#endif
#elif defined(USE_BONE_ANIMATION)
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
#endif
varying vec3 var_Position;
@ -78,8 +83,22 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
void main()
{
#if defined(USE_VERTEX_ANIMATION)
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
#elif defined(USE_BONE_ANIMATION)
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
vec3 normal = normalize(nrmMat * attr_Normal);
#else
vec3 position = attr_Position;
vec3 normal = attr_Normal;
#endif
position = DeformPosition(position, normal, attr_TexCoord0.st);

View File

@ -148,6 +148,8 @@ static uniformInfo_t uniformsInfo[] =
{ "u_CubeMapInfo", GLSL_VEC4 },
{ "u_AlphaTest", GLSL_INT },
{ "u_BoneMatrix", GLSL_MAT16_BONEMATRIX },
};
typedef enum
@ -555,6 +557,12 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int
if(attribs & ATTR_LIGHTDIRECTION)
qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection");
if(attribs & ATTR_BONE_INDEXES)
qglBindAttribLocation(program->program, ATTR_INDEX_BONE_INDEXES, "attr_BoneIndexes");
if(attribs & ATTR_BONE_WEIGHTS)
qglBindAttribLocation(program->program, ATTR_INDEX_BONE_WEIGHTS, "attr_BoneWeights");
if(attribs & ATTR_POSITION2)
qglBindAttribLocation(program->program, ATTR_INDEX_POSITION2, "attr_Position2");
@ -660,6 +668,9 @@ void GLSL_InitUniforms(shaderProgram_t *program)
case GLSL_MAT16:
size += sizeof(vec_t) * 16;
break;
case GLSL_MAT16_BONEMATRIX:
size += sizeof(vec_t) * 16 * glRefConfig.glslMaxAnimatedBones;
break;
default:
break;
}
@ -843,6 +854,38 @@ void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t
qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix);
}
void GLSL_SetUniformMat4BoneMatrix(shaderProgram_t *program, int uniformNum, /*const*/ mat4_t *matrix, int numMatricies)
{
GLint *uniforms = program->uniforms;
vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
if (uniforms[uniformNum] == -1) {
return;
}
if (uniformsInfo[uniformNum].type != GLSL_MAT16_BONEMATRIX)
{
ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: wrong type for uniform %i in program %s\n", uniformNum, program->name);
return;
}
if (numMatricies > glRefConfig.glslMaxAnimatedBones)
{
ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: too many matricies (%d/%d) for uniform %i in program %s\n",
numMatricies, glRefConfig.glslMaxAnimatedBones, uniformNum, program->name);
return;
}
if (!memcmp(matrix, compare, numMatricies * sizeof(mat4_t)))
{
return;
}
Com_Memcpy(compare, matrix, numMatricies * sizeof(mat4_t));
qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], numMatricies, GL_FALSE, &matrix[0][0]);
}
void GLSL_DeleteGPUShader(shaderProgram_t *program)
{
if(program->program)
@ -886,6 +929,12 @@ void GLSL_InitGPUShaders(void)
for (i = 0; i < GENERICDEF_COUNT; i++)
{
if ((i & GENERICDEF_USE_VERTEX_ANIMATION) && (i & GENERICDEF_USE_BONE_ANIMATION))
continue;
if ((i & GENERICDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR;
extradefines[0] = '\0';
@ -903,6 +952,11 @@ void GLSL_InitGPUShaders(void)
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
}
else if (i & GENERICDEF_USE_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (i & GENERICDEF_USE_FOG)
Q_strcat(extradefines, 1024, "#define USE_FOG\n");
@ -943,14 +997,28 @@ void GLSL_InitGPUShaders(void)
for (i = 0; i < FOGDEF_COUNT; i++)
{
attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
if ((i & FOGDEF_USE_VERTEX_ANIMATION) && (i & FOGDEF_USE_BONE_ANIMATION))
continue;
if ((i & FOGDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
extradefines[0] = '\0';
if (i & FOGDEF_USE_DEFORM_VERTEXES)
Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
if (i & FOGDEF_USE_VERTEX_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
}
else if (i & FOGDEF_USE_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp))
{
@ -1001,6 +1069,12 @@ void GLSL_InitGPUShaders(void)
if ((i & LIGHTDEF_USE_SHADOWMAP) && (!lightType || !r_sunlightMode->integer))
continue;
if ((i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && (i & LIGHTDEF_ENTITY_BONE_ANIMATION))
continue;
if ((i & LIGHTDEF_ENTITY_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL;
extradefines[0] = '\0';
@ -1043,7 +1117,7 @@ void GLSL_InitGPUShaders(void)
attribs |= ATTR_TANGENT;
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer)
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && !(i & LIGHTDEF_ENTITY_BONE_ANIMATION) && r_parallaxMapping->integer)
{
Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n");
if (r_parallaxMapping->integer > 1)
@ -1093,7 +1167,7 @@ void GLSL_InitGPUShaders(void)
Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
}
if (i & LIGHTDEF_ENTITY)
if (i & LIGHTDEF_ENTITY_VERTEX_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
@ -1103,6 +1177,12 @@ void GLSL_InitGPUShaders(void)
attribs |= ATTR_TANGENT2;
}
}
else if (i & LIGHTDEF_ENTITY_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_MODELMATRIX\n");
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp))
{
@ -1124,19 +1204,40 @@ void GLSL_InitGPUShaders(void)
numLightShaders++;
}
attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
for (i = 0; i < SHADOWMAPDEF_COUNT; i++)
{
if ((i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) && (i & SHADOWMAPDEF_USE_BONE_ANIMATION))
continue;
if ((i & SHADOWMAPDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
extradefines[0] = '\0';
if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
if (i & SHADOWMAPDEF_USE_VERTEX_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
}
if (i & SHADOWMAPDEF_USE_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (!GLSL_InitGPUShader(&tr.shadowmapShader[i], "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
{
ri.Error(ERR_FATAL, "Could not load shadowfill shader!");
}
GLSL_InitUniforms(&tr.shadowmapShader);
GLSL_FinishGPUShader(&tr.shadowmapShader);
GLSL_InitUniforms(&tr.shadowmapShader[i]);
GLSL_FinishGPUShader(&tr.shadowmapShader[i]);
numEtcShaders++;
}
attribs = ATTR_POSITION | ATTR_NORMAL;
extradefines[0] = '\0';
@ -1363,7 +1464,9 @@ void GLSL_ShutdownGPUShaders(void)
for ( i = 0; i < LIGHTDEF_COUNT; i++)
GLSL_DeleteGPUShader(&tr.lightallShader[i]);
GLSL_DeleteGPUShader(&tr.shadowmapShader);
for ( i = 0; i < SHADOWMAPDEF_COUNT; i++)
GLSL_DeleteGPUShader(&tr.shadowmapShader[i]);
GLSL_DeleteGPUShader(&tr.pshadowShader);
GLSL_DeleteGPUShader(&tr.down4xShader);
GLSL_DeleteGPUShader(&tr.bokehShader);
@ -1439,6 +1542,10 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage)
{
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
}
else if (glState.boneAnimation)
{
shaderAttribs |= GENERICDEF_USE_BONE_ANIMATION;
}
if (pStage->bundle[0].numTexMods)
{

View File

@ -275,6 +275,13 @@ static void InitOpenGL( void )
qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &temp );
glConfig.numTextureUnits = temp;
// reserve 160 components for other uniforms
qglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS, &temp );
glRefConfig.glslMaxAnimatedBones = Com_Clamp( 0, IQM_MAX_JOINTS, ( temp - 160 ) / 16 );
if ( glRefConfig.glslMaxAnimatedBones < 12 ) {
glRefConfig.glslMaxAnimatedBones = 0;
}
}
// set default state

View File

@ -554,16 +554,18 @@ enum
GENERICDEF_USE_VERTEX_ANIMATION = 0x0004,
GENERICDEF_USE_FOG = 0x0008,
GENERICDEF_USE_RGBAGEN = 0x0010,
GENERICDEF_ALL = 0x001F,
GENERICDEF_COUNT = 0x0020,
GENERICDEF_USE_BONE_ANIMATION = 0x0020,
GENERICDEF_ALL = 0x003F,
GENERICDEF_COUNT = 0x0040,
};
enum
{
FOGDEF_USE_DEFORM_VERTEXES = 0x0001,
FOGDEF_USE_VERTEX_ANIMATION = 0x0002,
FOGDEF_ALL = 0x0003,
FOGDEF_COUNT = 0x0004,
FOGDEF_USE_BONE_ANIMATION = 0x0004,
FOGDEF_ALL = 0x0007,
FOGDEF_COUNT = 0x0008,
};
enum
@ -579,12 +581,21 @@ enum
LIGHTDEF_USE_LIGHT_VECTOR = 0x0002,
LIGHTDEF_USE_LIGHT_VERTEX = 0x0003,
LIGHTDEF_LIGHTTYPE_MASK = 0x0003,
LIGHTDEF_ENTITY = 0x0004,
LIGHTDEF_ENTITY_VERTEX_ANIMATION = 0x0004,
LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008,
LIGHTDEF_USE_PARALLAXMAP = 0x0010,
LIGHTDEF_USE_SHADOWMAP = 0x0020,
LIGHTDEF_ALL = 0x003F,
LIGHTDEF_COUNT = 0x0040
LIGHTDEF_ENTITY_BONE_ANIMATION = 0x0040,
LIGHTDEF_ALL = 0x007F,
LIGHTDEF_COUNT = 0x0080
};
enum
{
SHADOWMAPDEF_USE_VERTEX_ANIMATION = 0x0001,
SHADOWMAPDEF_USE_BONE_ANIMATION = 0x0002,
SHADOWMAPDEF_ALL = 0x0003,
SHADOWMAPDEF_COUNT = 0x0004
};
enum
@ -595,7 +606,8 @@ enum
GLSL_VEC2,
GLSL_VEC3,
GLSL_VEC4,
GLSL_MAT16
GLSL_MAT16,
GLSL_MAT16_BONEMATRIX
};
typedef enum
@ -686,6 +698,8 @@ typedef enum
UNIFORM_ALPHATEST,
UNIFORM_BONEMATRIX,
UNIFORM_COUNT
} uniform_t;
@ -849,6 +863,7 @@ typedef enum {
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_VAO_MDVMESH,
SF_VAO_IQM,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
@ -976,6 +991,9 @@ typedef struct {
float *jointMats;
float *poseMats;
float *bounds;
int numVaoSurfaces;
struct srfVaoIQModel_s *vaoSurfaces;
} iqmData_t;
// inter-quake-model surface
@ -989,6 +1007,21 @@ typedef struct srfIQModel_s {
int first_influence, num_influences;
} srfIQModel_t;
typedef struct srfVaoIQModel_s
{
surfaceType_t surfaceType;
iqmData_t *iqmData;
struct srfIQModel_s *iqmSurface;
// backEnd stats
int numIndexes;
int numVerts;
// static render data
vao_t *vao;
} srfVaoIQModel_t;
typedef struct srfVaoMdvMesh_s
{
surfaceType_t surfaceType;
@ -1332,6 +1365,8 @@ typedef struct {
uint32_t storedGlState;
float vertexAttribsInterpolation;
qboolean vertexAnimation;
int boneAnimation; // number of bones
mat4_t boneMatrix[IQM_MAX_JOINTS];
uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise
FBO_t *currentFBO;
vao_t *currentVao;
@ -1361,6 +1396,7 @@ typedef struct {
int glslMajorVersion;
int glslMinorVersion;
int glslMaxAnimatedBones;
memInfo_t memInfo;
@ -1541,7 +1577,7 @@ typedef struct {
shaderProgram_t fogShader[FOGDEF_COUNT];
shaderProgram_t dlightShader[DLIGHTDEF_COUNT];
shaderProgram_t lightallShader[LIGHTDEF_COUNT];
shaderProgram_t shadowmapShader;
shaderProgram_t shadowmapShader[SHADOWMAPDEF_COUNT];
shaderProgram_t pshadowShader;
shaderProgram_t down4xShader;
shaderProgram_t bokehShader;
@ -2190,6 +2226,7 @@ void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t
void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v);
void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v);
void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix);
void GLSL_SetUniformMat4BoneMatrix(shaderProgram_t *program, int uniformNum, /*const*/ mat4_t *matrix, int numMatricies);
shaderProgram_t *GLSL_GetGenericShaderProgram(int stage);
@ -2244,6 +2281,7 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface );
qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name );
void R_AddIQMSurfaces( trRefEntity_t *ent );
void RB_IQMSurfaceAnim( surfaceType_t *surface );
void RB_IQMSurfaceAnimVao( srfVaoIQModel_t *surface );
int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
int startFrame, int endFrame,
float frac, const char *tagName );

View File

@ -916,6 +916,170 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
}
}
// Create VAO surfaces
if ( iqmData->num_surfaces && iqmData->num_joints <= glRefConfig.glslMaxAnimatedBones )
{
srfVaoIQModel_t *vaoSurf;
srfIQModel_t *surf;
iqmData->numVaoSurfaces = iqmData->num_surfaces;
iqmData->vaoSurfaces = ri.Hunk_Alloc(sizeof(*iqmData->vaoSurfaces) * iqmData->numVaoSurfaces, h_low);
vaoSurf = iqmData->vaoSurfaces;
surf = iqmData->surfaces;
for (i = 0; i < iqmData->num_surfaces; i++, vaoSurf++, surf++)
{
uint32_t offset_xyz, offset_st, offset_normal, offset_tangent;
uint32_t offset_blendindexes, offset_blendweights, stride;
uint32_t dataSize, dataOfs;
uint8_t *data;
glIndex_t indexes[SHADER_MAX_INDEXES];
glIndex_t *ptr;
int *tri;
offset_xyz = 0;
offset_st = offset_xyz + sizeof(float) * 3;
offset_normal = offset_st + sizeof(float) * 2;
offset_tangent = offset_normal + sizeof(int16_t) * 4;
if ( iqmData->num_joints )
{
offset_blendindexes = offset_tangent + sizeof(int16_t) * 4;
offset_blendweights = offset_blendindexes + sizeof(byte) * 4;
if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
stride = offset_blendweights + sizeof(float) * 4;
} else {
stride = offset_blendweights + sizeof(byte) * 4;
}
}
else
{
stride = offset_tangent + sizeof(int16_t) * 4;
}
dataSize = surf->num_vertexes * stride;
data = ri.Malloc(dataSize);
dataOfs = 0;
for ( j = 0; j < surf->num_vertexes; j++ )
{
int vtx = surf->first_vertex + j;
// xyz
memcpy(data + dataOfs, &iqmData->positions[vtx*3], sizeof(float) * 3);
dataOfs += sizeof(float) * 3;
// st
memcpy(data + dataOfs, &iqmData->texcoords[vtx*2], sizeof(float) * 2);
dataOfs += sizeof(float) * 2;
// normal
R_VaoPackNormal((int16_t*)(data + dataOfs), &iqmData->normals[vtx*3]);
dataOfs += sizeof(int16_t) * 4;
// tangent
R_VaoPackTangent((int16_t*)(data + dataOfs), &iqmData->tangents[vtx*4]);
dataOfs += sizeof(int16_t) * 4;
if ( iqmData->num_joints )
{
// blendindexes
memcpy(data + dataOfs, &blendIndexes[vtx*4], sizeof(byte) * 4);
dataOfs += sizeof(byte) * 4;
// blendweights
if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
memcpy(data + dataOfs, &blendWeights.f[vtx*4], sizeof(float) * 4);
dataOfs += sizeof(float) * 4;
} else {
memcpy(data + dataOfs, &blendWeights.b[vtx*4], sizeof(byte) * 4);
dataOfs += sizeof(byte) * 4;
}
}
}
tri = iqmData->triangles + 3 * surf->first_triangle;
ptr = indexes;
for( j = 0; j < surf->num_triangles; j++ ) {
*ptr++ = (*tri++ - surf->first_vertex);
*ptr++ = (*tri++ - surf->first_vertex);
*ptr++ = (*tri++ - surf->first_vertex);
}
vaoSurf->surfaceType = SF_VAO_IQM;
vaoSurf->iqmData = iqmData;
vaoSurf->iqmSurface = surf;
vaoSurf->numIndexes = surf->num_triangles * 3;
vaoSurf->numVerts = surf->num_vertexes;
vaoSurf->vao = R_CreateVao(va("staticIQMMesh_VAO '%s'", surf->name), data, dataSize, (byte *)indexes, surf->num_triangles * 3 * sizeof(indexes[0]), VAO_USAGE_STATIC);
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].count = 4;
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].offset = offset_normal;
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride;
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride;
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].stride = stride;
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride;
if ( iqmData->num_joints )
{
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].enabled = 1;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].enabled = 1;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].count = 4;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].count = 4;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].type = GL_UNSIGNED_BYTE;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].normalized = GL_FALSE;
if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].type = GL_FLOAT;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].normalized = GL_FALSE;
} else {
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].type = GL_UNSIGNED_BYTE;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].normalized = GL_TRUE;
}
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].offset = offset_blendindexes;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].offset = offset_blendweights;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].stride = stride;
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].stride = stride;
}
Vao_SetVertexPointers(vaoSurf->vao);
ri.Free(data);
}
}
return qtrue;
}
@ -1017,6 +1181,7 @@ Add all surfaces of this model
void R_AddIQMSurfaces( trRefEntity_t *ent ) {
iqmData_t *data;
srfIQModel_t *surface;
void *drawSurf;
int i, j;
qboolean personalModel;
int cull;
@ -1097,6 +1262,12 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
shader = surface->shader;
}
if ( data->numVaoSurfaces ) {
drawSurf = &data->vaoSurfaces[i];
} else {
drawSurf = surface;
}
// we will add shadows even if the main object isn't visible in the view
// stencil shadows can't do personal models unless I polyhedron clip
@ -1105,7 +1276,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
&& fogNum == 0
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
&& shader->sort == SS_OPAQUE ) {
R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0, 0 );
R_AddDrawSurf( drawSurf, tr.shadowShader, 0, 0, 0, 0 );
}
// projection shadows work fine with personal models
@ -1113,11 +1284,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
&& fogNum == 0
&& (ent->e.renderfx & RF_SHADOW_PLANE )
&& shader->sort == SS_OPAQUE ) {
R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 );
R_AddDrawSurf( drawSurf, tr.projectionShadowShader, 0, 0, 0, 0 );
}
if( !personalModel ) {
R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex );
R_AddDrawSurf( drawSurf, shader, fogNum, 0, 0, cubemapIndex );
}
surface++;
@ -1418,6 +1589,73 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
tess.numVertexes += surf->num_vertexes;
}
/*
=================
RB_IQMSurfaceAnimVao
=================
*/
void RB_IQMSurfaceAnimVao(srfVaoIQModel_t * surface)
{
iqmData_t *data = surface->iqmData;
if (ShaderRequiresCPUDeforms(tess.shader))
{
RB_IQMSurfaceAnim((surfaceType_t*)surface->iqmSurface);
return;
}
if(!surface->vao)
return;
//RB_CheckVao(surface->vao);
RB_EndSurface();
RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex);
R_BindVao(surface->vao);
tess.useInternalVao = qfalse;
tess.numIndexes = surface->numIndexes;
tess.numVertexes = surface->numVerts;
glState.boneAnimation = data->num_poses;
if ( glState.boneAnimation ) {
float jointMats[IQM_MAX_JOINTS * 12];
int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0;
int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0;
float backlerp = backEnd.currentEntity->e.backlerp;
int i;
// compute interpolated joint matrices
ComputePoseMats( surface->iqmData, frame, oldframe, backlerp, jointMats );
// convert row-major order 3x4 matrix to column-major order 4x4 matrix
for ( i = 0; i < data->num_poses; i++ ) {
glState.boneMatrix[i][0] = jointMats[i*12+0];
glState.boneMatrix[i][1] = jointMats[i*12+4];
glState.boneMatrix[i][2] = jointMats[i*12+8];
glState.boneMatrix[i][3] = 0.0f;
glState.boneMatrix[i][4] = jointMats[i*12+1];
glState.boneMatrix[i][5] = jointMats[i*12+5];
glState.boneMatrix[i][6] = jointMats[i*12+9];
glState.boneMatrix[i][7] = 0.0f;
glState.boneMatrix[i][8] = jointMats[i*12+2];
glState.boneMatrix[i][9] = jointMats[i*12+6];
glState.boneMatrix[i][10] = jointMats[i*12+10];
glState.boneMatrix[i][11] = 0.0f;
glState.boneMatrix[i][12] = jointMats[i*12+3];
glState.boneMatrix[i][13] = jointMats[i*12+7];
glState.boneMatrix[i][14] = jointMats[i*12+11];
glState.boneMatrix[i][15] = 1.0f;
}
}
RB_EndSurface();
glState.boneAnimation = 0;
}
int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
int startFrame, int endFrame,
float frac, const char *tagName ) {

View File

@ -908,6 +908,8 @@ static void RB_FogPass( void ) {
if (glState.vertexAnimation)
index |= FOGDEF_USE_VERTEX_ANIMATION;
else if (glState.boneAnimation)
index |= FOGDEF_USE_BONE_ANIMATION;
sp = &tr.fogShader[index];
}
@ -922,6 +924,11 @@ static void RB_FogPass( void ) {
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
if (glState.boneAnimation)
{
GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation);
}
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
@ -1005,7 +1012,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
{
index |= LIGHTDEF_ENTITY;
if (glState.boneAnimation)
{
index |= LIGHTDEF_ENTITY_BONE_ANIMATION;
}
else
{
index |= LIGHTDEF_ENTITY_VERTEX_ANIMATION;
}
}
if (pStage->stateBits & GLS_ATEST_BITS)
@ -1028,6 +1042,10 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
}
else if (glState.boneAnimation)
{
shaderAttribs |= GENERICDEF_USE_BONE_ANIMATION;
}
if (pStage->stateBits & GLS_ATEST_BITS)
{
@ -1043,7 +1061,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
{
index |= LIGHTDEF_ENTITY;
if (glState.boneAnimation)
{
index |= LIGHTDEF_ENTITY_BONE_ANIMATION;
}
else
{
index |= LIGHTDEF_ENTITY_VERTEX_ANIMATION;
}
}
if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK))
@ -1075,6 +1100,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
if (glState.boneAnimation)
{
GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation);
}
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
@ -1368,7 +1398,16 @@ static void RB_RenderShadowmap( shaderCommands_t *input )
ComputeDeformValues(&deformGen, deformParams);
{
shaderProgram_t *sp = &tr.shadowmapShader;
shaderProgram_t *sp = &tr.shadowmapShader[0];
if (glState.vertexAnimation)
{
sp = &tr.shadowmapShader[SHADOWMAPDEF_USE_VERTEX_ANIMATION];
}
else if (glState.boneAnimation)
{
sp = &tr.shadowmapShader[SHADOWMAPDEF_USE_BONE_ANIMATION];
}
vec4_t vector;
@ -1380,6 +1419,11 @@ static void RB_RenderShadowmap( shaderCommands_t *input )
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
if (glState.boneAnimation)
{
GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation);
}
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{

View File

@ -1313,4 +1313,5 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
(void(*)(void*))RB_SurfaceFlare, // SF_FLARE,
(void(*)(void*))RB_SurfaceEntity, // SF_ENTITY
(void(*)(void*))RB_SurfaceVaoMdvMesh, // SF_VAO_MDVMESH
(void(*)(void*))RB_IQMSurfaceAnimVao, // SF_VAO_IQM
};