OpenGL进阶04.支持多贴图的Shader

Posted stq_wyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL进阶04.支持多贴图的Shader相关的知识,希望对你有一定的参考价值。

这篇文章来实现一下多贴图的效果。在这篇文章中,再次对代码进行了封装,是代码看起来更加清晰明了:

shader.h中添加了SetTexture接口:

#pragma once
#include "ggl.h"
struct UniformTexture 
{
	GLint mLocation;
	GLuint mTexture;
	UniformTexture()
	{
		mLocation = -1;
		mTexture = 0;
	}
};
class Shader
{
public:
	GLuint mProgram;
	std::map<std::string, UniformTexture*>mUniformTextures;
	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);
};

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

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

vertexbuffer.h中添加了Bind()和UnBind()接口

#pragma once
#include "ggl.h"
struct Vertex
{
	float Position[4];
	float Color[4];
	float Texcoord[4];
	float Normal[4];
};

class VertexBuffer {
public:
	Vertex* mVertexes;
	int mVertexCount;
	GLuint mVBO;
	void SetSize(int vertexCount);
	void SetPosition(int index, float x, float y, float z, float w = 1.0f);
	void SetColor(int index, float r, float g, float b, float a = 1.0f);
	void SetTexcoord(int index, float x, float y);
	void SetNormal(int index, float x, float y, float z);
	void Bind();
	void UnBind();
	Vertex& Get(int index);
};

vertexbuffer.cpp:

#include "vertexbuffer.h"
#include "Utils.h"

void VertexBuffer::SetSize(int vertexCount)
{
	mVertexCount = vertexCount;
	mVertexes = new Vertex[mVertexCount];
	memset(mVertexes, 0, sizeof(Vertex) * mVertexCount);
	mVBO = CreateBufferObject(GL_ARRAY_BUFFER, sizeof(Vertex) * mVertexCount, GL_STATIC_DRAW, nullptr);
}

void VertexBuffer::SetPosition(int index, float x, float y, float z, float w /* = 1.0f */)
{
	mVertexes[index].Position[0] = x;
	mVertexes[index].Position[1] = y;
	mVertexes[index].Position[2] = z;
	mVertexes[index].Position[3] = w;
}

void VertexBuffer::SetColor(int index, float r, float g, float b, float a /* = 1.0f */)
{
	mVertexes[index].Color[0] = r;
	mVertexes[index].Color[1] = g; 
	mVertexes[index].Color[2] = b;
	mVertexes[index].Color[3] = a;
}

void VertexBuffer::SetTexcoord(int index, float x, float y)
{
	mVertexes[index].Texcoord[0] = x;
	mVertexes[index].Texcoord[1] = y;
}

void VertexBuffer::SetNormal(int index, float x, float y, float z)
{
	mVertexes[index].Normal[0] = x;
	mVertexes[index].Normal[1] = y;
	mVertexes[index].Normal[2] = z;
	mVertexes[index].Normal[3] = 1.0;
}

void VertexBuffer::Bind()
{
	glBindBuffer(GL_ARRAY_BUFFER, mVBO);
	glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * mVertexCount, mVertexes);
}

void VertexBuffer::UnBind()
{
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

Vertex& VertexBuffer::Get(int index)
{
	return mVertexes[index];
}

看下shader的变化

test.vs:

attribute vec4 position;
attribute vec4 color;
attribute vec2 texcoord;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
varying vec4 V_Color;
varying vec2 V_Texcoord;

void main()
{
    V_Color = color;
    V_Texcoord = texcoord;
    gl_Position = ProjectionMatrix*ViewMatrix*ModelMatrix*position;
}

test.fs:

#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D U_Texture;
uniform sampler2D U_Texture2;
varying vec4 V_Color;
varying vec2 V_Texcoord;

void main()
{
    gl_FragColor = V_Color*texture2D(U_Texture,V_Texcoord)*texture2D(U_Texture2,V_Texcoord);
}

最后看下Scene.cpp里的调用,代码是不是清爽了许多:

#include "scene.h"
#include "ggl.h"
#include "Utils.h"
#include "ground.h"
#include "shader.h"

GLuint texture;
glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
Ground ground;
Shader* shader;
VertexBuffer* vertexBuffer;

void Init()
{
	vertexBuffer = new VertexBuffer;
	vertexBuffer->SetSize(3);
	vertexBuffer->SetPosition(0, -0.2f, -0.2f, 0.0f);
	vertexBuffer->SetTexcoord(0, 0.0f, 0.0f);
	vertexBuffer->SetColor(0, 1.0f, 1.0f, 1.0f);
	vertexBuffer->SetPosition(1, 0.2f, -0.2f, 0.0f);
	vertexBuffer->SetTexcoord(1, 1.0f, 0.0f);
	vertexBuffer->SetColor(1, 1.0f, 0.0f, 0.0f, 0.0f);
	vertexBuffer->SetPosition(2, 0.0f, 0.2f, 0.0f);
	vertexBuffer->SetTexcoord(2, 0.5f, 1.0f);
	vertexBuffer->SetColor(2, 0.0f, 1.0f, 0.0f);

	shader = new Shader;

	shader->Init("Res/test.vs", "Res/test.fs");
	shader->SetTexture("U_Texture", "Res/test.bmp");
	shader->SetTexture("U_Texture2", "Res/test2.bmp");
	modelMatrix = glm::translate(0.0f, 0.0f, -0.6f);
	ground.Init();
}

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);
	vertexBuffer->Bind();
	shader->Bind(glm::value_ptr(modelMatrix), glm::value_ptr(viewMatrix), glm::value_ptr(projectionMatrix));
	glDrawArrays(GL_TRIANGLES, 0, 3);
	vertexBuffer->UnBind();
}

看下三角形两个纹理叠加的效果吧:

以上是关于OpenGL进阶04.支持多贴图的Shader的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL进阶04.支持多贴图的Shader

我的OpenGL学习进阶之旅 C++ 长行字符串多行书写的方法以及如何书写正确的OpenGL Shader着色器代码

OpenGL进阶01.使用Shader绘制三角形

我的OpenGL学习进阶之旅 C++ 长行字符串多行书写的方法以及如何书写正确的OpenGL Shader着色器代码

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

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