From: havoc Date: Thu, 23 Sep 2004 01:44:33 +0000 (+0000) Subject: added a Mod_BuildNormals function to accelerate vertex lighting which doesn't need... X-Git-Tag: xonotic-v0.1.0preview~5571 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=1ffce651075275f57c7e04b443ea6f1fd748fd98 added a Mod_BuildNormals function to accelerate vertex lighting which doesn't need texture vectors moved vertex blending function from gl_models.c to model_alias.c and renamed accordingly model loader now compiles frame zero into raw arrays because most models are not animated, this speeds up non-animated models, and anything else idling on frame 0, this eliminates vertex processing in many cases git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@4535 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/gl_models.c b/gl_models.c index 14df524c..d3036acc 100644 --- a/gl_models.c +++ b/gl_models.c @@ -6,82 +6,6 @@ void GL_Models_Init(void) { } -void R_Model_Alias_GetMesh_Vertex3f(const entity_render_t *ent, const aliasmesh_t *mesh, float *out3f) -{ - if (mesh->num_vertexboneweights) - { - int i, k, blends; - aliasvertexboneweight_t *v; - float *out, *matrix, m[12], bonepose[256][12]; - // vertex weighted skeletal - // interpolate matrices and concatenate them to their parents - for (i = 0;i < ent->model->alias.aliasnum_bones;i++) - { - for (k = 0;k < 12;k++) - m[k] = 0; - for (blends = 0;blends < 4 && ent->frameblend[blends].lerp > 0;blends++) - { - matrix = ent->model->alias.aliasdata_poses + (ent->frameblend[blends].frame * ent->model->alias.aliasnum_bones + i) * 12; - for (k = 0;k < 12;k++) - m[k] += matrix[k] * ent->frameblend[blends].lerp; - } - if (ent->model->alias.aliasdata_bones[i].parent >= 0) - R_ConcatTransforms(bonepose[ent->model->alias.aliasdata_bones[i].parent], m, bonepose[i]); - else - for (k = 0;k < 12;k++) - bonepose[i][k] = m[k]; - } - // blend the vertex bone weights - memset(out3f, 0, mesh->num_vertices * sizeof(float[3])); - v = mesh->data_vertexboneweights; - for (i = 0;i < mesh->num_vertexboneweights;i++, v++) - { - out = out3f + v->vertexindex * 3; - matrix = bonepose[v->boneindex]; - // FIXME: this can very easily be optimized with SSE or 3DNow - out[0] += v->origin[0] * matrix[0] + v->origin[1] * matrix[1] + v->origin[2] * matrix[ 2] + v->origin[3] * matrix[ 3]; - out[1] += v->origin[0] * matrix[4] + v->origin[1] * matrix[5] + v->origin[2] * matrix[ 6] + v->origin[3] * matrix[ 7]; - out[2] += v->origin[0] * matrix[8] + v->origin[1] * matrix[9] + v->origin[2] * matrix[10] + v->origin[3] * matrix[11]; - } - } - else - { - int i, vertcount; - float lerp1, lerp2, lerp3, lerp4; - const float *vertsbase, *verts1, *verts2, *verts3, *verts4; - // vertex morph - vertsbase = mesh->data_morphvertex3f; - vertcount = mesh->num_vertices; - verts1 = vertsbase + ent->frameblend[0].frame * vertcount * 3; - lerp1 = ent->frameblend[0].lerp; - if (ent->frameblend[1].lerp) - { - verts2 = vertsbase + ent->frameblend[1].frame * vertcount * 3; - lerp2 = ent->frameblend[1].lerp; - if (ent->frameblend[2].lerp) - { - verts3 = vertsbase + ent->frameblend[2].frame * vertcount * 3; - lerp3 = ent->frameblend[2].lerp; - if (ent->frameblend[3].lerp) - { - verts4 = vertsbase + ent->frameblend[3].frame * vertcount * 3; - lerp4 = ent->frameblend[3].lerp; - for (i = 0;i < vertcount * 3;i++) - VectorMAMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, lerp4, verts4 + i, out3f + i); - } - else - for (i = 0;i < vertcount * 3;i++) - VectorMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, out3f + i); - } - else - for (i = 0;i < vertcount * 3;i++) - VectorMAM(lerp1, verts1 + i, lerp2, verts2 + i, out3f + i); - } - else - memcpy(out3f, verts1, vertcount * sizeof(float[3])); - } -} - aliaslayer_t r_aliasnoskinlayers[2] = {{ALIASLAYER_DIFFUSE, NULL, NULL}, {ALIASLAYER_FOG | ALIASLAYER_FORCEDRAW_IF_FIRSTPASS, NULL, NULL}}; aliasskin_t r_aliasnoskin = {0, 2, r_aliasnoskinlayers}; aliasskin_t *R_FetchAliasSkin(const entity_render_t *ent, const aliasmesh_t *mesh) @@ -111,6 +35,7 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2) { int c, fullbright, layernum, firstpass, generatenormals = true; float tint[3], fog, ifog, colorscale, ambientcolor4f[4], diffusecolor[3], diffusenormal[3]; + float *vertex3f, *normal3f; vec3_t diff; qbyte *bcolor; rmeshstate_t m; @@ -141,7 +66,18 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2) firstpass = true; skin = R_FetchAliasSkin(ent, mesh); - R_Model_Alias_GetMesh_Vertex3f(ent, mesh, varray_vertex3f); + + if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1) + { + vertex3f = mesh->data_basevertex3f; + normal3f = mesh->data_basenormal3f; + } + else + { + vertex3f = varray_vertex3f; + Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f); + normal3f = NULL; + } for (layernum = 0, layer = skin->data_layers;layernum < skin->num_layers;layernum++, layer++) { if (!(layer->flags & ALIASLAYER_FORCEDRAW_IF_FIRSTPASS) || !firstpass) @@ -183,7 +119,7 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2) m.texrgbscale[0] = 4; } } - m.pointer_vertex = varray_vertex3f; + m.pointer_vertex = vertex3f; c_alias_polys += mesh->num_triangles; if (layer->flags & ALIASLAYER_FOG) @@ -218,12 +154,12 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2) if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha, false)) { m.pointer_color = varray_color4f; - if (generatenormals) + if (normal3f == NULL) { - generatenormals = false; - Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_texcoord2f, mesh->data_element3i, NULL, NULL, varray_normal3f); + normal3f = varray_normal3f; + Mod_BuildNormals(mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, normal3f); } - R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, mesh->num_vertices, varray_vertex3f, varray_normal3f, varray_color4f); + R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, mesh->num_vertices, vertex3f, normal3f, varray_color4f); } else GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]); @@ -259,7 +195,7 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor int meshnum; aliasmesh_t *mesh; aliasskin_t *skin; - float projectdistance; + float projectdistance, *vertex3f; if (ent->effects & EF_ADDITIVE || ent->alpha < 1) return; projectdistance = lightradius + ent->model->radius;// - sqrt(DotProduct(relativelightorigin, relativelightorigin)); @@ -271,8 +207,14 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor skin = R_FetchAliasSkin(ent, mesh); if (skin->flags & ALIASSKIN_TRANSPARENT) continue; - R_Model_Alias_GetMesh_Vertex3f(ent, mesh, varray_vertex3f); - R_Shadow_VolumeFromSphere(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, projectdistance, lightradius); + if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1) + vertex3f = mesh->data_basevertex3f; + else + { + vertex3f = varray_vertex3f; + Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f); + } + R_Shadow_VolumeFromSphere(mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, projectdistance, lightradius); } } } @@ -281,6 +223,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v { int c, meshnum, layernum; float fog, ifog, lightcolor2[3]; + float *vertex3f, *svector3f, *tvector3f, *normal3f; vec3_t diff; qbyte *bcolor; aliasmesh_t *mesh; @@ -315,8 +258,22 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v skin = R_FetchAliasSkin(ent, mesh); if (skin->flags & ALIASSKIN_TRANSPARENT) continue; - R_Model_Alias_GetMesh_Vertex3f(ent, mesh, varray_vertex3f); - Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_texcoord2f, mesh->data_element3i, varray_svector3f, varray_tvector3f, varray_normal3f); + if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1) + { + vertex3f = mesh->data_basevertex3f; + svector3f = mesh->data_basesvector3f; + tvector3f = mesh->data_basetvector3f; + normal3f = mesh->data_basenormal3f; + } + else + { + vertex3f = varray_vertex3f; + svector3f = varray_svector3f; + tvector3f = varray_tvector3f; + normal3f = varray_normal3f; + Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f); + Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_texcoord2f, mesh->data_element3i, svector3f, tvector3f, normal3f); + } for (layernum = 0, layer = skin->data_layers;layernum < skin->num_layers;layernum++, layer++) { if (!(layer->flags & (ALIASLAYER_DIFFUSE | ALIASLAYER_SPECULAR)) @@ -329,7 +286,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v if (layer->flags & ALIASLAYER_SPECULAR) { c_alias_polys += mesh->num_triangles; - R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, varray_vertex3f, varray_svector3f, varray_tvector3f, varray_normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_SPECULAR); + R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_SPECULAR); } else if (layer->flags & ALIASLAYER_DIFFUSE) { @@ -358,7 +315,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v lightcolor2[2] *= bcolor[2] * (1.0f / 255.0f); } c_alias_polys += mesh->num_triangles; - R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, varray_vertex3f, varray_svector3f, varray_tvector3f, varray_normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_DIFFUSE); + R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_DIFFUSE); } } } diff --git a/model_alias.c b/model_alias.c index 7c0fd8af..fc92cc06 100644 --- a/model_alias.c +++ b/model_alias.c @@ -26,6 +26,93 @@ void Mod_AliasInit (void) { } +void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameblend, const aliasmesh_t *mesh, float *out3f) +{ + if (mesh->num_vertexboneweights) + { + int i, k, blends; + aliasvertexboneweight_t *v; + float *out, *matrix, m[12], bonepose[256][12]; + // vertex weighted skeletal + // interpolate matrices and concatenate them to their parents + for (i = 0;i < model->alias.aliasnum_bones;i++) + { + for (k = 0;k < 12;k++) + m[k] = 0; + for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++) + { + matrix = model->alias.aliasdata_poses + (frameblend[blends].frame * model->alias.aliasnum_bones + i) * 12; + for (k = 0;k < 12;k++) + m[k] += matrix[k] * frameblend[blends].lerp; + } + if (model->alias.aliasdata_bones[i].parent >= 0) + R_ConcatTransforms(bonepose[model->alias.aliasdata_bones[i].parent], m, bonepose[i]); + else + for (k = 0;k < 12;k++) + bonepose[i][k] = m[k]; + } + // blend the vertex bone weights + memset(out3f, 0, mesh->num_vertices * sizeof(float[3])); + v = mesh->data_vertexboneweights; + for (i = 0;i < mesh->num_vertexboneweights;i++, v++) + { + out = out3f + v->vertexindex * 3; + matrix = bonepose[v->boneindex]; + // FIXME: this can very easily be optimized with SSE or 3DNow + out[0] += v->origin[0] * matrix[0] + v->origin[1] * matrix[1] + v->origin[2] * matrix[ 2] + v->origin[3] * matrix[ 3]; + out[1] += v->origin[0] * matrix[4] + v->origin[1] * matrix[5] + v->origin[2] * matrix[ 6] + v->origin[3] * matrix[ 7]; + out[2] += v->origin[0] * matrix[8] + v->origin[1] * matrix[9] + v->origin[2] * matrix[10] + v->origin[3] * matrix[11]; + } + } + else + { + int i, vertcount; + float lerp1, lerp2, lerp3, lerp4; + const float *vertsbase, *verts1, *verts2, *verts3, *verts4; + // vertex morph + vertsbase = mesh->data_morphvertex3f; + vertcount = mesh->num_vertices; + verts1 = vertsbase + frameblend[0].frame * vertcount * 3; + lerp1 = frameblend[0].lerp; + if (frameblend[1].lerp) + { + verts2 = vertsbase + frameblend[1].frame * vertcount * 3; + lerp2 = frameblend[1].lerp; + if (frameblend[2].lerp) + { + verts3 = vertsbase + frameblend[2].frame * vertcount * 3; + lerp3 = frameblend[2].lerp; + if (frameblend[3].lerp) + { + verts4 = vertsbase + frameblend[3].frame * vertcount * 3; + lerp4 = frameblend[3].lerp; + for (i = 0;i < vertcount * 3;i++) + VectorMAMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, lerp4, verts4 + i, out3f + i); + } + else + for (i = 0;i < vertcount * 3;i++) + VectorMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, out3f + i); + } + else + for (i = 0;i < vertcount * 3;i++) + VectorMAM(lerp1, verts1 + i, lerp2, verts2 + i, out3f + i); + } + else + memcpy(out3f, verts1, vertcount * sizeof(float[3])); + } +} + +static void Mod_Alias_Mesh_CompileFrameZero(aliasmesh_t *mesh) +{ + frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}}; + mesh->data_basevertex3f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[3][4])); + mesh->data_basesvector3f = mesh->data_basevertex3f + mesh->num_vertices * 3; + mesh->data_basetvector3f = mesh->data_basevertex3f + mesh->num_vertices * 6; + mesh->data_basenormal3f = mesh->data_basevertex3f + mesh->num_vertices * 9; + Mod_Alias_GetMesh_Vertex3f(loadmodel, frameblend, mesh, mesh->data_basevertex3f); + Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, mesh->data_basevertex3f, mesh->data_texcoord2f, mesh->data_element3i, mesh->data_basesvector3f, mesh->data_basetvector3f, mesh->data_basenormal3f); +} + static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask) { int i, framenum; @@ -507,6 +594,7 @@ void Mod_IDP0_Load(model_t *mod, void *buffer) Mod_MDL_LoadFrames (startframes, numverts, scale, translate, vertremap); Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles); Mod_CalcAliasModelBBoxes(); + Mod_Alias_Mesh_CompileFrameZero(loadmodel->alias.aliasdata_meshes); Mem_Free(vertst); Mem_Free(vertremap); @@ -845,6 +933,7 @@ void Mod_IDP2_Load(model_t *mod, void *buffer) loadmodel->alias.aliasdata_meshes->data_neighbor3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3])); Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles); Mod_CalcAliasModelBBoxes(); + Mod_Alias_Mesh_CompileFrameZero(loadmodel->alias.aliasdata_meshes); } void Mod_IDP3_Load(model_t *mod, void *buffer) @@ -953,6 +1042,7 @@ void Mod_IDP3_Load(model_t *mod, void *buffer) Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__); Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles); + Mod_Alias_Mesh_CompileFrameZero(mesh); if (LittleLong(pinmesh->num_shaders) >= 1) Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, pinmesh->name, ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name); @@ -1223,6 +1313,7 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer) Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__); Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles); + Mod_Alias_Mesh_CompileFrameZero(mesh); // since zym models do not have named sections, reuse their shader // name as the section name diff --git a/model_alias.h b/model_alias.h index f8c81f79..4e6faa02 100644 --- a/model_alias.h +++ b/model_alias.h @@ -277,6 +277,13 @@ typedef struct aliasmesh_s int num_morphframes; float *data_morphvertex3f; + // base frame (frame zero typically) + // since most models do not animate, caching the base frame helps + float *data_basevertex3f; + float *data_basesvector3f; + float *data_basetvector3f; + float *data_basenormal3f; + // skeletal blending, these are zero if model is morph int num_vertexboneweights; aliasvertexboneweight_t *data_vertexboneweights; @@ -298,5 +305,8 @@ typedef struct aliasbone_s } aliasbone_t; +struct frameblend_s; +void Mod_Alias_GetMesh_Vertex3f(const struct model_s *model, const struct frameblend_s *frameblend, const struct aliasmesh_s *mesh, float *out3f); + #endif diff --git a/model_shared.c b/model_shared.c index e0b55c80..d4948b4a 100644 --- a/model_shared.c +++ b/model_shared.c @@ -648,18 +648,53 @@ void Mod_ValidateElements(const int *elements, int numtriangles, int numverts, c Con_Printf("Mod_ValidateElements: out of bounds element detected at %s:%d\n", filename, fileline); } +// warning: this is an expensive function! +void Mod_BuildNormals(int numverts, int numtriangles, const float *vertex3f, const int *elements, float *normal3f) +{ + int i, tnum; + float normal[3], *v; + const int *e; + // clear the vectors + memset(normal3f, 0, numverts * sizeof(float[3])); + // process each vertex of each triangle and accumulate the results + for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3) + { + TriangleNormal(vertex3f + e[0] * 3, vertex3f + e[1] * 3, vertex3f + e[2] * 3, normal); + VectorNormalize(normal); + v = normal3f + e[0] * 3; + v[0] += normal[0]; + v[1] += normal[1]; + v[2] += normal[2]; + v = normal3f + e[1] * 3; + v[0] += normal[0]; + v[1] += normal[1]; + v[2] += normal[2]; + v = normal3f + e[2] * 3; + v[0] += normal[0]; + v[1] += normal[1]; + v[2] += normal[2]; + } + // now we could divide the vectors by the number of averaged values on + // each vertex... but instead normalize them + for (i = 0, v = normal3f;i < numverts;i++, v += 3) + VectorNormalize(v); +} + void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f) { float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2]; // 103 add/sub/negate/multiply (1 cycle), 3 divide (20 cycle), 3 sqrt (22 cycle), 4 compare (3 cycle?), total cycles not counting load/store/exchange roughly 241 cycles // 12 add, 28 subtract, 57 multiply, 3 divide, 3 sqrt, 4 compare, 50% chance of 6 negates - // 18 multiply, 19 subtract + // 6 multiply, 9 subtract VectorSubtract(v1, v0, v10); VectorSubtract(v2, v0, v20); normal3f[0] = v10[1] * v20[2] - v10[2] * v20[1]; normal3f[1] = v10[2] * v20[0] - v10[0] * v20[2]; normal3f[2] = v10[0] * v20[1] - v10[1] * v20[0]; + // 1 sqrt, 1 divide, 6 multiply, 2 add, 1 compare + VectorNormalize(normal3f); + // 12 multiply, 10 subtract tc10[1] = tc1[1] - tc0[1]; tc20[1] = tc2[1] - tc0[1]; svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0]; @@ -670,8 +705,6 @@ void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, con tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0]; tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1]; tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2]; - // 1 sqrt, 1 divide, 6 multiply, 2 add, 1 compare - VectorNormalize(normal3f); // 12 multiply, 4 add, 6 subtract f = DotProduct(svector3f, normal3f); svector3f[0] -= f * normal3f[0]; @@ -696,7 +729,7 @@ void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, con } } -// warning: this is an expensive function! +// warning: this is a very expensive function! void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const float *vertex3f, const float *texcoord2f, const int *elements, float *svector3f, float *tvector3f, float *normal3f) { int i, tnum; diff --git a/model_shared.h b/model_shared.h index 779da1f6..701a6ed5 100644 --- a/model_shared.h +++ b/model_shared.h @@ -641,6 +641,7 @@ extern char loadname[32]; // for hunk tags int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices); void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles); void Mod_ValidateElements(const int *elements, int numtriangles, int numverts, const char *filename, int fileline); +void Mod_BuildNormals(int numverts, int numtriangles, const float *vertex3f, const int *elements, float *normal3f); void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const float *vertex, const float *texcoord, const int *elements, float *svectors, float *tvectors, float *normals); shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable);