Skip to content

Commit

Permalink
Implement almost smooth hair using skinning
Browse files Browse the repository at this point in the history
This is the penultimate step for #51. The hair is as smooth as anyone
could want it to be, in any TR game (except TR1 obviously). The only
thing missing is the area between the hair and the head, which is very
noticeable in TR4 (especially the tutorial level).
  • Loading branch information
cochrane committed Jun 14, 2015
1 parent 42b9755 commit 9d24959
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 14 deletions.
87 changes: 86 additions & 1 deletion src/hair.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@

#include <algorithm>
#include <math.h>
#include "bullet/LinearMath/btScalar.h"
#include "hair.h"
#include "mesh.h"
#include "render.h"

// Internal utility function:
// Creates a single mesh out of all the parts of the given model.
// This assumes that Mesh_GenFaces was already called on the parts of model.
// @TODO: Should this be in this file or somewhere else? Where would it make sense?
void hair_CreateHairMesh(hair_p hair, const skeletal_model_s *model);

bool Hair_Create(hair_p hair, hair_setup_p setup, entity_p parent_entity)
{
Expand Down Expand Up @@ -210,10 +218,87 @@ bool Hair_Create(hair_p hair, hair_setup_p setup, entity_p parent_entity)

curr_joint++; // Point to the next joint.
}

hair_CreateHairMesh(hair, model);

return true;
}

void hair_CreateHairMesh(hair_p hair, const skeletal_model_s *model)
{
hair->mesh = (base_mesh_s *) calloc(sizeof(base_mesh_s), 1);
hair->mesh->element_count_per_texture = (uint32_t *) calloc(sizeof(uint32_t), engine_world.tex_count);
uint32_t totalElements = 0;

// Gather size information
for (int i = 0; i < model->mesh_count; i++)
{
const base_mesh_s *original = model->mesh_tree[i].mesh_base;

hair->mesh->num_texture_pages = std::max(hair->mesh->num_texture_pages, original->num_texture_pages);
hair->mesh->vertex_count += original->vertex_count;

for (int j = 0; j < original->num_texture_pages; j++)
{
hair->mesh->element_count_per_texture[j] += original->element_count_per_texture[j];
totalElements += original->element_count_per_texture[j];
}
}

// Create arrays
hair->mesh->elements = (uint32_t *) calloc(sizeof(uint32_t), totalElements);
hair->mesh->vertices = (vertex_s *) calloc(sizeof(vertex_s), hair->mesh->vertex_count);

// - with matrix index information
hair->mesh->matrix_indices = (int8_t *) calloc(sizeof(int8_t [2]), hair->mesh->vertex_count);

// Copy information
uint32_t *elementsStartPerTexture = (uint32_t *) calloc(sizeof(uint32_t), hair->mesh->num_texture_pages);
uint32_t matrixStart = 0;
uint32_t verticesStart = 0;
for (int i = 0; i < model->mesh_count; i++)
{
const base_mesh_s *original = model->mesh_tree[i].mesh_base;

// Copy vertices
memcpy(&hair->mesh->vertices[verticesStart], original->vertices, sizeof(vertex_t) * original->vertex_count);

// Copy elements
uint32_t originalElementsStart = 0;
for (int page = 0; page < original->num_texture_pages; page++)
{
memcpy(&hair->mesh->elements[elementsStartPerTexture[page]],
&original->elements[originalElementsStart],
sizeof(uint32_t) * original->element_count_per_texture[page]);
for (int j = 0; j < original->element_count_per_texture[page]; j++) {
hair->mesh->elements[elementsStartPerTexture[page]] = verticesStart + original->elements[originalElementsStart];
originalElementsStart += 1;
elementsStartPerTexture[page] += 1;
}
}

// And create matrix indices
for (int j = 0; j < original->vertex_count; j++) {
if (original->vertices[j].position[1] <= 0)
{
hair->mesh->matrix_indices[(verticesStart+j)*2 + 0] = std::max(0, i-1);
hair->mesh->matrix_indices[(verticesStart+j)*2 + 1] = i;
}
else
{
hair->mesh->matrix_indices[(verticesStart+j)*2 + 0] = i;
hair->mesh->matrix_indices[(verticesStart+j)*2 + 1] = std::min(i+1, model->mesh_count - 1);
}
hair->mesh->vertices[verticesStart+j].position[1] = 0;
}

verticesStart += original->vertex_count;
}
free(elementsStartPerTexture);

Mesh_GenVBO(&renderer, hair->mesh);
}

void Hair_Clear(hair_p hair)
{
for(int i=0; i<hair->joint_count; i++)
Expand Down
1 change: 1 addition & 0 deletions src/hair.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ typedef struct hair_s
uint32_t *hair_vertex_map; // Hair vertex indices to link
uint32_t *head_vertex_map; // Head vertex indices to link

struct base_mesh_s *mesh; // Mesh containing all vertices of all parts of this hair object.
}hair_t, *hair_p;

typedef struct hair_setup_s
Expand Down
22 changes: 10 additions & 12 deletions src/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,32 +594,30 @@ void Render_Entity(struct entity_s *entity, const btScalar modelViewMatrix[16],
}
}

void Render_Hair(struct entity_s *entity, const btScalar modelViewMatrix[16], const btScalar modelViewProjectionMatrix[16])
void Render_Hair(struct entity_s *entity, const btScalar modelViewMatrix[16], const btScalar projection[16])
{
if((!entity) || !(entity->character) || (entity->character->hair_count == 0) || !(entity->character->hairs))
return;

// Calculate lighting
const lit_shader_description *shader = render_setupEntityLight(entity, modelViewMatrix, false);
const lit_shader_description *shader = render_setupEntityLight(entity, modelViewMatrix, true);


for(int h=0; h<entity->character->hair_count; h++)
{
btScalar subModelViewMatrices[16 * 10];
for(uint16_t i=0; i<entity->character->hairs[h].element_count; i++)
{
btScalar subModelView[16];
btScalar subModelViewProjection[16];

btScalar transform[16];
const btTransform &bt_tr = entity->character->hairs[h].elements[i].body->getWorldTransform();
bt_tr.getOpenGLMatrix(transform);

Mat4_Mat4_mul(subModelView, modelViewMatrix, transform);
Mat4_Mat4_mul(subModelViewProjection, modelViewProjectionMatrix, transform);

glUniformMatrix4fvARB(shader->model_view, 1, GL_FALSE, subModelView);
glUniformMatrix4fvARB(shader->model_view_projection, 1, GL_FALSE, subModelViewProjection);
Render_Mesh(entity->character->hairs[h].elements[i].mesh);
Mat4_Mat4_mul(&subModelViewMatrices[i * 16], modelViewMatrix, transform);
}
glUniformMatrix4fvARB(shader->model_view, entity->character->hairs[h].element_count, GL_FALSE, subModelViewMatrices);
glUniformMatrix4fvARB(shader->projection, 1, GL_FALSE, projection);

Render_Mesh(entity->character->hairs[h].mesh);
}
}

Expand Down Expand Up @@ -933,7 +931,7 @@ void Render_DrawList()
if(renderer.world->Character)
{
Render_Entity(renderer.world->Character, renderer.cam->gl_view_mat, renderer.cam->gl_view_proj_mat, renderer.cam->gl_proj_mat);
Render_Hair(renderer.world->Character, renderer.cam->gl_view_mat, renderer.cam->gl_view_proj_mat);
Render_Hair(renderer.world->Character, renderer.cam->gl_view_mat, renderer.cam->gl_proj_mat);
}

/*
Expand Down
2 changes: 1 addition & 1 deletion src/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ render_list_p Render_CreateRoomListArray(unsigned int count);
void Render_Entity(struct entity_s *entity, const btScalar modelViewMatrix[16], const btScalar modelViewProjectionMatrix[16], const btScalar projection[16]); // отрисовка одного фрейма скелетной анимации
void Render_SkeletalModel(const struct lit_shader_description *shader, struct ss_bone_frame_s *bframe, const btScalar mvMatrix[16], const btScalar mvpMatrix[16], const btScalar pMatrix[16]);
void Render_SkeletalModelSkin(const lit_shader_description *shader, struct entity_s *ent, struct ss_bone_frame_s *bframe, const btScalar mvMatrix[16], const btScalar pMatrix[16]);
void Render_Hair(struct entity_s *entity, const btScalar modelViewMatrix[16], const btScalar modelViewProjectionMatrix[16]);
void Render_Hair(struct entity_s *entity, const btScalar modelViewMatrix[16], const btScalar projection[16]);
void Render_SkyBox(const btScalar matrix[16]);
void Render_Mesh(struct base_mesh_s *mesh);
void Render_PolygonTransparency(uint16_t &currentTransparency, const struct bsp_face_ref_s *p, const struct unlit_tinted_shader_description *shader);
Expand Down

0 comments on commit 9d24959

Please sign in to comment.