Import .glb model file with animation
- improve movement controls - TODO: allow more than one model, instance, and animation
This commit is contained in:
29
res/glsl/model_vertex.glsl
Normal file
29
res/glsl/model_vertex.glsl
Normal file
@@ -0,0 +1,29 @@
|
||||
#version 450 core
|
||||
|
||||
layout (location = 0) in vec3 position;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
layout (location = 2) in ivec4 jointIndices;
|
||||
layout (location = 3) in vec4 jointWeights;
|
||||
|
||||
out vec3 textureCoord;
|
||||
|
||||
uniform mat4 theModelMatrix;
|
||||
uniform mat4 theViewMatrix;
|
||||
uniform mat4 theProjMatrix;
|
||||
uniform mat4 theJointMatrices[64];
|
||||
uniform float texIndex;
|
||||
|
||||
void main()
|
||||
{
|
||||
mat4 skinMatrix =
|
||||
jointWeights.x * theJointMatrices[jointIndices.x] +
|
||||
jointWeights.y * theJointMatrices[jointIndices.y] +
|
||||
jointWeights.z * theJointMatrices[jointIndices.z] +
|
||||
jointWeights.w * theJointMatrices[jointIndices.w];
|
||||
|
||||
vec4 localPos = skinMatrix * vec4(position, 1.0);
|
||||
mat4 mvp = theProjMatrix * theViewMatrix * theModelMatrix;
|
||||
|
||||
gl_Position = mvp * localPos;
|
||||
textureCoord = vec3(texCoord.x, texCoord.y, texIndex);
|
||||
}
|
||||
BIN
res/model/human.glb
Normal file
BIN
res/model/human.glb
Normal file
Binary file not shown.
7
src/cgltf/LICENSE
Normal file
7
src/cgltf/LICENSE
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2018-2021 Johannes Kuhlmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
7240
src/cgltf/cgltf.h
Normal file
7240
src/cgltf/cgltf.h
Normal file
File diff suppressed because it is too large
Load Diff
1565
src/cgltf/cgltf_write.h
Normal file
1565
src/cgltf/cgltf_write.h
Normal file
File diff suppressed because it is too large
Load Diff
31
src/game.c
31
src/game.c
@@ -18,20 +18,31 @@ GameState *Game_New()
|
||||
|
||||
void Game_Update(GameState *gs)
|
||||
{
|
||||
vec3 move;
|
||||
glm_vec3_zero(move);
|
||||
const float speed = 0.3f;
|
||||
if (gs->input.w) move[0] = speed;
|
||||
else if (gs->input.s) move[0] = -speed;
|
||||
if (gs->input.a) move[1] = speed;
|
||||
else if (gs->input.d) move[1] = -speed;
|
||||
if (gs->input.q) move[2] = speed;
|
||||
else if (gs->input.e) move[2] = -speed;
|
||||
vec3 move, front, right;
|
||||
glm_vec3_zero(move);
|
||||
front[0] = gs->camera.front[0];
|
||||
front[1] = 0.0f;
|
||||
front[2] = gs->camera.front[2];
|
||||
glm_vec3_normalize(front);
|
||||
right[0] = gs->camera.right[0];
|
||||
right[1] = 0.0f;
|
||||
right[2] = gs->camera.right[2];
|
||||
glm_vec3_normalize(right);
|
||||
|
||||
ShapeInstance *target = &(gs->shapes[2]->instances[0]);
|
||||
if (gs->input.w) glm_vec3_add(move, front, move);
|
||||
else if (gs->input.s) glm_vec3_sub(move, front, move);
|
||||
if (gs->input.a) glm_vec3_sub(move, right, move);
|
||||
else if (gs->input.d) glm_vec3_add(move, right, move);
|
||||
if (gs->input.q) move[1] = 1.0f;
|
||||
else if (gs->input.e) move[1] = -1.0f;
|
||||
|
||||
glm_vec3_scale_as(move, speed, move);
|
||||
|
||||
ShapeInstance *target = &(gs->testModel.instance);
|
||||
vec3 displacement;
|
||||
glm_vec3_scale(gs->camera.front, -20.0f, displacement);
|
||||
displacement[1] += 16.0f;
|
||||
displacement[1] += 8.0f;
|
||||
glm_vec3_add(target->position, move, target->position);
|
||||
glm_vec3_add(target->position, displacement, gs->camera.position);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "cglm/cglm.h"
|
||||
#include "camera.h"
|
||||
#include "shape.h"
|
||||
#include "model.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -24,9 +25,11 @@ typedef struct
|
||||
SDL_GLContext *glContext;
|
||||
GLuint textureId;
|
||||
int shaderProgramId;
|
||||
int modelShaderProgramId;
|
||||
Camera camera;
|
||||
Shape **shapes;
|
||||
int numShapes;
|
||||
Model testModel;
|
||||
mat4 projMatrix;
|
||||
mat4 viewMatrix;
|
||||
} GameState;
|
||||
|
||||
226
src/model.c
226
src/model.c
@@ -1,4 +1,5 @@
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -6,7 +7,227 @@
|
||||
#include "GL/glew.h"
|
||||
#include "cglm/cglm.h"
|
||||
#include "hashmap/hashmap.h"
|
||||
#define CGLTF_IMPLEMENTATION
|
||||
#include "cgltf/cgltf.h"
|
||||
#include "shape.h"
|
||||
#include "model.h"
|
||||
|
||||
static struct BufferViewMapItem
|
||||
{
|
||||
cgltf_buffer_view *bv;
|
||||
int index;
|
||||
};
|
||||
|
||||
static int BufferView_Compare(const void *itemA, const void *itemB, void *udata)
|
||||
{
|
||||
const struct BufferViewMapItem *a = itemA;
|
||||
const struct BufferViewMapItem *b = itemB;
|
||||
return a->bv->offset < b->bv->offset ? -1
|
||||
: a->bv->offset > b->bv->offset ? 1
|
||||
: a->bv->size < b->bv->size ? -1
|
||||
: a->bv->size > b->bv->size ? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
static uint64_t BufferView_Hash(const void *item, uint64_t seed0, uint64_t seed1)
|
||||
{
|
||||
const struct BufferViewMapItem *x = item;
|
||||
uint64_t data = (uint64_t)x->bv->size << 32;
|
||||
data |= (uint64_t)x->bv->offset;
|
||||
return hashmap_sip(&data, sizeof(uint64_t), seed0, seed1);
|
||||
}
|
||||
|
||||
static struct BufferOptions
|
||||
{
|
||||
cgltf_type expectedType;
|
||||
cgltf_component_type expectedComponentType;
|
||||
int glAttributeIndex;
|
||||
int glAttributeSize;
|
||||
int glAttributeType;
|
||||
};
|
||||
|
||||
static bool InitBuffer(cgltf_accessor *accessor, struct hashmap *bvMap, GLuint *vbos, struct BufferOptions options)
|
||||
{
|
||||
if (accessor->type != options.expectedType || accessor->component_type != options.expectedComponentType)
|
||||
{
|
||||
printf("Error: unexpected attribute type\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Initializing buffer %d...\n", options.glAttributeIndex);
|
||||
cgltf_buffer_view *bv = accessor->buffer_view;
|
||||
struct BufferViewMapItem mapItem = {0};
|
||||
mapItem.bv = bv;
|
||||
void *existing = hashmap_get(bvMap, &mapItem);
|
||||
|
||||
if (existing == NULL)
|
||||
{
|
||||
printf("Error: bv map entry not found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
mapItem = *((struct BufferViewMapItem*)existing);
|
||||
GLuint vbo = vbos[mapItem.index];
|
||||
void *bvData = bv->buffer->data + bv->offset;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, bv->size, bvData, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(options.glAttributeIndex);
|
||||
if (options.expectedComponentType == cgltf_component_type_r_32f)
|
||||
glVertexAttribPointer(options.glAttributeIndex, options.glAttributeSize, options.glAttributeType, accessor->normalized, accessor->stride, (GLvoid*)accessor->offset);
|
||||
else
|
||||
glVertexAttribIPointer(options.glAttributeIndex, options.glAttributeSize, options.glAttributeType, accessor->stride, (GLvoid*)accessor->offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Model Model_LoadGltf(char *path)
|
||||
{
|
||||
printf("Loading glTF model file...\n");
|
||||
Model model = {0};
|
||||
model.instance.scale = 4.0f;
|
||||
cgltf_options options = {0};
|
||||
cgltf_data *data = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, path, &data);
|
||||
|
||||
if (result == cgltf_result_success)
|
||||
{
|
||||
result = cgltf_load_buffers(&options, data, path);
|
||||
}
|
||||
|
||||
if (result != cgltf_result_success)
|
||||
{
|
||||
printf("glTF Error\n");
|
||||
return model;
|
||||
}
|
||||
|
||||
printf("meshes: %d, skins: %d, animations: %d\n", data->meshes_count, data->skins_count, data->animations_count);
|
||||
|
||||
cgltf_skin *skin = NULL;
|
||||
for (int i = 0; i < data->skins_count; i++)
|
||||
{
|
||||
cgltf_skin *s = data->skins + i;
|
||||
const char *n = s->name;
|
||||
if (n != NULL && n[0] == 'r' && n[1] == 'i' && n[2] == 'g')
|
||||
{
|
||||
skin = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->meshes_count != 1 || data->meshes[0].primitives_count != 1 || skin == NULL)
|
||||
{
|
||||
printf("Unexpected number of meshes/primitives/skins\n");
|
||||
return model;
|
||||
}
|
||||
|
||||
cgltf_size buffer_views_count = data->buffer_views_count;
|
||||
cgltf_primitive *primitive = data->meshes->primitives;
|
||||
cgltf_accessor *indices = primitive->indices;
|
||||
cgltf_attribute *attributes = primitive->attributes;
|
||||
cgltf_size attributes_count = primitive->attributes_count;
|
||||
cgltf_morph_target *targets = primitive->targets;
|
||||
cgltf_size targets_count = primitive->targets_count;
|
||||
|
||||
if (primitive->type != cgltf_primitive_type_triangles)
|
||||
{
|
||||
printf("Unexpected primitive type\n");
|
||||
return model;
|
||||
}
|
||||
|
||||
if (indices->type != cgltf_type_scalar || indices->component_type != cgltf_component_type_r_16u)
|
||||
{
|
||||
printf("Unexpected data type for index buffer\n");
|
||||
return model;
|
||||
}
|
||||
|
||||
model.data = data;
|
||||
model.skin = skin;
|
||||
printf("primitive type: %d, attributes: %d, targets: %d\n", primitive->type, attributes_count, targets_count);
|
||||
|
||||
model.vbos = calloc(buffer_views_count, sizeof(GLuint));
|
||||
glGenVertexArrays(1, &model.vao);
|
||||
glBindVertexArray(model.vao);
|
||||
glGenBuffers(buffer_views_count, model.vbos);
|
||||
glGenBuffers(1, &model.ebo);
|
||||
struct hashmap *bvMap = hashmap_new(sizeof(struct BufferViewMapItem), 128, 0, 0, BufferView_Hash, BufferView_Compare, NULL, NULL);
|
||||
|
||||
for (int i = 0; i < buffer_views_count; i++)
|
||||
{
|
||||
cgltf_buffer_view *bv = data->buffer_views + i;
|
||||
struct BufferViewMapItem mapItem = {0};
|
||||
mapItem.bv = bv;
|
||||
mapItem.index = i;
|
||||
void *existing = hashmap_set(bvMap, &mapItem);
|
||||
if (existing != NULL) printf("Duplicate bv map entry (index %d)\n", i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < attributes_count; i++)
|
||||
{
|
||||
cgltf_attribute *attr = attributes + i;
|
||||
cgltf_accessor *accessor = attr->data;
|
||||
struct BufferOptions options = {0};
|
||||
|
||||
switch (attr->type)
|
||||
{
|
||||
case cgltf_attribute_type_position:
|
||||
options.expectedType = cgltf_type_vec3;
|
||||
options.expectedComponentType = cgltf_component_type_r_32f;
|
||||
options.glAttributeIndex = 0;
|
||||
options.glAttributeSize = 3;
|
||||
options.glAttributeType = GL_FLOAT;
|
||||
InitBuffer(accessor, bvMap, model.vbos, options);
|
||||
break;
|
||||
case cgltf_attribute_type_texcoord:
|
||||
options.expectedType = cgltf_type_vec2;
|
||||
options.expectedComponentType = cgltf_component_type_r_32f;
|
||||
options.glAttributeIndex = 1;
|
||||
options.glAttributeSize = 2;
|
||||
options.glAttributeType = GL_FLOAT;
|
||||
InitBuffer(accessor, bvMap, model.vbos, options);
|
||||
break;
|
||||
case cgltf_attribute_type_joints:
|
||||
options.expectedType = cgltf_type_vec4;
|
||||
options.expectedComponentType = cgltf_component_type_r_8u;
|
||||
options.glAttributeIndex = 2;
|
||||
options.glAttributeSize = 4;
|
||||
options.glAttributeType = GL_UNSIGNED_BYTE;
|
||||
InitBuffer(accessor, bvMap, model.vbos, options);
|
||||
break;
|
||||
case cgltf_attribute_type_weights:
|
||||
options.expectedType = cgltf_type_vec4;
|
||||
options.expectedComponentType = cgltf_component_type_r_32f;
|
||||
options.glAttributeIndex = 3;
|
||||
options.glAttributeSize = 4;
|
||||
options.glAttributeType = GL_FLOAT;
|
||||
InitBuffer(accessor, bvMap, model.vbos, options);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cgltf_buffer_view *indicesBufferView = indices->buffer_view;
|
||||
void *indicesData = indicesBufferView->buffer->data + indicesBufferView->offset;
|
||||
model.indexCount = indices->count;
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBufferView->size, indicesData, GL_STATIC_DRAW);
|
||||
|
||||
printf("skin: %s, joints: %d\n", skin->name, skin->joints_count);
|
||||
model.jointMatrices = calloc(skin->joints_count, sizeof(mat4));
|
||||
|
||||
printf("Finished loading glTF model file.\n");
|
||||
return model;
|
||||
}
|
||||
|
||||
void Model_Free(Model model)
|
||||
{
|
||||
free(model.vbos);
|
||||
free(model.jointMatrices);
|
||||
cgltf_data *data = model.data;
|
||||
cgltf_free(data);
|
||||
}
|
||||
|
||||
static enum
|
||||
{
|
||||
@@ -37,7 +258,10 @@ static int VertRef_Compare(const void *itemA, const void *itemB, void *udata)
|
||||
|
||||
static uint64_t VertRef_Hash(const void *item, uint64_t seed0, uint64_t seed1)
|
||||
{
|
||||
return hashmap_sip(item, 2 * sizeof(uint16_t), seed0, seed1);
|
||||
const struct VertRef *vr = item;
|
||||
uint64_t data = (uint64_t)vr->xyzIndex << 32;
|
||||
data |= (uint64_t)vr->uvIndex;
|
||||
return hashmap_sip(&data, sizeof(uint64_t), seed0, seed1);
|
||||
}
|
||||
|
||||
static void ReadCoords(const char *str, float *coords, int n)
|
||||
|
||||
19
src/model.h
19
src/model.h
@@ -1,3 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "GL/glew.h"
|
||||
#include "cglm/cglm.h"
|
||||
#include "shape.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *data;
|
||||
void *skin;
|
||||
mat4 *jointMatrices;
|
||||
GLuint *vbos;
|
||||
GLuint vao;
|
||||
GLuint ebo;
|
||||
int vboCount;
|
||||
int indexCount;
|
||||
ShapeInstance instance;
|
||||
} Model;
|
||||
|
||||
Model Model_LoadGltf(char *path);
|
||||
void Model_Free(Model model);
|
||||
Shape *Model_ReadObjFile(const char *path);
|
||||
|
||||
168
src/render.c
168
src/render.c
@@ -7,6 +7,7 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb/stb_image.h"
|
||||
#include "cglm/cglm.h"
|
||||
#include "cgltf/cgltf.h"
|
||||
#include "render.h"
|
||||
#include "camera.h"
|
||||
#include "game.h"
|
||||
@@ -125,15 +126,13 @@ static int CompileShader(GLchar *sourcePath, GLenum shaderType, char ***outCode,
|
||||
return shaderId;
|
||||
}
|
||||
|
||||
static int LoadShaders()
|
||||
static int LoadShaders(const char *vertShaderFilePath, const char *fragShaderFilePath)
|
||||
{
|
||||
const char *vertShaderFilePath = "./res/glsl/vertex.glsl";
|
||||
char **vertCode = NULL;
|
||||
int vertNumLines;
|
||||
int vertShaderId = CompileShader(vertShaderFilePath, GL_VERTEX_SHADER, &vertCode, &vertNumLines);
|
||||
if (vertShaderId < 0) return vertShaderId;
|
||||
|
||||
const char *fragShaderFilePath = "./res/glsl/fragment.glsl";
|
||||
char **fragCode = NULL;
|
||||
int fragNumLines;
|
||||
int fragShaderId = CompileShader(fragShaderFilePath, GL_FRAGMENT_SHADER, &fragCode, &fragNumLines);
|
||||
@@ -223,9 +222,10 @@ bool Render_Init(GameState *gs)
|
||||
printf("Created OpenGL window.\n");
|
||||
|
||||
glewInit();
|
||||
gs->shaderProgramId = LoadShaders();
|
||||
gs->shaderProgramId = LoadShaders("./res/glsl/vertex.glsl", "./res/glsl/fragment.glsl");
|
||||
gs->modelShaderProgramId = LoadShaders("./res/glsl/model_vertex.glsl", "./res/glsl/fragment.glsl");
|
||||
|
||||
if (gs->shaderProgramId < 0)
|
||||
if (gs->shaderProgramId < 0 || gs->modelShaderProgramId < 0)
|
||||
{
|
||||
printf("Failed to load shaders.\n");
|
||||
return false;
|
||||
@@ -238,7 +238,7 @@ bool Render_Init(GameState *gs)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
printf("Initialized OpenGL.\n");
|
||||
|
||||
gs->numShapes = 3;
|
||||
gs->numShapes = 2;
|
||||
|
||||
Shape *shape = Shape_MakePyramid(5);
|
||||
gs->shapes[0] = shape;
|
||||
@@ -256,27 +256,22 @@ bool Render_Init(GameState *gs)
|
||||
glGenBuffers(1, &shape->EBO);
|
||||
printf("Created shape 1.\n");
|
||||
|
||||
shape = Model_ReadObjFile("res/model/human.obj");
|
||||
gs->shapes[2] = shape;
|
||||
glGenVertexArrays(1, &shape->VAO);
|
||||
glGenBuffers(1, &shape->VBO);
|
||||
glGenBuffers(1, &shape->IBO);
|
||||
glGenBuffers(1, &shape->EBO);
|
||||
printf("Created shape 2.\n");
|
||||
|
||||
LoadTexture(gs);
|
||||
printf("Loaded textures.\n");
|
||||
Camera_Init(&gs->camera);
|
||||
|
||||
InitShapeBuffers(gs->shapes[0]);
|
||||
InitShapeBuffers(gs->shapes[1]);
|
||||
InitShapeBuffers(gs->shapes[2]);
|
||||
printf("Initialized buffers.\n");
|
||||
|
||||
gs->testModel = Model_LoadGltf("res/model/human.glb");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Render_Destroy(GameState *gs)
|
||||
{
|
||||
Model_Free(gs->testModel);
|
||||
SDL_GL_DeleteContext(gs->glContext);
|
||||
SDL_DestroyWindow(gs->window);
|
||||
}
|
||||
@@ -313,6 +308,132 @@ static void SetViewport(GameState *gs)
|
||||
Camera_GetViewMatrix(&gs->camera, gs->viewMatrix);
|
||||
}
|
||||
|
||||
static void Transform(ShapeInstance *instance, mat4 *matrix)
|
||||
{
|
||||
mat4 tempMat;
|
||||
glm_mat4_identity(tempMat);
|
||||
|
||||
glm_translate(tempMat, instance->position);
|
||||
|
||||
glm_rotate_x(tempMat, instance->rotation[0], tempMat);
|
||||
glm_rotate_y(tempMat, instance->rotation[1], tempMat);
|
||||
glm_rotate_z(tempMat, instance->rotation[2], tempMat);
|
||||
|
||||
vec3 scale;
|
||||
scale[0] = instance->scale;
|
||||
scale[1] = instance->scale;
|
||||
scale[2] = instance->scale;
|
||||
glm_scale(tempMat, scale);
|
||||
|
||||
memcpy(matrix, tempMat, sizeof(mat4));
|
||||
}
|
||||
|
||||
static void DrawModel(GameState *gs)
|
||||
{
|
||||
Model model = gs->testModel;
|
||||
ShapeInstance instance = model.instance;
|
||||
cgltf_data *data = model.data;
|
||||
cgltf_skin *skin = model.skin;
|
||||
cgltf_animation *anim = data->animations;
|
||||
mat4 modelMatrix;
|
||||
glm_mat4_identity(modelMatrix);
|
||||
Transform(&model.instance, &modelMatrix);
|
||||
|
||||
uint64_t ticks = SDL_GetTicks();
|
||||
float t = ticks / 1000.0f;
|
||||
while (t > 2.0f) t -= 2.0f;
|
||||
|
||||
// apply local transformations for each bone for the current animation frame
|
||||
for (int i = 0; i < anim->channels_count; i++)
|
||||
{
|
||||
cgltf_animation_channel* channel = &anim->channels[i];
|
||||
cgltf_animation_sampler* sampler = channel->sampler;
|
||||
cgltf_node* node = channel->target_node;
|
||||
|
||||
// find keyframe interval [k, k+1]
|
||||
size_t k = 0;
|
||||
float alpha = 0.0f;
|
||||
size_t num_keyframes = sampler->input->count;
|
||||
|
||||
// binary search may be faster
|
||||
for (size_t j = 0; j < num_keyframes - 1; ++j)
|
||||
{
|
||||
float t0, t1;
|
||||
cgltf_accessor_read_float(sampler->input, j, &t0, 1);
|
||||
cgltf_accessor_read_float(sampler->input, j + 1, &t1, 1);
|
||||
|
||||
if (t >= t0 && t <= t1)
|
||||
{
|
||||
k = j;
|
||||
float range = t1 - t0;
|
||||
alpha = (range > 0.0f) ? (t - t0) / range : 0.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// interpolate
|
||||
switch (channel->target_path)
|
||||
{
|
||||
case cgltf_animation_path_type_translation:
|
||||
{
|
||||
vec3 p0, p1, result;
|
||||
cgltf_accessor_read_float(sampler->output, k, p0, 3);
|
||||
cgltf_accessor_read_float(sampler->output, k + 1, p1, 3);
|
||||
glm_vec3_lerp(p0, p1, alpha, result);
|
||||
// glm_vec3_copy is not used here due to potential struct alignment issues
|
||||
for (int x = 0; x < 3; x++) node->translation[x] = result[x];
|
||||
node->has_translation = true;
|
||||
}
|
||||
break;
|
||||
case cgltf_animation_path_type_rotation:
|
||||
{
|
||||
versor q0, q1, result;
|
||||
cgltf_accessor_read_float(sampler->output, k, q0, 4);
|
||||
cgltf_accessor_read_float(sampler->output, k + 1, q1, 4);
|
||||
// slerp (not lerp) for rotation
|
||||
glm_quat_slerp(q0, q1, alpha, result);
|
||||
for (int x = 0; x < 4; x++) node->rotation[x] = result[x];
|
||||
node->has_rotation = true;
|
||||
}
|
||||
break;
|
||||
case cgltf_animation_path_type_scale:
|
||||
{
|
||||
vec3 s0, s1, result;
|
||||
cgltf_accessor_read_float(sampler->output, k, s0, 3);
|
||||
cgltf_accessor_read_float(sampler->output, k + 1, s1, 3);
|
||||
glm_vec3_lerp(s0, s1, alpha, result);
|
||||
for (int x = 0; x < 3; x++) node->scale[x] = result[x];
|
||||
node->has_scale = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// recalculate the joint matrices
|
||||
for (int i = 0; i < skin->joints_count; i++)
|
||||
{
|
||||
cgltf_node *joint = skin->joints[i];
|
||||
cgltf_node_transform_world(joint, (float*)model.jointMatrices[i]);
|
||||
mat4 inverseBind;
|
||||
cgltf_accessor_read_float(skin->inverse_bind_matrices, i, (float*)inverseBind, 16);
|
||||
glm_mat4_mul(model.jointMatrices[i], inverseBind, model.jointMatrices[i]);
|
||||
}
|
||||
|
||||
int shaderId = gs->modelShaderProgramId;
|
||||
glUseProgram(shaderId);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theModelMatrix"), 1, GL_FALSE, (void*)(modelMatrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theViewMatrix"), 1, GL_FALSE, (void*)(gs->viewMatrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theProjMatrix"), 1, GL_FALSE, (void*)(gs->projMatrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderId, "theJointMatrices"), 64, GL_FALSE, (void*)(model.jointMatrices));
|
||||
glUniform1f(glGetUniformLocation(shaderId, "texIndex"), 6.0f);
|
||||
glBindTexture(GL_TEXTURE_2D, gs->textureId);
|
||||
|
||||
glBindVertexArray(model.vao);
|
||||
glDrawElements(GL_TRIANGLES, model.indexCount, GL_UNSIGNED_SHORT, 0);
|
||||
}
|
||||
|
||||
void Render_Draw(GameState *gs)
|
||||
{
|
||||
glClearColor(0.4f, 0.6f, 0.8f, 1.0f);
|
||||
@@ -338,20 +459,7 @@ void Render_Draw(GameState *gs)
|
||||
{
|
||||
ShapeInstance* instance = shape->instances + j;
|
||||
mat4* matrix = (void*)(shape->instanceData + (j * 17) + 1);
|
||||
mat4 tempMat;
|
||||
glm_mat4_identity(tempMat);
|
||||
|
||||
glm_translate(tempMat, instance->position);
|
||||
glm_rotate_x(tempMat, instance->rotation[0], tempMat);
|
||||
glm_rotate_y(tempMat, instance->rotation[1], tempMat);
|
||||
glm_rotate_z(tempMat, instance->rotation[2], tempMat);
|
||||
|
||||
scale[0] = instance->scale;
|
||||
scale[1] = instance->scale;
|
||||
scale[2] = instance->scale;
|
||||
glm_scale(tempMat, scale);
|
||||
|
||||
memcpy(matrix, tempMat, sizeof(mat4));
|
||||
Transform(instance, matrix);
|
||||
}
|
||||
|
||||
// re-buffer the instance data because transformations may have changed
|
||||
@@ -361,5 +469,7 @@ void Render_Draw(GameState *gs)
|
||||
glDrawElementsInstanced(GL_TRIANGLES, shape->numIndices, GL_UNSIGNED_SHORT, 0, shape->numInstances);
|
||||
}
|
||||
|
||||
DrawModel(gs);
|
||||
|
||||
SDL_GL_SwapWindow(gs->window);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user