OpenGL进阶06.为模型添加光照和贴图

Posted stq_wyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL进阶06.为模型添加光照和贴图相关的知识,希望对你有一定的参考价值。

上篇文章介绍了模型的加载,不过太丑了,这篇文章我们给它添加一下光照和纹理,让它好看一点。

首先看一下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);
	void SetAmbientMaterial(float r, float g, float b, float a);
	void SetDiffuseMaterial(float r, float g, float b, float a);
	void SetSpecularMaterial(float r, float g, float b, float a);
	void SetTexture(const char*imagePath);
;

model.cpp实现接口:

#include "model.h"
#include "utils.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)
			if (szOneLine[0] == 'v')
				std::stringstream ssOneLine(szOneLine);
				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("position : %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 vertexStr;
				for (int i = 0; i < 3; i++) 
					ssOneLine >> vertexStr;
					size_t pos = vertexStr.find_first_of('/');
					std::string posIndexStr = vertexStr.substr(0, pos);
					size_t pos2 = vertexStr.find_first_of('/', pos + 1);
					std::string texcoordIndexStr = vertexStr.substr(pos + 1, pos2 - 1 - pos);
					std::string normalIndexStr = vertexStr.substr(pos2 + 1, vertexStr.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);
				
			
		
	
	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");
	mShader->SetVec4("U_LightPos", 0.0f, 1.0f, 1.0f, 0.0f);
	mShader->SetVec4("U_LightAmbient", 1.0f, 1.0f, 1.0f, 1.0f);
	mShader->SetVec4("U_LightDiffuse", 1.0f, 1.0f, 1.0f, 1.0f);
	mShader->SetVec4("U_LightSpecular", 1.0f, 1.0f, 1.0f, 1.0f);
	mShader->SetVec4("U_CameraPos", 0.0f, 0.0f, 0.0f, 1.0f);
	mShader->SetVec4("U_LightOpt", 32.0f, 0.0f, 0.0f, 1.0f);
	SetAmbientMaterial(0.1f, 0.1f, 0.1f, 1.0f);
	SetDiffuseMaterial(0.6f, 0.6f, 0.6f, 1.0f);
	SetSpecularMaterial(1.0f, 1.0f, 1.0f, 1.0f);

void Model::Draw(glm::mat4 & viewMatrix, glm::mat4 projectionMatrix) 
	glEnable(GL_DEPTH_TEST);
	mVertexBuffer->Bind();
	glm::mat4 it = glm::inverseTranspose(mModelMatrix);
	mShader->Bind(glm::value_ptr(mModelMatrix), glm::value_ptr(viewMatrix), glm::value_ptr(projectionMatrix));
	glUniformMatrix4fv(glGetUniformLocation(mShader->mProgram, "IT_ModelMatrix"), 1, GL_FALSE, glm::value_ptr(it));
	glDrawArrays(GL_TRIANGLES, 0, mVertexBuffer->mVertexCount);
	mVertexBuffer->Unbind();

void Model::SetPosition(float x, float y, float z) 
	mModelMatrix = glm::translate(x, y, z);

void Model::SetAmbientMaterial(float r, float g, float b, float a) 
	mShader->SetVec4("U_AmbientMaterial", r, g, b, a);

void Model::SetDiffuseMaterial(float r, float g, float b, float a) 
	mShader->SetVec4("U_DiffuseMaterial", r, g, b, a);

void Model::SetSpecularMaterial(float r, float g, float b, float a) 
	mShader->SetVec4("U_SpecularMaterial", r, g, b, a);

void Model::SetTexture(const char*imagePath) 
	mShader->SetTexture("U_Texture", imagePath);

然后看下shader里的变化:

model.vs

attribute vec4 position;
attribute vec4 color;
attribute vec4 texcoord;
attribute vec4 normal;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 IT_ModelMatrix;
varying vec4 V_Color;
varying vec4 V_Normal;
varying vec4 V_WorldPos;
varying vec4 V_Texcoord;
void main()

	V_Color=color;
	V_Normal=IT_ModelMatrix*normal;
	V_WorldPos=ModelMatrix*position;
	V_Texcoord=texcoord;
	gl_Position=ProjectionMatrix*ViewMatrix*ModelMatrix*position;

model.fs

#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D U_Texture;
uniform vec4 U_LightPos;
uniform vec4 U_LightAmbient;
uniform vec4 U_LightDiffuse;
uniform vec4 U_LightSpecular;
uniform vec4 U_AmbientMaterial;
uniform vec4 U_DiffuseMaterial;
uniform vec4 U_SpecularMaterial;
uniform vec4 U_CameraPos;
uniform vec4 U_LightOpt;
varying vec4 V_Color;
varying vec4 V_Normal;
varying vec4 V_WorldPos;
varying vec4 V_Texcoord;
void main()

	vec4 color=vec4(0.0,0.0,0.0,0.0);
	vec4 ambientColor=U_LightAmbient*U_AmbientMaterial;
	vec3 lightPos=U_LightPos.xyz;
	vec3 L=lightPos;
	L=normalize(L);
	vec3 n=normalize(V_Normal.xyz);
	float diffuseIntensity=max(0.0,dot(L,n));
	vec4 diffuseColor=U_LightDiffuse*U_DiffuseMaterial*diffuseIntensity;
	vec4 specularColor=vec4(0.0,0.0,0.0,0.0);
	if(diffuseIntensity!=0.0)
	
		vec3 reflectDir=normalize(reflect(-L,n));
		vec3 viewDir=normalize(U_CameraPos.xyz-V_WorldPos.xyz);
		specularColor=U_LightSpecular*U_SpecularMaterial*pow(max(0.0,dot(viewDir,reflectDir)),U_LightOpt.x);
	
	if(U_LightOpt.w==1.0)
	
		color=ambientColor+diffuseColor*texture2D(U_Texture,V_Texcoord.xy)+specularColor;
	
	else
	
		color=(ambientColor+diffuseColor)*texture2D(U_Texture,V_Texcoord.xy);
	
	gl_FragColor=color;

scene.cpp调用:

#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.SetTexture("Res/earth.bmp");
	model.SetPosition(0.0f, 0.0f, -3.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进阶06.为模型添加光照和贴图的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL进阶06.为模型添加光照和贴图

OpenGL进阶06.为模型添加光照和贴图

✠OpenGL-10-增强表面细节

OpenGL进阶02.为三角形添加纹理贴图

OpenGL进阶02.为三角形添加纹理贴图

OpenGL进阶02.为三角形添加纹理贴图