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进阶05.绘制3D模型

OpenGL进阶05.绘制3D模型

我的OpenGL学习进阶之旅解决使用Assimp和OpenGL进行在屏渲染和离屏渲染FBO时绘制3D模型出现各种诡异的模型渲染画面问题,都是血和泪的教训啊!!!

我的OpenGL学习进阶之旅Assimp库支持哪些3D模型格式?

我的OpenGL学习进阶之旅Assimp库支持哪些3D模型格式?

我的OpenGL学习进阶之旅关于3D模型知识之:什么是obj文件和mtl文件