原文地址:WebGL学习之纹理盒

我们之前已经学习过二维纹理 gl.TEXTURE_2D,而且还使用它实现了各种效果。但还有一种立方体纹理 gl.TEXTURE_CUBE_MAP,它包含了6个纹理代表立方体的6个面。不像常规的纹理坐标有2个纬度,立方体纹理使用法向量,换句话说三维方向。本节实现的demo请看 天空盒

根据法向量的朝向选取立方体6个面中的一个,这个面的像素用来采样生成颜色。这六个面通过他们相对于立方体中心的方向被引用。它们是分别是

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//前
复制代码

环境贴图

其实我们更应该把cube map叫作纹理盒,通常纹理盒不是给立方体设置纹理用的,设置立方体纹理的标准用法其实是使用二维贴图,那么纹理盒用来做什么的呢?纹理盒最常见的用法是用来做环境贴图。在百度和google地图中的3D街景就是环境贴图应用的一个例子。

纹理

下面是6张红色峡谷图片

将以上尺寸为512x512的图片填充到立方体的每个面,以下就是纹理的创建加载过程

// 创建纹理。
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);const faceInfos = [{target: gl.TEXTURE_CUBE_MAP_POSITIVE_X, url: '/img/sorbin_rt.jpg',},{target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X, url: '/img/sorbin_lf.jpg',},{target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y, url: '/img/sorbin_up.jpg',},{target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, url: '/img/sorbin_dn.jpg',},{target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z, url: '/img/sorbin_bk.jpg',},{target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, url: '/img/sorbin_ft.jpg',},
];
faceInfos.forEach((faceInfo) => {const {target, url} = faceInfo;// 上传画布到立方体贴图的每个面const level = 0;const format = gl.RGBA;const width = 512;const height = 512;const type = gl.UNSIGNED_BYTE;// 设置每个面,使其立即可渲染gl.texImage2D(target, level, format, width, height, 0, format, type, null);// 异步加载图片const image = new Image();image.src = url;image.onload = function() {// 图片加载完成将其拷贝到纹理gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);gl.texImage2D(target, level, internalFormat, format, type, image);gl.generateMipmap(gl.TEXTURE_CUBE_MAP);};
});
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
复制代码

法向量

标准立方体法向量 和 纹理盒法向量的区别

3D立方体使用纹理盒有一个巨大的好处就是不需要额外指定纹理坐标。只要盒子是被放置在世界坐标系的原点,盒子本身的坐标就可以作为纹理坐标使用,因为在3D世界中位置本身就是一个向量,表示一个方向,我们要的就是这个方向。

所以顶点着色器非常简单

attribute vec4 a_position;
uniform mat4 u_vpMatrix;
varying vec3 v_normal;void main() {gl_Position = u_vpMatrix * a_position;//因为位置是以几何中心为原点的,可以用顶点坐标作为法向量v_normal = normalize(a_position.xyz);
}
复制代码

片段着色器中我们需要用samplerCube 代替 sampler2DtextureCube代替texture2DtextureCube 需要vec3类型的向量。 法向量从顶点着色器传递过来经过了插值处理,需要重新单位化。

precision mediump float; // 从顶点着色器传入。
varying vec3 v_normal; // 纹理。
uniform samplerCube u_texture; void main() {   gl_FragColor = textureCube(u_texture, normalize(v_normal));
}
复制代码

实现

运行后得到如下的效果,很明显就能看出是个立方体,并不是我们想要的360度环绕的3D场景。

其实我们只需要将相机位置置于原点(0,0,0),同时lookAt向其中的一个面就可以了。但是在原点有个问题,如果要旋转查看场景怎么办?我们可以通过旋转相机的位置,这其实就相当于立方体旋转,同时我们不需要矩阵位移相关的信息,只需要方向相关的信息就好了。同时还可以禁止写入深度缓存,造成背景在很远的假象,让效果更加真实。

const viewPosition = new Vector3([0,0,1]);//相机位置
const lookAt = [0, 0, 0];//原点//相机绕y轴旋转
cameraMatrix.rotate(0.2,0,1,0);
viewPoint = cameraMatrix.multiplyVector3(viewPosition);
vpMatrix.setPerspective( 30, canvas.width / canvas.height, 0.1, 5 );
vpMatrix.lookAt(...viewPoint.elements, ...lookAt, 0, 1, 0);//重置位移
vpMatrix.elements[12] = 0;
vpMatrix.elements[13] = 0;
vpMatrix.elements[14] = 0;// 禁止写入深度缓存,造成背景在很远的假象
gl.depthMask(false);
复制代码

环境纹理映射

环境贴图还有个更通俗的叫法-天空盒。接着我们还要实现一个非常帅气的效果,在天空盒三维场景中,让其中的物体反射场景周围的着色。这个操作就叫做环境纹理映射(environment mapping)。

反射

如果物体的表面像光滑的镜子,那么我们就能看到物体反射出天空和周围的景色。反射的原理非常简单,那就是使用反射公式映射纹理盒对应的纹素:

相机位置(观察点)和 物体顶点的位置,顶点位置又包含着法线信息,通过GLSL的reflect函数就可以非常容易的计算反射向量R,进而确定看到的是哪一块表面的着色。

实现

我们就在天空盒下面增加一个镜面立方体,那就需要增加一对着色器,首先顶点着色器需要增加法线,mvp矩阵

attribute vec4 a_position;
attribute vec4 a_normal;
uniform mat4 u_vpMatrix;
uniform mat4 u_modelMatrix;
varying vec3 v_position;
varying vec3 v_normal;void main() {v_position = (u_modelMatrix * a_position).xyz;v_normal = vec3(u_modelMatrix * a_normal);gl_Position = u_vpMatrix * u_modelMatrix * a_position;
}
复制代码

片元着色器则需要添加相机位置,纹理以及顶点着色器传递过来的法线和顶点位置

precision highp float;
varying vec3 v_position;
varying vec3 v_normal;
uniform samplerCube u_texture;
uniform vec3 u_viewPosition;void main() {vec3 normal = normalize(v_normal);vec3 eyeToSurfaceDir = normalize(v_position - u_viewPosition);vec3 direction = reflect(eyeToSurfaceDir,normal);gl_FragColor = textureCube(u_texture, direction);
}
复制代码

这样我们绘制的时候就要轮流切换着色器program

function draw(){gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);//天空盒gl.useProgram(program.program);//绘制天空盒//...//立方体gl.useProgram(cProgram.program);//绘制立方体//...requestAnimationFrame(draw);
}
复制代码

最后实现如下效果,demo情况 天空盒

后记

其实纹理盒除了可以做环境贴图,还可以结合光照,阴影贴图作出很多酷炫的效果。

转载于:https://juejin.im/post/5ccfbad6e51d453b560f2d4c

WebGL学习之纹理盒相关推荐

  1. webgl学习六 纹理贴图

    <html><head><title>纹理贴图</title><script type="text/javascript" s ...

  2. 【实战】(字节跳动、日本东京大学)学习使用白盒表示+GAN来创作卡通图片:Learning to Cartoonize Using White-Box Cartoon Representations

    要说亚洲动漫制作的王者,当然是我们一衣带水的邻邦--日本. 2020年字节跳动和日本东京大学联合发表了一篇<Learning to Cartoonize Using White-Box Cart ...

  3. WebGL学习(1) - 三角形

    原文地址:WebGL学习(1) - 三角形 还记得第一次看到canvas的粒子特效的时候,真的把我给惊艳到了,原来在浏览器也能做出这么棒的效果.结合<HTML5 Canvas核心技术>和网 ...

  4. 我的webgl学习之路(一)

    我的webgl学习之路 (一) 做项目中偶然需要移动端3d展示,所以学习了threejs;但是有着各种限制,还有就是项目要达到好的效果肯定是需要后期处理等等,所以展开了我学习webgl之路,我刚开始毫 ...

  5. 原生webgl学习(四) WebGL绘制矩形(一)

    本专栏所有文章示例代码均可在我的gitee码云上获取,读者可自行下载:https://gitee.com/babyogl/learnWebGL:本节代码在文件夹chapter-02里面的color-t ...

  6. webgl学习路线_WebGL:WebAssembly和功能路线图

    webgl学习路线 Yesterday, engineers from Google, Microsoft and Mozilla (makers of Chrome, Edge and Firefo ...

  7. WebGL three.js学习笔记 纹理贴图模拟太阳系运转

    纹理贴图的应用以及实现一个太阳系的自转公转 点击查看demo演示 demo地址:https://nsytsqdtn.github.io/demo/solar/solar three.js中的纹理 纹理 ...

  8. WebGL学习笔记七点一

    第六章讲的是一些GL的一些语法,前面已经涉及,学习时直接跳过,来看第七章,第七章是真正意义的三维立体的出现,其实图形绘制方法是差不多的,就是Z坐标此时不再为0,所以很容易能构造出一些立体图形,但是立体 ...

  9. WEBGL学习【八】模型视图投影矩阵

    版权声明:本文为博主原创文章,未经博主允许不得转载.更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/ ...

最新文章

  1. mysql的ab测试工具_轻量级性能测试工具ab / wrk / locust 分析 对比
  2. 极速理解设计模式系列:23.装饰器模式(Decorator Pattern)
  3. php mysqli result,PHP mysqli_free_result()与mysqli_fetch_array()函数详解
  4. python learning1.py
  5. windows 2003 iis 360防黑加固后不能使用
  6. vim 使用、设置笔记
  7. MATLAB R2021b v9.11.0.1769968中文版for Mac
  8. 再谈 最速下降法/梯度法/Steepest Descent
  9. python手机号信息查询身份证_Python使用xpath爬虫查询身份证信息和手机号信息并写入Excel表格...
  10. 你所不知道的我国交通工程早期经历了怎样的发展?
  11. crypto密码学知识大纲
  12. 北航超算运行matlab,超50万亿次!北航学子又破世界纪录,他们获得全球总决赛一等奖!...
  13. 2010年计算语言学分词作业——采用二元语法模型与viterbi算法分词
  14. Homebrew完美卸载软件及其依赖包
  15. OpenCV python 绘制椭圆形
  16. 使用代理访问百度网站 ProxyHandler python 爬虫 入门
  17. 新媒体运营教程:头条平台视频运营和分析
  18. 1010 -- 青蛙的约会
  19. 一名优秀的测试工程师需要具备哪些技能?
  20. Matlab电影动画的初级制作

热门文章

  1. Qt Dll总结——链接库预备知识(转载)
  2. JavaScript中使用console调试程序的坑
  3. Noip2015普及组第四题 Salesman的解题报告
  4. Java中的访问权限
  5. Exchange 2010 OAB无法更新
  6. VMware View把iPad从娱乐工具变成强大办公平台
  7. 【唠叨两句】如何将一张树型结构的Excel表格中的数据导入到多张数据库表中...
  8. Cookie和Session的区别
  9. 简单说一下,你对CPU缓存的了解?
  10. 【转】iOS实时卡顿监控