目前,我正在尝试使用OpenGL在C ++中制作游戏引擎,并希望让3D动画能够正常运行。我被建议使用Assimp并且能够找到一个让静态模型工作的教程,但我不知道从哪里开始动画。我一直试图谷歌它,但没有找到任何有效的东西。如何修改代码以获取动画?推荐使用哪种文件格式?
这是我目前的代码:
//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();
}
答案 0 :(得分:5)
这是一个古老的问题,但是我确信它可能会在将来被其他人使用,因此我将尝试概述使用Assimp库进行动画处理时所具有的一些选项。
首先,我想提一提,您可以在没有Assimp库的情况下进行动画处理。该库只是为您提供了一种加载模型的好方法,但是您发现它不会为您做动画。
从概念上讲,无论您是否使用Assimp,动画都将非常相似。例如;如果您编写了自己的模型加载器,则可以轻松地使用它而不是Assimp并仍然可以进行动画处理。但是,由于制作动画的方式不止一种,因此实现动画的方式可能会受到更多限制,因为在没有Assimp的情况下进行骨架动画将涉及编写模型加载器,该加载器可以从中获取骨骼变换,权重和各种数据模型文件,这可能需要一段时间。
有多种制作动画的方法;无论是技术方面,还是您是否想通过硬件加速(在GPU或CPU上)来实现。我要提到的是这里的一些选项,因为大多数人都使用Assimp来做骨骼动画,如果您的数学技能不强并且只想要易于组合的东西,这可能会令人生畏。 / p>
通常有三种接受的动画制作方法:
关键帧
关键帧动画是当您为动画的每一帧创建单独的模型时,类似于2D精灵表。您可以连续渲染模型以产生动画。该方法可能是最简单但最幼稚的实现,因为您需要为每个动画加载多个模型。这些框架之间的过渡可能会很明显,具体取决于您生成的框架数量,并且在看起来可接受之前,您可能需要导出几个模型文件。 这种方法的另一个缺点是您可能需要生成自己的模型。
具有插值的关键帧
此方法与上述方法类似,但是不是将每个关键帧生成为单独的模型,而是仅生成几个关键帧,并使用内插引擎生成“缺失”模型。之所以可以这样做,是因为如果知道顶点的起点和终点,我们可以进行插值以找出在时间= 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向上)等。