Skip to content

Commit

Permalink
rt: compute tangents for studio models
Browse files Browse the repository at this point in the history
Enables applying normal maps to studio models.

Fixes #220, fixes #241
  • Loading branch information
w23 committed Mar 1, 2023
1 parent bd2bda9 commit a20fdec
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 9 deletions.
10 changes: 7 additions & 3 deletions ref/vk/vk_math.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,17 +267,21 @@ void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z )
Matrix4x4_Concat( out, base, temp );
}

void computeTangent(vec3_t out_tangent, vec3_t v0, vec3_t v1, vec3_t v2, vec2_t uv0, vec2_t uv1, vec2_t uv2) {
void computeTangent(vec3_t out_tangent, const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t uv0, const vec2_t uv1, const vec2_t uv2) {
vec3_t e1, e2;
vec2_t duv1, duv2;
float f;

VectorSubtract(v1, v0, e1);
VectorSubtract(v2, v0, e2);
Vector2Subtract(uv1, uv0, duv1);
Vector2Subtract(uv2, uv0, duv2);

f = 1.f / (duv1[0] * duv2[1] - duv1[1] * duv2[0]);
const float div = duv1[0] * duv2[1] - duv1[1] * duv2[0];
if (fabs(div) < 1e-5f) {
VectorClear(out_tangent);
return;
}
const float f = 1.f / div;
out_tangent[0] = f * (duv2[1] * e1[0] - duv1[1] * e2[0]);
out_tangent[1] = f * (duv2[1] * e1[1] - duv1[1] * e2[1]);
out_tangent[2] = f * (duv2[1] * e1[2] - duv1[1] * e2[2]);
Expand Down
2 changes: 1 addition & 1 deletion ref/vk/vk_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ void Matrix4x4_CreateProjection(matrix4x4 out, float xMax, float xMin, float yMa
void Matrix4x4_CreateOrtho(matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar);
void Matrix4x4_CreateModelview( matrix4x4 out );

void computeTangent(vec3_t out_tangent, vec3_t v0, vec3_t v1, vec3_t v2, vec2_t uv0, vec2_t uv1, vec2_t uv2);
void computeTangent(vec3_t out_tangent, const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t uv0, const vec2_t uv1, const vec2_t uv2);
45 changes: 40 additions & 5 deletions ref/vk/vk_studio.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "vk_geometry.h"
#include "vk_previous_frame.h"
#include "vk_renderstate.h"
#include "vk_math.h"
#include "camera.h"

#include "xash3d_mathlib.h"
Expand Down Expand Up @@ -74,6 +75,7 @@ typedef struct
sortedmesh_t meshes[MAXSTUDIOMESHES]; // sorted meshes
vec3_t verts[MAXSTUDIOVERTS];
vec3_t norms[MAXSTUDIOVERTS];
vec3_t tangents[MAXSTUDIOVERTS];

vec3_t prev_verts[MAXSTUDIOVERTS]; // last frame state for motion vectors

Expand Down Expand Up @@ -1127,14 +1129,16 @@ g_studio.verts must be computed
void R_StudioGenerateNormals( void )
{
int v0, v1, v2;
vec3_t e0, e1, norm;
vec3_t e0, e1, norm, tangent;
mstudiomesh_t *pmesh;
int i, j;

ASSERT( m_pSubModel != NULL );

for( i = 0; i < m_pSubModel->numverts; i++ )
for( i = 0; i < m_pSubModel->numverts; i++ ) {
VectorClear( g_studio.norms[i] );
VectorClear( g_studio.tangents[i] );
}

for( j = 0; j < m_pSubModel->nummesh; j++ )
{
Expand All @@ -1151,11 +1155,16 @@ void R_StudioGenerateNormals( void )

if( i > 2 )
{
// TODO should we get uv (for tangents) for STUDIO_NF_CHROME differently?
const vec2_t uv0 = {ptricmds[2], ptricmds[3]};
v0 = ptricmds[0]; ptricmds += 4;

vec2_t uv1 = {ptricmds[2], ptricmds[3]};
v1 = ptricmds[0]; ptricmds += 4;

for( i -= 2; i > 0; i--, ptricmds += 4 )
{
const vec2_t uv2 = {ptricmds[2], ptricmds[3]};
v2 = ptricmds[0];

VectorSubtract( g_studio.verts[v1], g_studio.verts[v0], e0 );
Expand All @@ -1166,7 +1175,14 @@ void R_StudioGenerateNormals( void )
VectorAdd( g_studio.norms[v1], norm, g_studio.norms[v1] );
VectorAdd( g_studio.norms[v2], norm, g_studio.norms[v2] );

computeTangent(tangent, g_studio.verts[v0], g_studio.verts[v1], g_studio.verts[v2], uv0, uv1, uv2);

VectorAdd( g_studio.tangents[v0], tangent, g_studio.tangents[v0] );
VectorAdd( g_studio.tangents[v1], tangent, g_studio.tangents[v1] );
VectorAdd( g_studio.tangents[v2], tangent, g_studio.tangents[v2] );

v1 = v2;
Vector2Copy(uv2, uv1);
}
}
else
Expand All @@ -1180,11 +1196,16 @@ void R_StudioGenerateNormals( void )
{
qboolean odd = false;

// TODO should we get uv (for tangents) for STUDIO_NF_CHROME differently?
vec2_t uv0 = {ptricmds[2], ptricmds[3]};
v0 = ptricmds[0]; ptricmds += 4;

vec2_t uv1 = {ptricmds[2], ptricmds[3]};
v1 = ptricmds[0]; ptricmds += 4;

for( i -= 2; i > 0; i--, ptricmds += 4 )
{
const vec2_t uv2 = {ptricmds[2], ptricmds[3]};
v2 = ptricmds[0];

VectorSubtract( g_studio.verts[v1], g_studio.verts[v0], e0 );
Expand All @@ -1195,8 +1216,19 @@ void R_StudioGenerateNormals( void )
VectorAdd( g_studio.norms[v1], norm, g_studio.norms[v1] );
VectorAdd( g_studio.norms[v2], norm, g_studio.norms[v2] );

if( odd ) v1 = v2;
else v0 = v2;
computeTangent(tangent, g_studio.verts[v0], g_studio.verts[v1], g_studio.verts[v2], uv0, uv1, uv2);

VectorAdd( g_studio.tangents[v0], tangent, g_studio.tangents[v0] );
VectorAdd( g_studio.tangents[v1], tangent, g_studio.tangents[v1] );
VectorAdd( g_studio.tangents[v2], tangent, g_studio.tangents[v2] );

if( odd ) {
v1 = v2;
Vector2Copy(uv2, uv1);
} else {
v0 = v2;
Vector2Copy(uv2, uv0);
}

odd = !odd;
}
Expand All @@ -1209,8 +1241,10 @@ void R_StudioGenerateNormals( void )
}
}

for( i = 0; i < m_pSubModel->numverts; i++ )
for( i = 0; i < m_pSubModel->numverts; i++ ) {
VectorNormalize( g_studio.norms[i] );
VectorNormalize( g_studio.tangents[i] );
}
}

/*
Expand Down Expand Up @@ -1919,6 +1953,7 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float
VectorCopy(g_studio.verts[ptricmds[0]], dst_vtx->pos);
VectorCopy(g_studio.prev_verts[ptricmds[0]], dst_vtx->prev_pos);
VectorCopy(g_studio.norms[ptricmds[0]], dst_vtx->normal);
VectorCopy(g_studio.tangents[ptricmds[0]], dst_vtx->tangent);
dst_vtx->lm_tc[0] = dst_vtx->lm_tc[1] = 0.f;

if (FBitSet( g_nFaceFlags, STUDIO_NF_CHROME ))
Expand Down

0 comments on commit a20fdec

Please sign in to comment.