学习OpenGL ES for Android(二十三)— 立方体贴图

╰+攻爆jí腚メ 2023-06-30 09:23 213阅读 0赞

我们前面学过纹理贴图,我们可以用6个2D纹理的纹理构建成立方体,而立方体贴图本身就是包含6个2D纹理的纹理,它优势在于可以通过一个方向向量来进行索引/采样。只要在立方体贴图的中心点,就能使用立方体的实际位置向量来对立方体贴图进行采样。

创建立方体贴图

与2D纹理区别不大,创建立方体贴图同样是创建纹理,只是我们的glBindTexture的方法的参数要变为GLES20.GL_TEXTURE_CUBE_MAP,然后同样要处理环绕和过滤方式。与2D纹理不同的是,它需要用6张图片来分别设置立方体的六个面,同样是使用GLUtils.texImage2D方法,它的target参数如下表


































纹理目标 方位
GL_TEXTURE_CUBE_MAP_POSITIVE_X
GL_TEXTURE_CUBE_MAP_NEGATIVE_X
GL_TEXTURE_CUBE_MAP_POSITIVE_Y
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
GL_TEXTURE_CUBE_MAP_POSITIVE_Z
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z

我们把创建立方体贴图的同样封装一下,代码如下

  1. /**
  2. * 立方体贴图
  3. * @param context context
  4. * @param resIds 贴图集合,顺序是:
  5. * <ul><li>右{@link GLES20#GL_TEXTURE_CUBE_MAP_POSITIVE_X}</li>
  6. * <li>左{@link GLES20#GL_TEXTURE_CUBE_MAP_NEGATIVE_X}</li>
  7. * <li>上{@link GLES20#GL_TEXTURE_CUBE_MAP_POSITIVE_Y}</li>
  8. * <li>下{@link GLES20#GL_TEXTURE_CUBE_MAP_NEGATIVE_Y}</li>
  9. * <li>后{@link GLES20#GL_TEXTURE_CUBE_MAP_POSITIVE_Z}</li>
  10. * <li>前{@link GLES20#GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}</li></ul>
  11. * @return int
  12. */
  13. public static int createTextureCube(Context context, int[] resIds) {
  14. if (resIds != null && resIds.length >= 6) {
  15. int[] texture = new int[1];
  16. //生成纹理
  17. GLES20.glGenTextures(1, texture, 0);
  18. checkGlError("glGenTexture");
  19. //生成纹理
  20. GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, texture[0]);
  21. GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
  22. GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
  23. GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
  24. GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
  25. if (OpenGLVersion > 2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
  26. GLES20.glTexParameteri(GLES20.GL_TEXTURE_CUBE_MAP, GLES30.GL_TEXTURE_WRAP_R, GLES20.GL_CLAMP_TO_EDGE);
  27. }
  28. Bitmap bitmap;
  29. final BitmapFactory.Options options = new BitmapFactory.Options();
  30. options.inScaled = false;
  31. for (int i = 0; i < resIds.length; i++) {
  32. bitmap = BitmapFactory.decodeResource(context.getResources(),
  33. resIds[i], options);
  34. if (bitmap == null) {
  35. LogUtil.w("Resource ID " + resIds[i] + " could not be decoded.");
  36. GLES20.glDeleteTextures(1, texture, 0);
  37. return 0;
  38. }
  39. GLUtils.texImage2D(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, bitmap, 0);
  40. bitmap.recycle();
  41. }
  42. GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
  43. return texture[0];
  44. }
  45. return 0;
  46. }

着色器的代码同样需要修改,我们需要使用samplerCube接收我们的立方体贴图,使用textureCube来生成立方体贴图,同样的我们需要定义六个面的顶点坐标和纹理坐标。片段着色器的代码如下

  1. precision mediump float;
  2. varying vec3 TexCoord; // 代表3D纹理坐标的方向向量
  3. uniform samplerCube skybox; // 立方体贴图的纹理采样器
  4. void main() {
  5. gl_FragColor = textureCube(skybox, TexCoord);
  6. }

天空盒

想象一下我们创建好一个立方体贴图,我们把视角设置在立方体贴图的中间,这时我们移动视角方向,就像是在一个立方体的房间内向各个方向观望。我们可以在这个网站(http://www.custommapmakers.org/skyboxes.php)上找到各种素材,暂时我们使用下面的六张图片实现立方体贴图,

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2prbHdhbg_size_16_color_FFFFFF_t_70

然后绘制一个盒子放到我们的视角内,关键的代码如下

  1. @Override
  2. public void onDrawFrame(GL10 gl) {
  3. super.onDrawFrame(gl);
  4. drawTexture();
  5. GLES20.glDepthFunc(GLES20.GL_LEQUAL);
  6. drawSkyBox();
  7. GLES20.glDepthFunc(GLES20.GL_LESS);
  8. }

此时的效果如下图,

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2prbHdhbg_size_16_color_FFFFFF_t_70 1

我们想要移动我们的视角,使用触摸事件的话有些繁琐了,这里我们使用手机自带的传感器中的旋转矢量功能,我们移动手机就能移动在天空盒中移动视角。在onSensorChanged中使用getRotationMatrixFromVector将旋转矢量转换为旋转矩阵,随后传入我们的Renderer中计算即可。源码地址https://github.com/jklwan/OpenGLProject/blob/master/sample/src/main/java/com/chends/opengl/renderer/advanced/opengl/CubeMapsRenderer.java,可以自己测试效果。本章对应文档https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/06%20Cubemaps/。

发表评论

表情:
评论列表 (有 0 条评论,213人围观)

还没有评论,来说两句吧...

相关阅读