天空盒Get知识点:
- 1、立方体贴图是和其它纹理一样的,所以如果想创建一个立方体贴图的话,我们需要生成一个纹理,并将其绑定到纹理目标上,之后再做其它的纹理操作。这次要绑定到GL_TEXTURE_CUBE_MAP:
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
因为立方体贴图包含有6个纹理,每个面一个,我们需要调用glTexImage2D函数6次,参数和之前教程中很类似。但这一次我们将纹理目标(target)参数设置为立方体贴图的一个特定的面,告诉OpenGL我们在对立方体贴图的哪一个面创建纹理。这就意味着我们需要对立方体贴图的每一个面都调用一次glTexImage2D。
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
设定它的环绕和过滤方式:
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
2.1、天空盒绘制优化:
先渲染天空盒,之后再渲染场景中的其它物体。这样子能够工作,但不是非常高效。如果我们先渲染天空盒,我们就会对屏幕上的每一个像素运行一遍片段着色器,即便只有一小部分的天空盒最终是可见的。可以使用提前深度测试.所以,最后渲染天空盒,以获得轻微的性能提升。这样子的话,深度缓冲就会填充满所有物体的深度值了,我们只需要在提前深度测试通过的地方渲染天空盒的片段就可以了,很大程度上减少了片段着色器的调用. -
2.2、天空盒顶点着色器:
attribute vec3 aPos;
uniform mat4 projectionM;
uniform mat4 modelViewM;
varying lowp vec3 outTextCoord;
void main(){
outTextCoord = aPos;
vec4 pos = projectionM * modelViewM * vec4(aPos,1.0);
//gl_Position = pos.xyww; //透视除法的应用
//需要通过多边形偏移解决 边界闪烁的问题 (下面那个0.99是可以不乘的,而直接使用gl_Position = pos.xyww;),再查一下
gl_Position = vec4(pos.x,pos.y,pos.w*0.99,pos.w);
}
- 3、天空盒片段着色器:
varying lowp vec3 outTextCoord;
uniform samplerCube boxTexture;
void main(){
//gl_FragColor = vec4(0.2,0.2,0.3,1.0);
gl_FragColor = textureCube(boxTexture,outTextCoord);
}
- 4、纹理加载:
#pragma mark - cubeShafer
+(GLuint)loadCubeTextureWithImageNames:(NSArray*)fileNames
{
//glActiveTexture(tex);
GLuint textId ;
glGenTextures(1, &textId);
//绑定纹理
glBindTexture(GL_TEXTURE_CUBE_MAP, textId);
[self glCheckError];
for (int i = 0; i < fileNames.count; ++i) {
NSString* fileName = fileNames[I];
size_t width,height;
GLubyte *spriteData = [self getImageData:fileName width:&width height:&height];
float fw = width,fh = height;
if (spriteData) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i , 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
//绑定纹理
//glBindTexture(GL_TEXTURE_2D, 0);
free(spriteData);
} else {
NSLog(@"立方体纹理加载错误---- ");
}
}
[self glCheckError];
//设置纹理的相关参数
//参数不记得的同学,可以回顾一下OpenGL中的纹理课程
//放大过滤器,缩小过滤器
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
[self glCheckError];
return textId;
}
- 5、绘制
- (void)draw{
glViewport(0, 0, _viewWidth,_viewHeight);
glUseProgram(self.myProgram);
//先绘制盒子 填充深度缓冲区
glBindVertexArray(self.blackBoxVAO);
glBindTexture(GL_TEXTURE_2D, self.textId);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
[ZKLodaShader glCheckError];
//再绘制天空盒 判断天空盒的深度缓冲区小于等于 当前深度缓冲区值,才比较通过。
//结果就是天空盒只会在没有可见物体的地方渲染了(只有这样才能通过深度测试,其它所有的东西都在天空盒前面)
glDepthFunc(GL_LEQUAL);
glPolygonOffset(1.0, 1.0);
glUseProgram(self.skyBoxProgram);
glBindVertexArray(self.VAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, self.cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
[ZKLodaShader glCheckError];
glDepthFunc(GL_LESS);
if (_myColorRenderBuffer) {
glBindRenderbuffer(GL_RENDERBUFFER, _myColorRenderBuffer);
}
//绘制
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
glDeleteVertexArrays(1,&_VAO);
glDeleteVertexArrays(1, &_blackBoxVAO);
}
-
6、效果
天空盒.gif
反射
折射
这两个等哪天心情好了在写,又懒了,这样不好_。
网友评论