这篇文章基于上一篇的基础上,为三角形添加纹理贴图。首先我们要解码bmp文件,然后创建纹理对象,再将bmp数据转化成2D贴图,贴到三角形上。
在Utils.h中添加所需接口:
#pragma once
#include "ggl.h"
unsigned char* LoadFileContent(const char* path, int& filesize);
GLuint CompileShader(GLenum shaderType, const char* shaderCode);
GLuint CreateProgram(GLuint vsShader, GLuint fsShader);
float GetFrameTime();
//解码
unsigned char* DecodeBMP(unsigned char* bmpFileData, int& width, int& height);
GLuint CreateTexture2D(unsigned char* pixelData, int width, int height, GLenum type);
GLuint CreateTexture2DFromBMP(const char* bmpPath);
Utils.cpp中实现上述新添加的3个接口:
//解码BMP
unsigned char* DecodeBMP(unsigned char* bmpFileData, int& width, int& height)
{
if (0x4D42 == *((unsigned short*)bmpFileData))
{
int pixelDataOffset = *((int*)(bmpFileData + 10));
width = *((int*)(bmpFileData + 18));
height = *((int*)(bmpFileData + 22));
unsigned char* pixelData = bmpFileData + pixelDataOffset;
for (int i=0;i<width*height*3;i+=3)
{
unsigned char temp = pixelData[i];
pixelData[i] = pixelData[i + 2];
pixelData[i + 2] = temp;
}
return pixelData;
}
return nullptr;
}
//创建纹理对象
GLuint CreateTexture2D(unsigned char* pixelData, int width, int height, GLenum type)
{
GLuint texture;
glGenTextures(1, &texture);
//设置纹理对象
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//像素数据传到显卡
glTexImage2D(GL_TEXTURE_2D, 0, type, width, height, 0, type, GL_UNSIGNED_BYTE, pixelData);
glBindTexture(GL_TEXTURE_2D, 0);
return texture;
}
//从bmp创建texture
GLuint CreateTexture2DFromBMP(const char* bmpPath)
{
int nFileSize = 0;
unsigned char* bmpFileContent = LoadFileContent(bmpPath, nFileSize);
if (bmpFileContent == nullptr)
{
return 0;
}
int bmpWidth = 0, bmpHeight = 0;
unsigned char* pixelData = DecodeBMP(bmpFileContent, bmpWidth, bmpHeight);
if (bmpWidth == 0)
{
delete bmpFileContent;
return 0;
}
GLuint texture = CreateTexture2D(pixelData, bmpWidth, bmpHeight, GL_RGB);
delete bmpFileContent;
return texture;
}
scene.cpp中添加所需要的数据:
#include "scene.h"
#include "ggl.h"
#include "Utils.h"
GLuint vbo,ebo;
GLuint program;
GLint positionLocation, modelMatrixLocation, viewMatrixLocation, projectionMatrixLocation,colorLocation;
GLuint texcoordLocation, textureLocation;
GLuint texture;
glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
void Init()
{
float data[] = {
-0.2f,-0.2f,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,
0.2f,-0.2f,0.0f,1.0f,0.0f,1.0f,0.0f,1.0f,1.0f,0.0f,
0.0f,0.2f,0.0f,1.0f,1.0f,0.0f,0.0f,1.0f,0.5f,1.0f
};
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 30, data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unsigned short indexes[] = { 0,1,2 };
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * 3, indexes, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
int fileSize = 0;
//读取shader代码
unsigned char* shaderCode = LoadFileContent("Res/test.vs", fileSize);
GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char*)shaderCode);
delete shaderCode;
shaderCode = LoadFileContent("Res/test.fs", fileSize);
GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, (char*)shaderCode);
delete shaderCode;
program = CreateProgram(vsShader, fsShader);
glDeleteShader(vsShader);
glDeleteShader(fsShader);
//获取shader中的变量
positionLocation = glGetAttribLocation(program, "position");
colorLocation = glGetAttribLocation(program, "color");
texcoordLocation = glGetAttribLocation(program, "texcoord");
modelMatrixLocation = glGetUniformLocation(program, "ModelMatrix");
viewMatrixLocation = glGetUniformLocation(program, "ViewMatrix");
projectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
textureLocation = glGetUniformLocation(program, "U_Texture");
modelMatrix = glm::translate(0.0f, 0.0f, -0.6f);
texture = CreateTexture2DFromBMP("Res/test.bmp");
}
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);
glUseProgram(program);
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(textureLocation, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 10, 0);
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 10, (void*)(sizeof(float)*4));
glEnableVertexAttribArray(texcoordLocation);
glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 10, (void*)(sizeof(float) * 8));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
main.cpp中无文件变化,接下来看下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;
varying vec4 V_Color;
varying vec2 V_Texcoord;
void main()
{
gl_FragColor = V_Color*texture2D(U_Texture,V_Texcoord);
}
话不多说,看结果: