OpenGL进阶05.绘制3D模型
Posted stq_wyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL进阶05.绘制3D模型相关的知识,希望对你有一定的参考价值。
这篇文章来绘制3D模型。添加了model.h和model.cpp文件.
model.h
#pragma once
#include "ggl.h"
#include "vertexbuffer.h"
#include "shader.h"
class Model
VertexBuffer* mVertexBuffer;
Shader* mShader;
glm::mat4 mModelMatrix;
public:
Model();
void Init(const char* modelPath);
void Draw(glm::mat4& viewMatrix, glm::mat4 projectionMatrix);
void SetPosition(float x, float y, float z);
;
model.cpp
#include "Utils.h"
#include "model.h"
Model::Model()
void Model::Init(const char* modelPath)
struct FloatData
float v[3];
;
struct VertexDefine
int posIndex;
int texcoordIndex;
int normalIndex;
;
int nFileSize = 0;
unsigned char* fileContent = LoadFileContent(modelPath, nFileSize);
if (fileContent == nullptr)
return;
std::vector<FloatData>positions, texcoords, normals;
std::vector<VertexDefine> vertexes;
std::stringstream ssFileContent((char*)fileContent);
std::string temp;
char szOneLine[256];
while (!ssFileContent.eof())
memset(szOneLine, 0, 256);
ssFileContent.getline(szOneLine, 256);
if (strlen(szOneLine)>0)
std::stringstream ssOneLine(szOneLine);
if (szOneLine[0]=='v')
if (szOneLine[1]=='t')
ssOneLine >> temp;
FloatData floatData;
ssOneLine >> floatData.v[0];
ssOneLine >> floatData.v[1];
texcoords.push_back(floatData);
printf("texcoord: %f,%f\\n",floatData.v[0],floatData.v[1]);
else if (szOneLine[1] == 'n')
ssOneLine >> temp;
FloatData floatData;
ssOneLine >> floatData.v[0];
ssOneLine >> floatData.v[1];
ssOneLine >> floatData.v[2];
normals.push_back(floatData);
printf("normal: %f,%f,%f\\n", floatData.v[0], floatData.v[1], floatData.v[2]);
else
ssOneLine >> temp;
FloatData floatData;
ssOneLine >> floatData.v[0];
ssOneLine >> floatData.v[1];
ssOneLine >> floatData.v[2];
positions.push_back(floatData);
printf("normal: %f,%f,%f\\n", floatData.v[0], floatData.v[1], floatData.v[2]);
else if (szOneLine[0] == 'f')
std::stringstream ssOneLine(szOneLine);
ssOneLine >> temp;
std::string verterStr;
for (int i=0;i<3;i++)
ssOneLine >> verterStr;
size_t pos = verterStr.find_first_of('/');
std::string posIndexStr = verterStr.substr(0, pos);
size_t pos2 = verterStr.find_first_of('/', pos + 1);
std::string texcoordIndexStr = verterStr.substr(pos + 1, pos2 - 1 - pos);
std::string normalIndexStr = verterStr.substr(pos2 + 1, verterStr.length() - 1 - pos2);
VertexDefine vd;
vd.posIndex = atoi(posIndexStr.c_str());
vd.texcoordIndex = atoi(texcoordIndexStr.c_str());
vd.normalIndex = atoi(normalIndexStr.c_str());
vertexes.push_back(vd);
printf("draw command: %s\\n", szOneLine);
delete fileContent;
int vertexCount = (int)vertexes.size();
mVertexBuffer = new VertexBuffer;
mVertexBuffer->SetSize(vertexCount);
for (int i=0;i<vertexCount;++i)
float* temp = positions[vertexes[i].posIndex - 1].v;
mVertexBuffer->SetPosition(i, temp[0], temp[1], temp[2]);
temp = texcoords[vertexes[i].texcoordIndex - 1].v;
mVertexBuffer->SetTexcoord(i, temp[0], temp[1]);
temp = normals[vertexes[i].normalIndex - 1].v;
mVertexBuffer->SetNormal(i, temp[0], temp[1], temp[2]);
mShader = new Shader;
mShader->Init("Res/model.vs", "Res/model.fs");
void Model::Draw(glm::mat4& viewMatrix, glm::mat4 projectionMatrix)
//Model是3D物体,开启深度测试
glEnable(GL_DEPTH_TEST);
mVertexBuffer->Bind();
mShader->Bind(glm::value_ptr(mModelMatrix), glm::value_ptr(viewMatrix), glm::value_ptr(projectionMatrix));
glDrawArrays(GL_TRIANGLES, 0, mVertexBuffer->mVertexCount);
mVertexBuffer->UnBind();
void Model::SetPosition(float x, float y, float z)
mModelMatrix = glm::translate(x, y, z);
3D模型的数据使用记事本打开可看到其数据结构(Sphere.obj的太长了,找了个小一点的,其结构都是一样的,数据长短的问题):
我们只需要v,vt,vn以及f开头的数据。model.cpp就是在做这件事。
shader.h和shader.cpp里添加了新的接口和结构体:
shader.h
#pragma once
#include "ggl.h"
struct UniformTexture
GLint mLocation;
GLuint mTexture;
UniformTexture()
mLocation = -1;
mTexture = 0;
;
struct UniformVector4f
GLint mLocation;
float v[4];
UniformVector4f()
mLocation = -1;
memset(v, 0, sizeof(float) * 4);
;
class Shader
public:
GLuint mProgram;
GLuint mPosition;
GLuint mColor;
GLuint mTexcoord;
GLuint mNormal;
std::map<std::string, UniformTexture*> mUniformTextures;
std::map<std::string, UniformVector4f*> mUniformVec4s;
GLint mModelMatrixLocation, mViewMatrixLocation, mProjectionMatrixLocation;
GLint mPositionLocation, mColorLocation, mTexcoordLocation, mNormalLocation;
void Init(const char* vs, const char* fs);
void Bind(float* M, float* V, float* P);
void SetTexture(const char* name, const char* imagePath);
void SetVec4(const char* name, float x, float y, float z, float w);
;
shader.cpp:
#include "shader.h"
#include "utils.h"
#include "vertexbuffer.h"
void Shader::Init(const char* vs, const char* fs)
int nFileSize = 0;
const char* vsCode = (char*)LoadFileContent(vs, nFileSize);
const char* fsCode = (char*)LoadFileContent(fs, nFileSize);
GLuint vsShader = CompileShader(GL_VERTEX_SHADER, vsCode);
if (vsShader == 0)
return;
GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, fsCode);
if (fsShader == 0)
return;
mProgram = CreateProgram(vsShader, fsShader);
glDeleteShader(vsShader);
glDeleteShader(fsShader);
if (mProgram != 0)
mModelMatrixLocation = glGetUniformLocation(mProgram, "ModelMatrix");
mViewMatrixLocation = glGetUniformLocation(mProgram, "ViewMatrix");
mProjectionMatrixLocation = glGetUniformLocation(mProgram, "ProjectionMatrix");
mPositionLocation = glGetAttribLocation(mProgram, "position");
mColorLocation = glGetAttribLocation(mProgram, "color");
mTexcoordLocation = glGetAttribLocation(mProgram, "texcoord");
mNormalLocation = glGetAttribLocation(mProgram, "normal");
void Shader::Bind(float* M, float* V, float* P)
glUseProgram(mProgram);
glUniformMatrix4fv(mModelMatrixLocation, 1, GL_FALSE, M);
glUniformMatrix4fv(mViewMatrixLocation, 1, GL_FALSE, V);
glUniformMatrix4fv(mProjectionMatrixLocation, 1, GL_FALSE, P);
int iIndex = 0;
for (auto iter = mUniformTextures.begin(); iter != mUniformTextures.end(); ++iter)
glActiveTexture(GL_TEXTURE0 + iIndex);
glBindTexture(GL_TEXTURE_2D, iter->second->mTexture);
glUniform1i(iter->second->mLocation, iIndex++);
for (auto iter = mUniformVec4s.begin(); iter != mUniformVec4s.end(); ++iter)
glUniform4fv(iter->second->mLocation, 1, iter->second->v);
glEnableVertexAttribArray(mPositionLocation);
glVertexAttribPointer(mPositionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glEnableVertexAttribArray(mColorLocation);
glVertexAttribPointer(mColorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 4));
glEnableVertexAttribArray(mTexcoordLocation);
glVertexAttribPointer(mTexcoordLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 8));
glEnableVertexAttribArray(mNormalLocation);
glVertexAttribPointer(mNormalLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 12));
void Shader::SetTexture(const char* name, const char* imagePath)
auto iter = mUniformTextures.find(name);
if (iter == mUniformTextures.end())
GLint location = glGetUniformLocation(mProgram, name);
if (location != -1)
UniformTexture* t = new UniformTexture;
t->mLocation = location;
t->mTexture = CreateTexture2DFromBMP(imagePath);
mUniformTextures.insert(std::pair<std::string, UniformTexture*>(name, t));
else
glDeleteTextures(1, &iter->second->mTexture);
iter->second->mTexture = CreateTexture2DFromBMP(imagePath);
void Shader::SetVec4(const char* name, float x, float y, float z, float w)
auto iter = mUniformVec4s.find(name);
if (iter == mUniformVec4s.end())
GLint location = glGetUniformLocation(mProgram, name);
if (location != -1)
UniformVector4f* v = new UniformVector4f;
v->v[0] = x;
v->v[1] = y;
v->v[2] = z;
v->v[3] = w;
v->mLocation = location;
mUniformVec4s.insert(std::pair<std::string, UniformVector4f*>(name, v));
else
iter->second->v[0] = x;
iter->second->v[1] = y;
iter->second->v[2] = z;
iter->second->v[3] = w;
新添加了model.vs和model.fs的shader
model.vs:
attribute vec4 position;
attribute vec4 color;
attribute vec4 texcoord;
attribute vec4 normal;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
varying vec4 V_Color;
void main()
V_Color=color;
gl_Position=ProjectionMatrix*ViewMatrix*ModelMatrix*position;
model.fs:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 V_Color;
void main()
gl_FragColor=V_Color;
scene.cpp里调用model的初始化以及绘制接口:
#include "scene.h"
#include "ggl.h"
#include "utils.h"
#include "ground.h"
#include "shader.h"
#include "model.h"
glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
Ground ground;
Model model;
void Init()
ground.Init();
model.Init("Res/Sphere.obj");
model.SetPosition(0.0f, 0.0f, -5.0f);
void SetViewPortSize(float width, float height)
projectionMatrix = glm::perspective(60.0f, width / height, 0.1f, 1000.0f);
void Draw()
float frameTime = GetFrameTime();
glClearColor(0.1f, 0.4f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ground.Draw(viewMatrix, projectionMatrix);
model.Draw(viewMatrix, projectionMatrix);
看下效果:
太丑了,下篇文章来让它变得好看一点~
以上是关于OpenGL进阶05.绘制3D模型的主要内容,如果未能解决你的问题,请参考以下文章
我的OpenGL学习进阶之旅解决使用Assimp和OpenGL进行在屏渲染和离屏渲染FBO时绘制3D模型出现各种诡异的模型渲染画面问题,都是血和泪的教训啊!!!
我的OpenGL学习进阶之旅Assimp库支持哪些3D模型格式?