只可以绘制纯色的模型是不够的,为了呈现出更真实的模型,我们还需要通过纹理贴图给模型进行上色。
GPU作为一种公用资源,是会被多个进程同时使用的,在资源不足的情况下(比如PC或手机系统进入休眠状态前或被唤醒后),我们持有的上下文会出现丢失的情况,为了保证程序运行的健壮性,我们必须在丢失上下文之后做出处理。
Canvas为我们提供了两个事件来监听,上下文的丢失和恢复,具体使用看下面的代码:
1 var canvas = document.getElementById("myGLCanvas"); 2 // 监听上下文丢失的事件 3 canvas.addEventListener("webglcontextlost", function (event) { 4 // 取消默认行为 5 event.preventDefault(); 6 // 停止继续绘图的代码 7 }, false); 8 // 监听上下文恢复的事件 9 canvas.addEventListener("webglcontextrestored", function () { 10 // 重新初始化的代码 11 // 需要注意的是 Canvas 通过 getContext 方法获得的上下文对象不需要重新获取, 还可以继续使用之前获取的上下文对象 12 // 开始继续绘图的代码 13 }, false);
我们要测试丢失上下文的处理代码是否正常,就需要触发丢失上下文,我们可以使用下面的js库来模拟上下文的丢失:
https://github.com/KhronosGroup/WebGLDeveloperTools
可以参考其目录下的src\debug\lost-context-simulator-test.html示例来使用。
我们需要将2D图片贴到3D模型上,需要使用到2D的图片,采用UV坐标来确定3D的面上的一个点可以对应2D图片上的一个像素或多个像素(采样),下面是uv坐标的坐标系:
(s对应u、t对应v),范围[0-1]。
立方体映射,是一个包含了6个2D图片的映射,一般用来实现环境映射,或者实现环境反射,下面的示例可以很好的展现环境反射的应用:
https://threejs.org/examples/#webgl_materials_envmaps
另外立方体映射还常用于创建天空盒(SkyBox)。
我们提交到GPU的图片尺寸的高和宽必须是2的n次方,即(2、4、8、16、32、64、128、256...),不过在OpenGL ES 2.0和WebGL中,我们也可以使用高宽非2的n次方的图片,即NPOT(Non Power Of Two);
如果我们使用了非2的n次方的图片,会有下面的一些限制:
具体请看:https://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences
我们先看看DOM里的Image对象的坐标系和WebGL纹理的坐标系的区别:
可以发现,两个坐标系的y轴刚好是相反的,所以为了使坐标系一致,我们需要使用下面的代码来翻转y轴:
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
我们的纹理图片和将要渲染的区域尺寸是不一定完全一致的,当纹理小于渲染区域时需要纹理伸展,当纹理大于渲染区域时需要纹理收缩;
当纹理进行伸展过大和收缩过大时,会出现模糊和锯齿,为了解决这个问题,我们可以使用多套尺寸的纹理,来对应不同尺寸的渲染区域,GPU会根据渲染区域的大小自动选择;
激活当前的操作贴图,指定后续代码操作的贴图是哪一个,参数是枚举gl.TEXTURE0到gl.TEXTURE7(最大值请查看gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS,最少是8);
后面会调用bindTexture来绑定当前的操作贴图,如果没有调用activeTexture就调用了bindTexture,则默认激活0号纹理单元(可以理解为默认调用了gl.activeTexture(gl.TEXTURE0)代码);
绑定指定纹理到activeTexture激活的纹理单元中,同时可以指定该纹理的类型;
更多详细信息可以参考这里:https://www.jianshu.com/p/1829b4acc58d
https://hammerc.github.io/dou3d-ts/examples/learningNotes/lesson_4/index.html
原文:https://www.cnblogs.com/hammerc/p/11296130.html