【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);
}

看下效果:

太丑了,下篇文章来让它变得好看一点~

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值