目前,我正在尝试使用C++和OpenGL制作游戏引擎,并希望使3D动画正常工作。建议我使用Assimp,并能够找到一个使静态模型起作用的教程,但是我不知道从哪里开始动画。我一直在尝试使用Google,但找不到任何有效的方法。如何修改代码以获取动画?建议使用哪种文件格式?
这是我目前拥有的代码:
//Mesh.h
#include <string>
#include "glut\include\GL\glew.h"
#include "glut\include\GL\glut.h"
#include <assimp/Importer.hpp> // C++ importer interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing fla
//textures
#include <SOIL.h>
class Mesh
{
public:
Mesh(void);
Mesh(std::string filename, std::string textureFilename, float x, float y, float z, float width, float height, float depth, float rotX, float rotY, float rotZ);
~Mesh(void);
void Init(std::string filename);
void LoadTexture(std::string textureName);
void Draw();
private:
GLfloat *vertexArray;
GLfloat *normalArray;
GLfloat *uvArray;
GLint numVerts;
GLuint m_Texture[1];
float m_CenterX, m_CenterY, m_CenterZ, m_Width, m_Height, m_Depth;
float m_XRotation, m_YRotation, m_ZRotation;
};
//Mesh.cpp
#include "Mesh.h"
Mesh::Mesh(void)
{
}
Mesh::Mesh(std::string filename, std::string textureFilename, float x, float y, float z, float width, float height, float depth, float rotX, float rotY, float rotZ)
{
//fills in variables
Init(filename);
LoadTexture(textureFilename);
}
Mesh::~Mesh(void)
{
}
void Mesh::Init(std::string filename)
{
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(filename,aiProcessPreset_TargetRealtime_Fast);//aiProcessPreset_TargetRealtime_Fast has the configs you'll need
aiMesh *mesh = scene->mMeshes[0]; //assuming you only want the first mesh
numVerts = mesh->mNumFaces*3;
vertexArray = new float[mesh->mNumFaces*3*3];
normalArray = new float[mesh->mNumFaces*3*3];
uvArray = new float[mesh->mNumFaces*3*2];
for(unsigned int i=0;i<mesh->mNumFaces;i++)
{
const aiFace& face = mesh->mFaces[i];
for(int j=0;j<3;j++)
{
aiVector3D uv = mesh->mTextureCoords[0][face.mIndices[j]];
memcpy(uvArray,&uv,sizeof(float)*2);
uvArray+=2;
aiVector3D normal = mesh->mNormals[face.mIndices[j]];
memcpy(normalArray,&normal,sizeof(float)*3);
normalArray+=3;
aiVector3D pos = mesh->mVertices[face.mIndices[j]];
memcpy(vertexArray,&pos,sizeof(float)*3);
vertexArray+=3;
}
}
uvArray-=mesh->mNumFaces*3*2;
normalArray-=mesh->mNumFaces*3*3;
vertexArray-=mesh->mNumFaces*3*3;
}
void Mesh::LoadTexture(std::string textureName)
{
glGenTextures(1, &m_Texture[0]);
glBindTexture(GL_TEXTURE_2D, m_Texture[0]);
// Set our texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // NOTE the GL_NEAREST Here!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // NOTE the GL_NEAREST Here!
m_Texture[0] = SOIL_load_OGL_texture // load an image file directly as a new OpenGL texture
(
textureName.c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
);
}
void Mesh::Draw()
{
glPushMatrix();
glTranslatef(m_CenterX, m_CenterY, m_CenterZ);
glRotatef(m_XRotation, 1, 0, 0);
glRotatef(m_YRotation, 0, 1, 0);
glRotatef(m_ZRotation, 0, 0, 1);
glScalef(m_Width, m_Height, m_Depth);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT,0,normalArray);
glTexCoordPointer(2,GL_FLOAT,0,uvArray);
glVertexPointer(3,GL_FLOAT,0,vertexArray);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Texture[0]);
glDrawArrays(GL_TRIANGLES,0,numVerts);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
最佳答案
这是一个古老的问题,但是我相信它可能会在将来被其他人使用,因此我将尝试概述使用Assimp库进行动画处理时可以使用的一些选项。
首先,我想提一提,您可以在没有Assimp库的情况下进行动画处理。该库只是为您提供了一种加载模型的好方法,但是您发现它不会为您做动画。
从概念上讲,无论您是否使用Assimp,动画都将非常相似。例如;如果您编写了自己的模型加载器,则可以轻松地使用它而不是Assimp并仍然可以进行动画处理。但是,由于制作动画的方法不止一种,因此实现动画的方式可能会受到更多限制,因为在没有Assimp的情况下制作骨骼动画会涉及编写模型加载器,该加载器可以从中获取骨骼变换,权重和各种数据模型文件,这可能需要一段时间。
有多种制作动画的方法。无论是在技术方面,还是您是否想通过硬件加速(在GPU或CPU上)来做到这一点。我要提到的是这里的一些选项,因为大多数人使用Assimp来做骨骼动画,如果您的数学技能不强,只是想要一些易于组合的东西,这可能会令人生畏。
通常,有三种接受的动画制作方法:
关键帧
关键帧动画是当您为动画的每个帧创建单独的模型时,类似于2D Sprite 表。您可以连续渲染模型以产生动画。由于您需要为每个动画加载多个模型,因此该方法可能是最简单但最幼稚的实现。这些框架之间的过渡可能会很明显,具体取决于您生成的框架数量,并且在看起来可接受之前,您可能需要导出几个模型文件。
这种方法的另一个缺点是您可能需要生成自己的模型。
带插值的关键帧
此方法与上述方法类似,但是不是将每个关键帧生成为单独的模型,而是仅生成几个关键帧,并使用内插法由引擎生成“缺失”模型。之所以可以这样做是因为,如果我们知道顶点的起点和终点,就可以进行插值以找出在时间= t处顶点应位于的位置。
本教程在解释如何进行关键帧动画方面做得非常出色:
https://www.khronos.org/opengl/wiki/Keyframe_Animation
同样,它没有讨论Assimp,但是概念是相同的,您仍然可以使用Assimp加载模型。
这种动画形式实现起来非常简单,对初学者来说非常好。但是,它确实有一些缺点。
如果您选择这种方式,则可能会受到内存的限制,因为此方法可能会占用VBO的大量内存,这取决于模型的详细程度。
如果选择创建自己的模型,则还需要保留模型文件中的顶点顺序,以便在一个模型文件(关键帧1)的顶点2与另一个模型文件(关键帧2)的顶点2之间进行插值正确的。
骨骼动画
这可能是制作动画最困难的方法,但是它处理了方法1和2中的许多问题。您还会发现,通过执行骨骼动画,您可以加载许多较新的文件格式。用于指定骨骼转换和旋转的文件,而不必为每个关键帧加载新文件。
这是我认为拥有Assimp会带来极大好处的一种情况。 Assimp非常有能力处理从模型文件中获取所需数据以进行骨骼动画处理。
如果您对制作骨骼动画感兴趣,那么本教程将是一个绝佳的选择,甚至还可以使用Assimp。
http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html
我本人使用本教程在自己的引擎中实现了骨骼动画。因此,如果您决定走这条路,我强烈建议您阅读此内容。
我要提到的最后一件事,是我发现有些人感到困惑,那就是可以使用硬件加速来完成动画,但这并不是绝对必要的。
在我提供的以前的教程链接中,这两个都是使用硬件加速进行动画处理的。在这种情况下,这意味着顶点计算是在顶点着色器主体中的GPU上完成的。
但是我知道很多人可能不熟悉现代OpenGL,在这种情况下,您仍然可以在CPU上进行这些相同的计算。这里的想法是查看顶点着色器中发生的事情,并创建一个为您执行这些计算的函数。
您还询问了动画的文件格式;这将取决于您执行动画的路线。如果要对.fbx和.md5等格式进行动画处理,则可能正在做骨骼动画处理。如果您选择关键帧动画,我可能会坚持使用.obj,这是我发现最易于使用的格式,因为格式说明非常容易理解。
在引擎中调试动画时,请确保您拥有一个已知有效的文件。另一个陷阱是,在互联网上下载免费模型可以包含任何旧格式,绝对纹理路径和不同的坐标系(Y向上或Z向上)等。
关于c++ - 如何使用Assimp获取模型动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28595852/