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.为模型添加光照和贴图的主要内容,如果未能解决你的问题,请参考以下文章