モデルに破壊時の破片データを追加します。
プログラムはこちらで公開しています。
https://github.com/matsushima-terunao/opengl_sample
破片データ作成
モデル作成時に、頂点データから破片データを作成します。
/**
* 破片データ作成。
*/
void create_fragment(Model& model) {
constexpr int cnt_max11 = 100, cnt_max12 = 150, cnt_max21 = 50, cnt_max22 = 100;
constexpr float vangle = 0.03f, vdistance = 10.0f, vangle2 = 0.03f, vdistance2 = 10.0f;
size_t vertex_count = model.polys ? model.polys_count : model.verts_count;
model.fragments1 = new Model::Fragment[vertex_count / 3];
model.fragments2 = new Model::Fragment[vertex_count];
memset(model.fragments1, 0, vertex_count / 3 * sizeof(Model::Fragment));
memset(model.fragments2, 0, vertex_count * sizeof(Model::Fragment));
model.fragments_count = vertex_count * 2;
std::cout << "model.verts_count=" << model.verts_count << std::endl;
std::cout << "> create_fragment(): vertex_count = " << vertex_count << ", model.fragments_count = " << model.fragments_count << std::endl;
float* new_vertsf = new float[model.fragments_count * model.verts_stride / sizeof(float)];
memcpy(new_vertsf, model.vertsf, model.verts_count * model.verts_stride);
// 中心座標用に頂点座標を加算
for (int i = 0; i < vertex_count; ++i) {
size_t vi = (model.polys ? model.polys[i] : i) * model.verts_stride / sizeof(float);
model.fragments1[i / 3].x += model.vertsf[vi + 0] / 3;
model.fragments1[i / 3].y += model.vertsf[vi + 1] / 3;
model.fragments1[i / 3].z += model.vertsf[vi + 2] / 3;
int i2 = i - i % 3 + (i + 2) % 3; // 0-1 1-2 2-0
model.fragments2[i].x += model.vertsf[vi + 0] / 2;
model.fragments2[i].y += model.vertsf[vi + 1] / 2;
model.fragments2[i].z += model.vertsf[vi + 2] / 2;
model.fragments2[i2].x += model.vertsf[vi + 0] / 2;
model.fragments2[i2].y += model.vertsf[vi + 1] / 2;
model.fragments2[i2].z += model.vertsf[vi + 2] / 2;
}
// 移動・回転量
for (int i = 0; i < vertex_count / 3; ++i) {
vec3_norm(&model.fragments1[i].vx, &model.fragments1[i].x);
model.fragments1[i].vx += randf(-1.0f, 1.0f) * vdistance;
model.fragments1[i].vy += randf(-1.0f, 1.0f) * vdistance;
model.fragments1[i].vz += randf(-1.0f, 1.0f) * vdistance;
model.fragments1[i].va = randf(-1.0f, 1.0f) * vangle;
model.fragments1[i].vb = randf(-1.0f, 1.0f) * vangle;
model.fragments1[i].vc = randf(-1.0f, 1.0f) * vangle;
model.fragments1[i].cnt = 0;
model.fragments1[i].cnt_max = (int)randf(cnt_max11, cnt_max12);
}
for (int i = 0; i < vertex_count; ++i) {
vec3_sub(&model.fragments2[i].vx, &model.fragments2[i].x, &model.fragments1[i / 3].x);
vec3_norm(&model.fragments2[i].vx, &model.fragments2[i].x);
model.fragments2[i].vx += randf(-1.0f, 1.0f) * vdistance2;
model.fragments2[i].vy += randf(-1.0f, 1.0f) * vdistance2;
model.fragments2[i].vz += randf(-1.0f, 1.0f) * vdistance2;
model.fragments2[i].va = randf(-1.0f, 1.0f) * vangle2;
model.fragments2[i].vb = randf(-1.0f, 1.0f) * vangle2;
model.fragments2[i].vc = randf(-1.0f, 1.0f) * vangle2;
model.fragments2[i].cnt = 0;
model.fragments2[i].cnt_max = (int)randf(cnt_max21, cnt_max22);
}
model.vertsf = new_vertsf;
}
破片データ初期化
モデル破壊時に、破片データの座標などの初期化を行います。
/**
* 破片データ初期化。
*/
void init_fragment(Model& model, float* buf) {
constexpr int cnt_max11 = 100, cnt_max12 = 150, cnt_max21 = 50, cnt_max22 = 100;
size_t vertex_count = model.polys ? model.polys_count : model.verts_count;
// 移動・回転量
for (int i = 0; i < vertex_count / 3; ++i) {
model.fragments1[i].cnt = 0;
model.fragments1[i].cnt_max = (int)randf(cnt_max11, cnt_max12);
}
for (int i = 0; i < vertex_count; ++i) {
model.fragments2[i].cnt = 0;
model.fragments2[i].cnt_max = (int)randf(cnt_max21, cnt_max22);
}
// 初期データ
model.fragment1_count = model.fragment2_count = 0;
memcpy(buf, model.vertsf, model.verts_count * model.verts_stride);
}
破片データ変更
破片の移動は、移動量に応じて頂点データを直接書き換えます。
/**
* 破片データ変更。
*/
void translate_vertex(Model& model, float* buf) {
size_t stride_length = model.verts_stride / sizeof(float);
size_t vertex_count = model.polys ? model.polys_count : model.verts_count;
model.fragment1_count = model.fragment2_count = 0;
float* buf1 = buf;
float* buf2 = buf + model.fragments_count * stride_length;
float angle1[3] = { 0.0f, 0.0f, 0.0f }, sin1[3] = { 0.0f, 0.0f, 0.0f }, cos1[3] = { 1.0f, 1.0f, 1.0f };
float angle2[3] = { 0.0f, 0.0f, 0.0f }, sin2[3] = { 0.0f, 0.0f, 0.0f }, cos2[3] = { 1.0f, 1.0f, 1.0f };
for (int i = 0; i < vertex_count; ++i) {
size_t vi = (model.polys ? model.polys[i] : i) * stride_length;
if (model.fragments1[i / 3].cnt < model.fragments1[i / 3].cnt_max) {
// 破片1
translate_fragment_vertex(&model.fragments1[i / 3], nullptr,
*(Vertex*)buf1, *(Vertex*)&model.vertsf[vi], angle1, sin1, cos1, nullptr, nullptr, nullptr);
model.fragments1[i / 3].cnt += (2 == i % 3);
buf1 += stride_length;
++model.fragment1_count;
} else if (model.fragments2[i].cnt < model.fragments2[i].cnt_max) {
// 破片2
for (int j = 0; j < 2; ++j) {
buf2 -= stride_length;
++model.fragment2_count;
size_t i2 = (0 == j) ? i : i - i % 3 + (i + 2) % 3; // 0-1 1-2 2-0
size_t vi2 = (model.polys ? model.polys[i2] : i2) * stride_length;
translate_fragment_vertex(&model.fragments2[i], &model.fragments1[i / 3],
*(Vertex*)buf2, *(Vertex*)&model.vertsf[vi2], angle2, sin2, cos2, angle1, sin1, cos1);
}
model.fragments1[i / 3].cnt += (2 == i % 3);
++model.fragments2[i].cnt;
}
}
}
/**
* 破片データ頂点変更。
*/
static void translate_fragment_vertex(Model::Fragment* fragment1, Model::Fragment* fragment2,
Vertex& dst_vertex, Vertex& src_vertex, float* angle, float* sin, float* cos, float* angle2, float* sin2, float* cos2) {
translate_vertex(fragment1, &dst_vertex.x, &src_vertex.x, angle, sin, cos);
if (fragment2) {
translate_vertex(fragment2, &dst_vertex.x, &dst_vertex.x, angle2, sin2, cos2);
}
dst_vertex.r = src_vertex.r;
dst_vertex.g = src_vertex.g;
dst_vertex.b = src_vertex.b;
dst_vertex.u = src_vertex.u;
dst_vertex.v = src_vertex.v;
translate_vertex(nullptr, &dst_vertex.nx, &src_vertex.nx, angle, sin, cos);
if (fragment2) {
translate_vertex(nullptr, &dst_vertex.nx, &dst_vertex.nx, angle2, sin2, cos2);
}
}
/**
* 頂点変更。
*/
static void translate_vertex(Model::Fragment* fragment, float* dst_vertex, float* src_vertex, float* angle, float* sin, float* cos) {
float x = src_vertex[0];
float y = src_vertex[1];
float z = src_vertex[2];
if (fragment) {
// オフセット
x -= fragment->x;
y -= fragment->y;
z -= fragment->z;
// sin/cos 更新
for (int i = 0; i < 3; ++i) {
float a = fragment->cnt * (&fragment->va)[i];
if (angle[i] != a) {
angle[i] = a;
sin[i] = sinf(a);
cos[i] = cosf(a);
}
}
}
// x軸回転
float x1 = x;
float y1 = y * cos[0] - z * sin[0];
float z1 = y * sin[0] + z * cos[0];
// y軸回転
float x2 = x1 * cos[1] + z1 * sin[1];
float y2 = y1;
float z2 = -x1 * sin[1] + z1 * cos[1];
// z軸回転
dst_vertex[0] = x2 * cos[2] - y2 * sin[2];
dst_vertex[1] = x2 * sin[2] + y2 * cos[2];
dst_vertex[2] = z2;
if (fragment) {
// オフセット + 移動
dst_vertex[0] += fragment->x + fragment->vx * fragment->cnt;
dst_vertex[1] += fragment->y + fragment->vy * fragment->cnt;
dst_vertex[2] += fragment->z + fragment->vz * fragment->cnt;
}
}
頂点データを変更しているので、バッファーデータも更新します。
// モデル描画
// 破片データ更新。
if (nullptr != sphere_model.fragments1) {
if (frame_count >= 100) {
glBindBuffer(GL_ARRAY_BUFFER, sphere_model.vertex_buffer);
float* buf = (float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, sphere_model.verts_count * sphere_model.verts_stride, GL_MAP_WRITE_BIT);
translate_vertex(sphere_model, buf);
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
破片1はポリゴン、破片2はワイヤーで描画します。
// 描画
glBindVertexArray(sphere_model.vertex_array);
if (frame_count >= 100) {
if (sphere_model.fragment1_count >= 1) {
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)sphere_model.fragment1_count);
}
if (sphere_model.fragment2_count >= 1) {
glDrawArrays(GL_LINES, (GLint)(sphere_model.fragments_count - sphere_model.fragment2_count), (GLsizei)sphere_model.fragment2_count);
}
コメント