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

看下效果:

这样就好看多了~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要给导入的.obj模型增加光照,首先需要了解光照模型的基本原理。在OpenGL中,常用的光照模型有环境光、漫反射光和镜面光。 1. 环境光照:环境光是指场景中无处不在的均匀光照,使得对象不会完全黑暗。为了使用环境光,我们需要设置环境光强度和环境光颜色。通过设置glLightfv函数中的GL_LIGHT_MODEL_AMBIENT参数来实现,例如:glLightfv(GL_LIGHT_MODEL_AMBIENT, GL_AMBIENT, ambientLightColor); 2. 漫反射光照:漫反射光照是指光源照射到物体表面后,根据光线入射角和表面法线的夹角来计算反射光照。为了使用漫反射光,我们需要设置光源位置和光源的强度和颜色,以及模型表面的法线向量。通过设置glLightfv函数中的GL_POSITION、GL_DIFFUSE和glNormal3f函数来实现,例如:glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLightColor);glNormal3f(objModelNormals[i].x, objModelNormals[i].y, objModelNormals[i].z); 3. 镜面光照:镜面光照是指光源照射到物体表面后,出射方向与光线入射方向相对称的反射光照。为了使用镜面光,我们需要设置视点位置、光源位置和光源的强度和颜色,以及模型表面的法线向量和视点方向。通过设置glLightfv函数中的GL_POSITION、GL_DIFFUSE、GL_SPECULAR和glNormal3f函数来实现,例如:glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLightColor);glLightfv(GL_LIGHT0, GL_SPECULAR, specularLightColor);glNormal3f(objModelNormals[i].x, objModelNormals[i].y, objModelNormals[i].z);glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); 通过以上三种光照模型的设置,我们可以给导入的.obj模型增加光照效果。可以根据模型的具体需求,调整光源的位置、强度和颜色,以及模型表面的法线向量和视点方向,来获得想要的光照效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值