您的位置:首页 > 运维架构

opengl中使用多重纹理

2017-07-27 12:11 330 查看
两个原始纹理





混合后的效果图



顶点shader

attribute vec3 pos;
attribute vec2 texcoord;
attribute vec3 normal;

uniform mat4 M;
uniform mat4 P;
uniform mat4 V;

varying vec2 V_Texcoord;
void main()
{
V_Texcoord=texcoord;
gl_Position=P*V*M*vec4(pos,1.0);
}

片元shader
varying vec2 V_Texcoord;
uniform sampler2D U_MainTexture;
uniform sampler2D U_Wood;
void main()
{
gl_FragColor=texture2D(U_MainTexture,V_Texcoord)*0.8+texture2D(U_Wood,V_Texcoord)*0.8;
}


程序入口
#include <windows.h>
#include "glew.h"
#include <stdio.h>
#include <math.h>
#include "utils.h"
#include "GPUProgram.h"
#include "ObjModel.h"
#include "Glm/glm.hpp"
#include "Glm/ext.hpp"
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glew32.lib")

LRESULT CALLBACK GLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,msg,wParam,lParam);
}

float* CreatePerspective(float fov, float aspect, float zNear, float zFar)
{
float *matrix = new float[16];
float half = fov / 2.0f;
float randiansOfHalf = (half / 180.0f)*3.14f;
float yscale = cosf(randiansOfHalf) / sinf(randiansOfHalf);
float xscale = yscale / aspect;
memset(matrix, 0, sizeof(float) * 16);
matrix[0] = xscale;
matrix[5] = yscale;
matrix[10] = (zNear + zFar) / (zNear - zFar);
matrix[11] = -1.0f;
matrix[14] = (2.0f*zNear*zFar) / (zNear - zFar);
return matrix;
}

INT WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
WNDCLASSEX wndClass;
wndClass.cbClsExtra = 0;
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = NULL;
wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndClass.hIcon = NULL;
wndClass.hIconSm = NULL;
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc=GLWindowProc;
wndClass.lpszClassName = L"OpenGL";
wndClass.lpszMenuName = NULL;
wndClass.style = CS_VREDRAW | CS_HREDRAW;
ATOM atom = RegisterClassEx(&wndClass);

HWND hwnd = CreateWindowEx(NULL, L"OpenGL", L"RenderWindow", WS_OVERLAPPEDWINDOW, 100, 100, 800, 600, NULL, NULL, hInstance, NULL);
HDC dc = GetDC(hwnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_TYPE_RGBA | PFD_DOUBLEBUFFER;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;

int pixelFormatID = ChoosePixelFormat(dc, &pfd);

SetPixelFormat(dc,pixelFormatID,&pfd);

HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);

glewInit();//初始化环境
//创建两个纹理
GLuint mainTexture = CreateTextureFromFile("Debug/res/image/test.bmp");
GLuint woodTexture = CreateTextureFromFile("Debug/res/image/wood.bmp");
//初始化并编译shader
GPUProgram gpuProgram;
gpuProgram.AttachShader(GL_VERTEX_SHADER, "Debug/res/shader/sample.vs");
gpuProgram.AttachShader(GL_FRAGMENT_SHADER, "Debug/res/shader/sample.fs");
gpuProgram.Link();

//获取shader中变量的引用
gpuProgram.DetectAttribute("pos");
gpuProgram.DetectAttribute("texcoord");
gpuProgram.DetectAttribute("normal");
gpuProgram.DetectUniform("M");
gpuProgram.DetectUniform("V");
gpuProgram.DetectUniform("P");
gpuProgram.DetectUniform("U_MainTexture");
gpuProgram.DetectUniform("U_Wood");
//加载并解析3D模型
ObjModel model;
model.Init("Debug/res/model/Cube.obj");
//单位矩阵 作为View矩阵
float identity[] = {
1.0f,0,0,0,
0,1.0f,0,0,
0,0,1.0f,0,
0,0,0,1.0f
};
float M[] = {
1.0f,0,0,0,
0,1.0f,0,0,
0,0,1.0f,0,
0,0,-2.0f,1.0f
};
//模型矩阵
glm::mat4 modelMatrix = glm::translate<float>(0.0f,0.0f,-2.0f)*glm::rotate<float>(-30.0f,0.0f,1.0f,1.0f);
//创建投影矩阵
float *projection = CreatePerspective(50.0f,800.0f/600.0f,0.1f,1000.0f);

glClearColor(41.0f/255.0f, 71.0f/255.0f, 121.0f / 255.0f, 1.0f);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);

MSG msg;
while (true)
{
if (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
{
if (msg.message==WM_QUIT)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//清除颜色缓冲深度缓冲
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//启用深度缓冲
glEnable(GL_DEPTH_TEST);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//启用shader
glUseProgram(gpuProgram.mProgram);

//给shader中的MVP矩阵分别设置值
glUniformMatrix4fv(gpuProgram.GetLocation("M"), 1,GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(gpuProgram.GetLocation("V"), 1, GL_FALSE, identity);
glUniformMatrix4fv(gpuProgram.GetLocation("P"), 1, GL_FALSE, projection);

glActiveTexture(GL_TEXTURE0);//激活0号纹理
glBindTexture(GL_TEXTURE_2D, mainTexture);//绑定0号纹理
glUniform1i(gpuProgram.GetLocation("U_MainTexture"),0);//将0号纹理绑定到shader中的纹理变量

glActiveTexture(GL_TEXTURE1);//激活1号纹理
glBindTexture(GL_TEXTURE_2D,woodTexture);//绑定1号纹理
glUniform1i(gpuProgram.GetLocation("U_Wood"),1);//将1号纹理绑定到shader中的纹理变量

model.Bind(gpuProgram.GetLocation("pos"), gpuProgram.GetLocation("texcoord"), gpuProgram.GetLocation("normal"));
model.Draw();

glUseProgram(0);
glFinish();
SwapBuffers(dc);
}
return 0;
}模型解析
#include "ObjModel.h"
#include "utils.h"
#include <stdio.h>
#include <sstream>
#include <string>
#include <vector>

void ObjModel::Init(const char*modelFilePath)
{
struct VertexInfo
{
float v[3];
VertexInfo()
{
memset(v, 0, sizeof(float) * 3);
}
};

struct VertexDefine
{
int positionIndex;
int texcoordIndex;
int normalIndex;
};
std::vector<VertexInfo> positions;
std::vector<VertexInfo> texcoords;
std::vector<VertexInfo> normals;

std::vector<VertexDefine> vertices;
std::vector<unsigned int> faces;

//load model from file
char*fileContent = LoadFileContent(modelFilePath);
//decode model
std::stringstream ssFileContent(fileContent);
char szOneLine[256];
std::string temp;
while (!ssFileContent.eof())
{
memset(szOneLine, 0, 256);
ssFileContent.getline(szOneLine, 256);
if (strlen(szOneLine)>0)
{
std::stringstream ssOneLine(szOneLine);
if (szOneLine[0]=='v')
{
if (szOneLine[1]=='t')
{
VertexInfo vi;
ssOneLine >> temp;//vt
ssOneLine >> vi.v[0];
ssOneLine >> vi.v[1];
texcoords.push_back(vi);
}
else if (szOneLine[1]=='n')
{
VertexInfo vi;
ssOneLine >> temp;//vn
ssOneLine >> vi.v[0];
ssOneLine >> vi.v[1];
ssOneLine >> vi.v[2];
normals.push_back(vi);
}
else
{
VertexInfo vi;
ssOneLine >> temp;//v
ssOneLine >> vi.v[0];
ssOneLine >> vi.v[1];
ssOneLine >> vi.v[2];
positions.push_back(vi);
}
}
else if(szOneLine[0]=='f')
{
//
ssOneLine >> temp;//f
std::string vertexStr;
for (int i = 0; i < 3; ++i)
{
ssOneLine >> vertexStr;
size_t pos = vertexStr.find_first_of('/');
std::string positionIndexStr = vertexStr.substr(0, pos);
size_t pos2 = vertexStr.find_first_of('/', pos + 1);
std::string texcoordIndexStr = vertexStr.substr(pos + 1, pos2 - pos - 1);
std::string normalIndexStr = vertexStr.substr(pos2 + 1, vertexStr.length() - pos2 - 1);
VertexDefine vd;
vd.positionIndex = atoi(positionIndexStr.c_str())-1;
vd.texcoordIndex = atoi(texcoordIndexStr.c_str())-1;
vd.normalIndex = atoi(normalIndexStr.c_str())-1;
//trim the same vertice
int nCurrentVertexIndex = -1;
size_t nCurrentVerticeCount = vertices.size();
for(int j=0;j<nCurrentVerticeCount;++j)
{
if (vertices[j].positionIndex==vd.positionIndex&&
vertices[j].texcoordIndex == vd.texcoordIndex&&
vertices[j].normalIndex == vd.normalIndex)
{
nCurrentVertexIndex = j;
break;
}
}
if (nCurrentVertexIndex==-1)
{
nCurrentVertexIndex = (int)vertices.size();
vertices.push_back(vd);
}
faces.push_back(nCurrentVertexIndex);
}
}
}
}
//convert to opengl vbo & ibo
int vertexCount = (int)vertices.size();
VertexData*vertexes = new VertexData[vertexCount];
for (int i=0;i<vertexCount;++i)
{
memcpy(vertexes[i].position, positions[vertices[i].positionIndex].v, sizeof(float) * 3);
memcpy(vertexes[i].texcoord, texcoords[vertices[i].texcoordIndex].v, sizeof(float) * 2);
memcpy(vertexes[i].normal, normals[vertices[i].normalIndex].v, sizeof(float) * 3);
}
//create vbo
glGenBuffers(1, &mVBO);
glBindBuffer(GL_ARRAY_BUFFER, mVBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(VertexData)*vertexCount,vertexes,GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
delete vertexes;

//ibo
mIndexCount = (int)faces.size();
unsigned int *indexes = new unsigned int[mIndexCount];
for (int i=0;i<mIndexCount;++i)
{
indexes[i] = faces[i];
}
glGenBuffers(1, &mIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*mIndexCount, indexes, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
delete indexes;

delete fileContent;
}

void ObjModel::Bind(GLint posLoc, GLint texcoordLoc, GLint normalLoc)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBO);//绑定到VBO
glEnableVertexAttribArray(posLoc);//启用顶点属性
glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), 0);//设置读取模型顶点的起始地址

glEnableVertexAttribArray(texcoordLoc);//启用顶点纹理属性
//设置纹理数据的起始地址
glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)(sizeof(float) * 3));

glEnableVertexAttribArray(normalLoc);//启用顶点法线属性
//设置读取法线的起始地址
glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)(sizeof(float) * 5));
glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void ObjModel::Draw()
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIBO);
glDrawElements(GL_TRIANGLES, mIndexCount, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

工具类
#include <stdio.h>
#include <windows.h>
#include "utils.h"

char* LoadFileContent(const char*path)
{
char *pFileContent = NULL;
FILE*pFile = fopen(path, "rb");
if (pFile)
{
fseek(pFile, 0, SEEK_END);
int nLen = ftell(pFile);
if (nLen > 0)
{
rewind(pFile);
pFileContent = new char[nLen + 1];
fread(pFileContent, 1, nLen, pFile);
pFileContent[nLen] = '\0';
}
fclose(pFile);
}
return pFileContent;
}

unsigned char* LoadBMP(const char*path, int &width, int &height)
{
unsigned char*imageData = nullptr;
FILE *pFile = fopen(path, "rb");
if (pFile)
{
BITMAPFILEHEADER bfh;
fread(&bfh, sizeof(BITMAPFILEHEADER), 1, pFile);
if (bfh.bfType == 0x4D42)
{
BITMAPINFOHEADER bih;
fread(&bih, sizeof(BITMAPINFOHEADER), 1, pFile);
width = bih.biWidth;
height = bih.biHeight;
int pixelCount = width*height * 3;
imageData = new unsigned char[pixelCount];
fseek(pFile, bfh.bfOffBits, SEEK_SET);
fread(imageData, 1, pixelCount, pFile);

unsigned char temp;
for (int i = 0; i < pixelCount; i += 3)
{
temp = imageData[i + 2];
imageData[i + 2] = imageData[i];
imageData[i] = temp;
}
}
fclose(pFile);
}
return imageData;
}

GLuint CreateTextureFromFile(const char*filePath)
{
unsigned char*imageData;
int width, height;
imageData = LoadBMP(filePath,width,height);

GLuint texture;
glGenTextures(1, &texture);//创建一个纹理
glBindTexture(GL_TEXTURE_2D,texture);//绑定
//GL_TEXTURE_WRAP系列参数用来设置当这些超出边界时应该怎样处理
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
//当摄像机离物体的距离发生变化时,纹理内容的插值方式
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//将纹理内容上传至GPU
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
imageData
);
glBindTexture(GL_TEXTURE_2D,0);
return texture;

}

shader加载编译类
#include "GPUProgram.h"
#include "utils.h"
#include <stdio.h>

GLuint CompileShader(const char*shaderPath, GLenum shaderType)
{
GLuint shader = glCreateShader(shaderType);
const char* code = LoadFileContent(shaderPath);
if (code == nullptr)
{
printf("cannot load shader source from file %s\n", shaderPath);
return 0;
}
glShaderSource(shader, 1, &code, nullptr);//ram -> vram
glCompileShader(shader);
GLint nResult;
glGetShaderiv(shader, GL_COMPILE_STATUS, &nResult);
if (nResult == GL_FALSE)
{
printf("compile shader %s fail\n", shaderPath);
GLint logLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
char*log = new char[logLength];
GLsizei writed = 0;
glGetShaderInfoLog(shader, logLength, &writed, log);
printf("%s\n", log);
delete log;
glDeleteShader(shader);
return 0;
}
return shader;
}

GPUProgram::GPUProgram()
{
mProgram = glCreateProgram();
}

GPUProgram::~GPUProgram()
{

}

void GPUProgram::AttachShader(GLenum shaderType, const char*shaderPath)
{
GLuint shader = CompileShader(shaderPath, shaderType);
if (shader!=0)
{
glAttachShader(mProgram, shader);
mAttachedShaders.push(shader);
}
}

void GPUProgram::Link()
{
glLinkProgram(mProgram);
GLint nResult;
glGetProgramiv(mProgram, GL_LINK_STATUS, &nResult);
if (nResult == GL_FALSE)
{
printf("create gpu program fail,link error\n");
GLint logLength;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &logLength);
char*log = new char[logLength];
GLsizei writed = 0;
glGetProgramInfoLog(mProgram, logLength, &writed, log);
printf("%s\n", log);
delete log;
glDeleteProgram(mProgram);
mProgram = 0;
}
while (!mAttachedShaders.empty())
{
GLuint shader = mAttachedShaders.top();
glDetachShader(mProgram, shader);
glDeleteShader(shader);
mAttachedShaders.pop();
}
}

void GPUProgram::DetectAttribute(const char*attributeName)
{
GLint loc = glGetAttribLocation(mProgram, attributeName);
if (loc!=-1)
{
mLocations.insert(std::pair<std::string,GLint>(attributeName,loc));
}
}

void GPUProgram::DetectUniform(const char*uniformName)
{
GLint loc = glGetUniformLocation(mProgram, uniformName);
if (loc != -1)
{
mLocations.insert(std::pair<std::string, GLint>(uniformName, loc));
}
}

GLint GPUProgram::GetLocation(const char*name)
{
auto iter = mLocations.find(name);
if (iter ==mLocations.end())
{
return -1;
}
return iter->second;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: