OpenGL纹理综合案例
2020-07-21 本文已影响0人
大橘猪猪侠
之前用OpenGL做了一个关于大球公转,小球自转的案例,现在我们通过纹理去绘制大球小球和地板,呈现出一个有倒影的画面。
运行效果图如下:
QQ20200721-155909-HD.gif
之前没有用纹理做出来的效果可以转到另一篇博客当中。
在这篇中,我就直接写关键代码和有差别的地方,首先定义的批次类容器都是不变的。
地板的坐标之前利用的是网格呈现出来的,在这个案例中,并不需要利用网格呈现。因此直接利用四个顶点坐标去绘制纹理图片:
SetupRC函数中
GLfloat texSize = 10.0f;
floorBatch.Begin(GL_TRIANGLE_FAN, 4,1);
floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);
floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
floorBatch.Vertex3f(20.0f, -0.41f, 20.f);
floorBatch.MultiTexCoord2f(0, texSize, texSize);
floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
floorBatch.End();
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
LoadTGATexture("Marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
LoadTGATexture("Marslike.tga", GL_LINEAR_MIPMAP_LINEAR,
GL_LINEAR, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
LoadTGATexture("Moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,
GL_LINEAR, GL_CLAMP_TO_EDGE);
然后我们需要设置纹理个数,读取纹理图片,设置纹理参数,载入纹理和释放纹理。
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode){
GLbyte *pBits;
int nWidth,nHeight,nComponets;
GLenum eFormat;
//1.读取纹理数据
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponets, &eFormat);
if(pBits == NULL)
return false;
//2、设置纹理参数
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
//3.载入纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
//使用完毕释放pBits
free(pBits);
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
//4.加载Mip,纹理生成所有的Mip层
//参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
在RenderScene函数中,需要渲染场景,由于大球小球需要转动,因此还是需要计时器而要做出有倒影的效果,又该如何实现呢?
首先可以将大球小球的画面封装成一个函数,下面这个函数利用点光源纹理着色器去绘制大球和小球。
void drawSomething(GLfloat yRot){
static GLfloat vWhite[] = {1.0f,1.0f,1.0f,1.0f};
static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
for (int i = 0; i<NUM_SPHERES; i++) {
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vWhite,0);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
torusBatch.Draw();
modelViewMatrix.PopMatrix();
//4.绘制公转小球球(公转自转)
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightPos,
vWhite,
0);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
在绘制完大球和小球之后,回到RenderScene函数去绘制整个图形,在上面的图形当中,倒影和实物图与地面呈现出了间隙,那么我们需要利用一个单元矩阵去翻转和平移y轴距离,去实现这个效果。然而,倒影旋转的方向与实物的旋转方向要一致的,那我们就需要指定顺时针面为正面,在绘制完后,需要复原。
//单元矩阵入栈
modelViewMatrix.PushMatrix();
//翻转y轴
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
//镜面世界围绕Y轴平移一定间距
modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);
//8.指定顺时针为正面
glFrontFace(GL_CW);
//9.绘制地面以外其他部分(镜面)
drawSomething(yRot);
//10.恢复为逆时针为正面
glFrontFace(GL_CCW);
//11.绘制镜面,恢复矩阵
modelViewMatrix.PopMatrix();
//12.开启混合功能(绘制地板)
glEnable(GL_BLEND);
//13. 指定glBlendFunc 颜色混合方程式
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//14.绑定地面纹理
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor,
0);
//shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);
//开始绘制
floorBatch.Draw();
//取消混合
glDisable(GL_BLEND);
//16.绘制地面以外其他部分
drawSomething(yRot);
//17.绘制完,恢复矩阵
modelViewMatrix.PopMatrix();
这个案例在之前那个案例上增加了纹理的样式和倒影,运行的效果比之前的要好看很多。