Files
dl_old/dl/render/dl_model_data.cpp
T
2024-09-17 17:56:41 +08:00

270 lines
6.8 KiB
C++

#include "dl_model_data.h"
#include "vk/dl_vk.h"
namespace dl
{
dl::Matrix4 ModelNode::Runtime::GetMatrixLocal()
{
if (_bNeedUpdateMatrixLocal)
{
_matLocal = _trans2Parent.GetMatrix();
}
return _matLocal;
}
dl::Matrix4 ModelNode::Runtime::GetMatrixWorld(ModelNode* node)
{
if (_bNeedUpdateMatrixWorld)
{
Matrix4 mat = GetMatrixLocal();
ModelNode* p = node;
while (p)
{
mat = p->_rt.GetMatrixLocal() * mat;
p = p->_parent;
}
_matWorld = mat;
_bNeedUpdateMatrixWorld = false;
return mat;
}
else
{
return _matWorld;
}
}
void ModelNode::Update()
{
_rt._bNeedUpdateMatrixWorld = true;
if (_mesh)
{
ModelMesh::Runtime& rt_mesh = _mesh->_rt;
Matrix4 mat = GetMatrixWorld();
if (_skin)
{
rt_mesh._mat = mat;
// Update join matrices
Matrix4 mat_mesh_inv = Mat::GetInverse(mat);
size_t num_joint = std::min(_skin->_allJoint.size(), NUM_MAX_JOINT);
rt_mesh._allMatJoint.resize(num_joint);
for (size_t i = 0; i < num_joint; ++i)
{
ModelNode* node_joint = _skin->_allJoint[i];
Matrix4 mat_joint = node_joint->GetMatrixWorld() * _skin->_allOffsetMatrix[i];
mat_joint = mat_mesh_inv * mat_joint;
rt_mesh._allMatJoint[i] = mat_joint;
}
}
else
{
rt_mesh._allMatJoint.resize(1);
rt_mesh._allMatJoint[0] = mat;
}
}
for (ModelNode* node : _allChild)
{
node->Update();
}
}
void ModelData::Update()
{
if (_allAnimation.empty())
{
log_warn("模型没有动画!");
return;
}
ModelAnimation& ani = _allAnimation[_rt._curAni];
bool updated = false;
for (ModelAnimationChannel& channel : ani._allChannel)
{
ModelAnimationSampler& sampler = ani._allSampler[channel.samplerIndex];
if (sampler.inputs.size() > sampler.outputsVec4.size())
{
continue;
}
float time = _rt._t;
for (size_t i = 0; i < sampler.inputs.size() - 1; i++)
{
if (time >= sampler.inputs[i]
&& time <= sampler.inputs[i + 1])
{
float u = std::max(0.0f, time - sampler.inputs[i])
/ (sampler.inputs[i + 1] - sampler.inputs[i]);
if (u <= 1.0f)
{
switch (channel.path)
{
case ModelAnimationChannel::PathType::TRANSLATION:
sampler.translate(i, time, channel.node);
break;
case ModelAnimationChannel::PathType::SCALE:
sampler.scale(i, time, channel.node);
break;
case ModelAnimationChannel::PathType::ROTATION:
sampler.rotate(i, time, channel.node);
break;
}
updated = true;
}
}
}
}
if (updated)
{
for (ModelNode* node : _allNode)
{
node->Update();
}
}
}
BoundingBox::BoundingBox()
{
}
BoundingBox::BoundingBox(Position3 imin, Position3 imax):
min{imin},
max{imax}
{
}
BoundingBox BoundingBox::getAABB(Matrix4 m)
{
Position3 min = toShorter(m[3]);
Position3 max = min;
Position3 v0, v1;
Position3 right = toShorter(m[0]);
v0 = right * this->min[0];
v1 = right * this->max[0];
min += Each::Min(v0, v1);
max += Each::Max(v0, v1);
Position3 up = toShorter(m[1]);
v0 = up * this->min[1];
v1 = up * this->max[1];
min += Each::Min(v0, v1);
max += Each::Max(v0, v1);
Position3 back = toShorter(m[2]);
v0 = back * this->min[2];
v1 = back * this->max[2];
min += Each::Min(v0, v1);
max += Each::Max(v0, v1);
return BoundingBox(min, max);
}
dl::Position4 ModelAnimationSampler::cubicSplineInterpolation(size_t index, float time, uint32_t stride)
{
float delta = inputs[index + 1] - inputs[index];
float t = (time - inputs[index]) / delta;
const size_t current = index * stride * 3;
const size_t next = (index + 1) * stride * 3;
const size_t A = 0;
const size_t V = stride * 1;
const size_t B = stride * 2;
float t2 = powf(t, 2);
float t3 = powf(t, 3);
Position4 pt{};
for (uint32_t i = 0; i < stride; i++) {
float p0 = outputs[current + i + V]; // starting point at t = 0
float m0 = delta * outputs[current + i + A]; // scaled starting tangent at t = 0
float p1 = outputs[next + i + V]; // ending point at t = 1
float m1 = delta * outputs[next + i + B]; // scaled ending tangent at t = 1
pt[i] = ((2.f * t3 - 3.f * t2 + 1.f) * p0) + ((t3 - 2.f * t2 + t) * m0) + ((-2.f * t3 + 3.f * t2) * p1) + ((t3 - t2) * m0);
}
return pt;
}
void ModelAnimationSampler::translate(size_t index, float time, ModelNode* node)
{
switch (interpolation) {
case ModelAnimationSampler::InterpolationType::LINEAR: {
float u = std::max(0.0f, time - inputs[index]) / (inputs[index + 1] - inputs[index]);
node->_rt._trans2Parent._t = toShorter(
Each::Lerp(outputsVec4[index], outputsVec4[index + 1], u));
break;
}
case ModelAnimationSampler::InterpolationType::STEP: {
node->_rt._trans2Parent._t = toShorter(outputsVec4[index]);
break;
}
case ModelAnimationSampler::InterpolationType::CUBICSPLINE: {
node->_rt._trans2Parent._t = toShorter(cubicSplineInterpolation(index, time, 3));
break;
}
}
}
void ModelAnimationSampler::scale(size_t index, float time, ModelNode* node)
{
switch (interpolation) {
case ModelAnimationSampler::InterpolationType::LINEAR: {
float u = std::max(0.0f, time - inputs[index]) / (inputs[index + 1] - inputs[index]);
node->_rt._trans2Parent._s = toShorter(
Each::Lerp(outputsVec4[index], outputsVec4[index + 1], u));
break;
}
case ModelAnimationSampler::InterpolationType::STEP: {
node->_rt._trans2Parent._s = toShorter(outputsVec4[index]);
break;
}
case ModelAnimationSampler::InterpolationType::CUBICSPLINE: {
node->_rt._trans2Parent._s = toShorter(cubicSplineInterpolation(index, time, 3));
break;
}
}
}
void ModelAnimationSampler::rotate(size_t index, float time, ModelNode* node)
{
switch (interpolation) {
case ModelAnimationSampler::InterpolationType::LINEAR: {
float u = std::max(0.0f, time - inputs[index]) / (inputs[index + 1] - inputs[index]);
Position4 q1;
q1[0] = outputsVec4[index][0];
q1[1] = outputsVec4[index][1];
q1[2] = outputsVec4[index][2];
q1[3] = outputsVec4[index][3];
Position4 q2;
q2[0] = outputsVec4[index + 1][0];
q2[1] = outputsVec4[index + 1][1];
q2[2] = outputsVec4[index + 1][2];
q2[3] = outputsVec4[index + 1][3];
node->_rt._trans2Parent._r = Math::Normalize(Math::Slerp(q1, q2, u));
break;
}
case ModelAnimationSampler::InterpolationType::STEP: {
Position4 q1;
q1[0] = outputsVec4[index][0];
q1[1] = outputsVec4[index][1];
q1[2] = outputsVec4[index][2];
q1[3] = outputsVec4[index][3];
node->_rt._trans2Parent._r = q1;
break;
}
case ModelAnimationSampler::InterpolationType::CUBICSPLINE: {
Position4 rot = cubicSplineInterpolation(index, time, 4);
Position4 q;
q[0] = rot[0];
q[1] = rot[1];
q[2] = rot[2];
q[3] = rot[3];
node->_rt._trans2Parent._r = Math::Normalize(std::as_const(q));
break;
}
}
}
}