mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
3d: Implement per-instance billboard vertices and UVs
Store the four billboard vertex positions and UVs in each RE_instance and use them for regular billboard rendering. The static billboard mesh is kept for billboard particles.
This commit is contained in:
@@ -217,6 +217,8 @@ struct RE_instance {
|
||||
|
||||
// Billboards
|
||||
enum RE_draw_type draw_type;
|
||||
vec3 vertex_pos[4];
|
||||
vec2 vertex_uv[4];
|
||||
|
||||
// Lights
|
||||
vec3 vec;
|
||||
@@ -260,6 +262,7 @@ bool RE_instance_load_next_motion(struct RE_instance *instance, const char *name
|
||||
bool RE_instance_free_next_motion(struct RE_instance *instance);
|
||||
bool RE_instance_set_mesh_show(struct RE_instance *instance, const char *mesh_name, bool show);
|
||||
bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x, float y, float z);
|
||||
bool RE_instance_set_vertex_uv(struct RE_instance *instance, int index, float u, float v);
|
||||
int RE_instance_get_bone_index(struct RE_instance *instance, const char *name);
|
||||
bool RE_instance_trans_local_pos_to_world_pos_by_bone(struct RE_instance *instance, int bone, vec3 offset, vec3 out);
|
||||
float RE_instance_calc_height(struct RE_instance *instance, float x, float z);
|
||||
|
||||
@@ -201,8 +201,10 @@ struct RE_renderer {
|
||||
GLint blend_tex;
|
||||
GLint use_blend_texture;
|
||||
|
||||
GLuint billboard_vao;
|
||||
GLuint billboard_attr_buffer;
|
||||
GLuint billboard_particle_vao;
|
||||
GLuint billboard_particle_attr_buffer;
|
||||
GLuint billboard_instance_vao;
|
||||
GLuint billboard_instance_attr_buffer;
|
||||
struct hash_table *billboard_textures; // cg_no -> struct billboard_texture*
|
||||
|
||||
uint32_t last_frame_timestamp;
|
||||
|
||||
+25
-8
@@ -53,6 +53,14 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin)
|
||||
instance->use_mag_speed = true;
|
||||
instance->column_height = 1.0f;
|
||||
instance->column_radius = 1.0f;
|
||||
glm_vec3_copy((vec3){-1.0f, 2.0f, 0.0f}, instance->vertex_pos[0]);
|
||||
glm_vec3_copy((vec3){-1.0f, 0.0f, 0.0f}, instance->vertex_pos[1]);
|
||||
glm_vec3_copy((vec3){ 1.0f, 2.0f, 0.0f}, instance->vertex_pos[2]);
|
||||
glm_vec3_copy((vec3){ 1.0f, 0.0f, 0.0f}, instance->vertex_pos[3]);
|
||||
glm_vec2_copy((vec2){0.0f, 0.0f}, instance->vertex_uv[0]);
|
||||
glm_vec2_copy((vec2){0.0f, 1.0f}, instance->vertex_uv[1]);
|
||||
glm_vec2_copy((vec2){1.0f, 0.0f}, instance->vertex_uv[2]);
|
||||
glm_vec2_copy((vec2){1.0f, 1.0f}, instance->vertex_uv[3]);
|
||||
glm_mat4_identity(instance->local_transform);
|
||||
glm_mat3_identity(instance->normal_transform);
|
||||
return instance;
|
||||
@@ -610,19 +618,28 @@ bool RE_instance_set_mesh_show(struct RE_instance *instance, const char *mesh_na
|
||||
return false;
|
||||
}
|
||||
|
||||
// Converts from the (top-left, top-right, bottom-left, bottom-right) order used
|
||||
// by the API to the vertex order of the billboard mesh.
|
||||
static const int billboard_vertex_index[4] = {0, 2, 1, 3};
|
||||
|
||||
bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x, float y, float z)
|
||||
{
|
||||
if (!instance)
|
||||
if (!instance || (unsigned)index >= 4)
|
||||
return false;
|
||||
if (instance->type != RE_ITYPE_BILLBOARD)
|
||||
ERROR("not implemented");
|
||||
// Hack: This works because SetInstanceVertexPos is only used to scale
|
||||
// billboards, and SetInstanceScale is not used for billboards.
|
||||
if (index == 1) {
|
||||
instance->scale[0] = x;
|
||||
instance->scale[1] = y / 2.0;
|
||||
}
|
||||
return false;
|
||||
glm_vec3_copy((vec3){x, y, z}, instance->vertex_pos[billboard_vertex_index[index]]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RE_instance_set_vertex_uv(struct RE_instance *instance, int index, float u, float v)
|
||||
{
|
||||
if (!instance || (unsigned)index >= 4)
|
||||
return false;
|
||||
if (instance->type != RE_ITYPE_BILLBOARD)
|
||||
ERROR("not implemented");
|
||||
glm_vec2_copy((vec2){u, v}, instance->vertex_uv[billboard_vertex_index[index]]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int RE_instance_get_bone_index(struct RE_instance *instance, const char *name)
|
||||
|
||||
+47
-24
@@ -166,24 +166,8 @@ static void destroy_outline_renderer(struct outline_renderer *or)
|
||||
glDeleteProgram(or->program);
|
||||
}
|
||||
|
||||
static void init_billboard_mesh(struct RE_renderer *r)
|
||||
static void init_billboard_unused_vertex_attrs(void)
|
||||
{
|
||||
static const GLfloat vertices[] = {
|
||||
// x, y, z, u, v
|
||||
-1.0, 1.0, 0.0, 0.0, 0.0,
|
||||
-1.0, -1.0, 0.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0, 0.0,
|
||||
1.0, -1.0, 0.0, 1.0, 1.0,
|
||||
};
|
||||
glGenVertexArrays(1, &r->billboard_vao);
|
||||
glBindVertexArray(r->billboard_vao);
|
||||
glGenBuffers(1, &r->billboard_attr_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r->billboard_attr_buffer);
|
||||
|
||||
glEnableVertexAttribArray(VATTR_POS);
|
||||
glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0);
|
||||
glEnableVertexAttribArray(VATTR_UV);
|
||||
glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12);
|
||||
glDisableVertexAttribArray(VATTR_LIGHT_UV);
|
||||
glVertexAttrib2f(VATTR_LIGHT_UV, 0.0, 0.0);
|
||||
glDisableVertexAttribArray(VATTR_COLOR);
|
||||
@@ -196,8 +180,39 @@ static void init_billboard_mesh(struct RE_renderer *r)
|
||||
glVertexAttribI4i(VATTR_BONE_INDEX, 0, 0, 0, 0);
|
||||
glDisableVertexAttribArray(VATTR_BONE_WEIGHT);
|
||||
glVertexAttrib4f(VATTR_BONE_WEIGHT, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
static void init_billboard_mesh(struct RE_renderer *r)
|
||||
{
|
||||
static const GLfloat vertices[] = {
|
||||
// x, y, z, u, v
|
||||
-1.0, 1.0, 0.0, 0.0, 0.0,
|
||||
-1.0, -1.0, 0.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0, 0.0,
|
||||
1.0, -1.0, 0.0, 1.0, 1.0,
|
||||
};
|
||||
glGenBuffers(1, &r->billboard_particle_attr_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r->billboard_particle_attr_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
glGenBuffers(1, &r->billboard_instance_attr_buffer);
|
||||
|
||||
glGenVertexArrays(1, &r->billboard_particle_vao);
|
||||
glBindVertexArray(r->billboard_particle_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r->billboard_particle_attr_buffer);
|
||||
glEnableVertexAttribArray(VATTR_POS);
|
||||
glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0);
|
||||
glEnableVertexAttribArray(VATTR_UV);
|
||||
glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12);
|
||||
init_billboard_unused_vertex_attrs();
|
||||
|
||||
glGenVertexArrays(1, &r->billboard_instance_vao);
|
||||
glBindVertexArray(r->billboard_instance_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r->billboard_instance_attr_buffer);
|
||||
glEnableVertexAttribArray(VATTR_POS);
|
||||
glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0);
|
||||
glEnableVertexAttribArray(VATTR_UV);
|
||||
glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12);
|
||||
init_billboard_unused_vertex_attrs();
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
@@ -205,8 +220,10 @@ static void init_billboard_mesh(struct RE_renderer *r)
|
||||
|
||||
static void destroy_billboard_mesh(struct RE_renderer *r)
|
||||
{
|
||||
glDeleteVertexArrays(1, &r->billboard_vao);
|
||||
glDeleteBuffers(1, &r->billboard_attr_buffer);
|
||||
glDeleteVertexArrays(1, &r->billboard_particle_vao);
|
||||
glDeleteVertexArrays(1, &r->billboard_instance_vao);
|
||||
glDeleteBuffers(1, &r->billboard_particle_attr_buffer);
|
||||
glDeleteBuffers(1, &r->billboard_instance_attr_buffer);
|
||||
}
|
||||
|
||||
struct RE_renderer *RE_renderer_new(void)
|
||||
@@ -603,8 +620,6 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
|
||||
glm_mat4_pick3t(view_mat, rot);
|
||||
glm_mat4_ins3(rot, local_transform);
|
||||
glm_scale(local_transform, inst->scale);
|
||||
// Billboard instances are bottomed at y=0.
|
||||
glm_translate_y(local_transform, 1.0);
|
||||
mat3 normal_transform;
|
||||
// This should be safe because billboards do not have non-uniform scaling.
|
||||
glm_mat4_pick3(local_transform, normal_transform);
|
||||
@@ -629,7 +644,15 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, bt->texture);
|
||||
glUniform1i(r->texture, 0);
|
||||
glBindVertexArray(r->billboard_vao);
|
||||
GLfloat vertices[4][5];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
glm_vec3_copy(inst->vertex_pos[i], vertices[i]);
|
||||
glm_vec2_copy(inst->vertex_uv[i], vertices[i] + 3);
|
||||
}
|
||||
glBindVertexArray(r->billboard_instance_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r->billboard_instance_attr_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
@@ -649,7 +672,7 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform1i(r->texture, 0);
|
||||
glBindVertexArray(r->billboard_vao);
|
||||
glBindVertexArray(r->billboard_particle_vao);
|
||||
|
||||
for (int index = 0; index < pae_obj->nr_particles; index++) {
|
||||
struct particle_instance *pi = &po->instances[index];
|
||||
@@ -742,7 +765,7 @@ static void render_s3de_billboard_particles(struct RE_renderer *r, struct RE_ins
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform1i(r->texture, 0);
|
||||
glBindVertexArray(r->billboard_vao);
|
||||
glBindVertexArray(r->billboard_particle_vao);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glBindTexture(GL_TEXTURE_2D, bt->texture);
|
||||
|
||||
|
||||
@@ -2405,7 +2405,11 @@ static bool SealEngine_GetInstanceAngleB(int plugin, int instance, float *angle_
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool SealEngine_SetInstanceVertexUV(int PluginNumber, int InstanceNumber, int Index, float U, float V);
|
||||
static bool SealEngine_SetInstanceVertexUV(int plugin, int instance, int index, float u, float v)
|
||||
{
|
||||
return RE_instance_set_vertex_uv(get_instance(plugin, instance), index, u, v);
|
||||
}
|
||||
|
||||
//bool SealEngine_GetInstanceDiffuse(int PluginNumber, int InstanceNumber, float *pR, float *pG, float *pB);
|
||||
//bool SealEngine_GetInstanceAmbient(int PluginNumber, int InstanceNumber, float *pR, float *pG, float *pB);
|
||||
|
||||
@@ -2636,7 +2640,7 @@ HLL_QUIET_UNIMPLEMENTED(false, bool, SealEngine, IsThreadLoadingMode, int Plugin
|
||||
HLL_EXPORT(GetInstanceAngle, SealEngine_GetInstanceAngle), \
|
||||
HLL_EXPORT(GetInstanceAngleP, SealEngine_GetInstanceAngleP), \
|
||||
HLL_EXPORT(GetInstanceAngleB, SealEngine_GetInstanceAngleB), \
|
||||
HLL_TODO_EXPORT(SetInstanceVertexUV, SealEngine_SetInstanceVertexUV), \
|
||||
HLL_EXPORT(SetInstanceVertexUV, SealEngine_SetInstanceVertexUV), \
|
||||
HLL_TODO_EXPORT(GetInstanceDiffuse, SealEngine_GetInstanceDiffuse), \
|
||||
HLL_TODO_EXPORT(GetInstanceAmbient, SealEngine_GetInstanceAmbient), \
|
||||
HLL_EXPORT(GetInstanceAlpha, SealEngine_GetInstanceAlpha), \
|
||||
|
||||
Reference in New Issue
Block a user