响应式网站建设开发公司,神马seo排名关键词点击,网站开发如何运用form表单,建一个网页网站目录
α混合
如何实现α混合
1. 开启混合功能#xff1a;
2. 指定混合函数
混合函数
gl.blendFunc#xff08;#xff09;函数规范
可以指定给src_factor和dst_factor的常量
混合后颜色的计算公式
加法混合
半透明的三角形#xff08;LookAtBlendedTriangl…目录
α混合
如何实现α混合
1. 开启混合功能
2. 指定混合函数
混合函数
gl.blendFunc函数规范
可以指定给src_factor和dst_factor的常量
混合后颜色的计算公式
加法混合
半透明的三角形LookAtBlendedTriangles.js
示例效果
示例代码
半透明的三维物体BlendedCube.js
示例效果
示例代码
透明与不透明物体共存
同时实现隐藏面消除和α混合的5个步骤
1.开启隐藏面消除功能。
2.绘制所有不透明的物体α为1.0。
3.锁定用于进行隐藏面消除的深度缓冲区的写入操作使之只读。
4.绘制所有半透明的物体α小于1.0注意它们应当按照深度排序然后从后向前绘制。
5.释放深度缓冲区使之可读可写。
gl.depthMask函数规范 α混合
颜色中的α分量即RGBA中的A控制着颜色的透明度。如果一个物体颜色的α分量值为0.5该物体就是半透明的透过它可以看到该物体背后的其他物体。如果一个物体颜色的α分量值为0那么它就是完全透明的我们将完全看不到它。在本文的示例程序中随着α分量的降低整个绘图区域会逐渐成为白色因为在默认情况下α混合不仅影响绘制的物体也会影响背景色最后你看到的白色实际上是canvas后空白的网页。
如何实现α混合
需要遵循以下两个步骤来开启α混合。
1. 开启混合功能 gl.enable(gl.BLEND) 2. 指定混合函数 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) 混合函数
下面来研究gl.blendFunc函数的作用。在进行α混合时实际上WebGL用到了两个颜色即源颜色source color和目标颜色destination color前者是“待混合进去”的颜色后者是“待被混合进去的颜色”。比如说我们先绘制了一个三角形然后在这个三角形之上又绘制了一个三角形那么在绘制后一个三角形中与前一个三角形重叠区域的像素的时候就涉及混合操作需要把后者的颜色“混入”前者中后者的颜色就是源颜色而前者的颜色就是目标颜色。
gl.blendFunc函数规范 可以指定给src_factor和dst_factor的常量 WebGL移除了OpenGL中的gl.CONSTANT_COLOR、gl.ONE_MINUS_CONSTANT_COLOR、gl.CONSTANT_ALPHA、gl.ONE_MINUS_CONSTANT_ALPHA
上表中RsGsBsAs和RdGdBdAd表示源颜色和目标颜色的各个分量。
本文的示例程序都将使用 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 混合后颜色的计算公式
这样如果源颜色是半透明的绿色0.01.00.00.4目标颜色是普通完全不透明的黄色1.01.00.01.0那么src_factor即源颜色的α分量为0.4而dst_factor则是1- 0.40.6计算出混合后的颜色就是0.61.00.0如下图。 加法混合
你可以试试将src_factor和dst_factor参数指定为其他常量比如有一种常用的混合模式——加法混合 additive blending如下所示。加法混合会使被混合的区域更加明亮通常被用来实现爆炸的光照效果或者游戏中需要引起玩家注意的任务物品等。 gl.BlendFunc(gl.SRC_ALHPA, gl.ONE) 半透明的三角形LookAtBlendedTriangles.js
看一下示例程序LookAtBlendedTriangles的运行效果如图中绘制了3个三角形并允许使用方向键来控制视点的位置。 本例将这3个三角形的α值从1.0改成0.4。下图显示了本例运行的效果。如你所见三角形变成了半透明的可以透过前面的三角形看到后面的三角形。使用方向键移动视点可见半透明效果一直存在。、
示例效果 示例代码
如下显示了LookAtBlendedTriangles.js的代码。我们开启了混合功能第26行指定了混合函数第27行并在initVertexBuffer函数中修改三角形颜色的α分量值第4050行gl.vertexAttribPointer函数的size和stride参数也相应地作了修改。
var VSHADER_SOURCE attribute vec4 a_Position;\n attribute vec4 a_Color;\n uniform mat4 u_ViewMatrix;\n uniform mat4 u_ProjMatrix;\n varying vec4 v_Color;\n void main() {\n gl_Position u_ProjMatrix * u_ViewMatrix * a_Position;\n v_Color a_Color;\n }\n;
var FSHADER_SOURCE #ifdef GL_ES\n precision mediump float;\n #endif\n varying vec4 v_Color;\n void main() {\n gl_FragColor v_Color;\n }\n;function main() {var canvas document.getElementById(webgl);var gl getWebGLContext(canvas);if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) returnvar n initVertexBuffers(gl);gl.clearColor(0, 0, 0, 1);gl.enable (gl.BLEND); // 开启混合功能gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); // 指定混合函数var u_ViewMatrix gl.getUniformLocation(gl.program, u_ViewMatrix);var u_ProjMatrix gl.getUniformLocation(gl.program, u_ProjMatrix);var viewMatrix new Matrix4();window.onkeydown function(ev){ keydown(ev, gl, n, u_ViewMatrix, viewMatrix); };var projMatrix new Matrix4();projMatrix.setOrtho(-1, 1, -1, 1, 0, 2);gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);// Drawdraw(gl, n, u_ViewMatrix, viewMatrix);
}function initVertexBuffers(gl) {var verticesColors new Float32Array([// 顶点坐标和颜色数据颜色透明度是 0.40.0, 0.5, -0.4, 0.4, 1.0, 0.4, 0.4, // The back green one-0.5, -0.5, -0.4, 0.4, 1.0, 0.4, 0.4,0.5, -0.5, -0.4, 1.0, 0.4, 0.4, 0.4, 0.5, 0.4, -0.2, 1.0, 0.4, 0.4, 0.4, // The middle yerrow one-0.5, 0.4, -0.2, 1.0, 1.0, 0.4, 0.4,0.0, -0.6, -0.2, 1.0, 1.0, 0.4, 0.4, 0.0, 0.5, 0.0, 0.4, 0.4, 1.0, 0.4, // The front blue one -0.5, -0.5, 0.0, 0.4, 0.4, 1.0, 0.4,0.5, -0.5, 0.0, 1.0, 0.4, 0.4, 0.4, ]);var n 9;var vertexColorbuffer gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);var FSIZE verticesColors.BYTES_PER_ELEMENT;var a_Position gl.getAttribLocation(gl.program, a_Position);gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 7, 0);gl.enableVertexAttribArray(a_Position);var a_Color gl.getAttribLocation(gl.program, a_Color);gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false, FSIZE * 7, FSIZE * 3);gl.enableVertexAttribArray(a_Color);gl.bindBuffer(gl.ARRAY_BUFFER, null);return n;
}function keydown(ev, gl, n, u_ViewMatrix, viewMatrix) {if(ev.keyCode 39) { // 按下了向右箭头键g_EyeX 0.01;} else if (ev.keyCode 37) { // 按下了向箭头键g_EyeX - 0.01;} else return;draw(gl, n, u_ViewMatrix, viewMatrix);
}// 眼位
var g_EyeX 0.20, g_EyeY 0.25, g_EyeZ 0.25;
function draw(gl, n, u_ViewMatrix, viewMatrix) {viewMatrix.setLookAt(g_EyeX, g_EyeY, g_EyeZ, 0, 0, 0, 0, 1, 0);gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);gl.drawArrays(gl.TRIANGLES, 0, n);
}半透明的三维物体BlendedCube.js
此刻我们将利用α混合功能在一个典型的三维物体——立方体上实现半透明效果。示例程序BlendedCube在WebGL 从0到1绘制一个立方体_山楂树の的博客-CSDN博客中的ColoredCube的基础上向代码中加入了使用α混合的两个步骤如下图所示。 示例效果 运行程序你会发现并没出现下图右中预期的效果实际的效果如下图左所示和WebGL 从0到1绘制一个立方体_山楂树の的博客-CSDN博客的ColoredCube没有什么区别。 这是因为程序开启了隐藏面消除功能第27行。我们知道α混合发生在绘制片元的过程而当隐藏面消除功能开启时被隐藏的片元不会被绘制所以也就不会发生混合过程更不会有半透明的效果。实际上只需要注释掉这一行开启隐藏面消除的代码即可。
示例代码
var VSHADER_SOURCE attribute vec4 a_Position;\n attribute vec4 a_Color;\n uniform mat4 u_MvpMatrix;\n varying vec4 v_Color;\n void main() {\n gl_Position u_MvpMatrix * a_Position;\n v_Color a_Color;\n }\n;
var FSHADER_SOURCE #ifdef GL_ES\n precision mediump float;\n #endif\n varying vec4 v_Color;\n void main() {\n gl_FragColor v_Color;\n }\n;function main() {var canvas document.getElementById(webgl);var gl getWebGLContext(canvas);if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) returnvar n initVertexBuffers(gl);// 设置清除背景色并开启深度测试gl.clearColor(0.0, 0.0, 0.0, 1.0);// gl.enable(gl.DEPTH_TEST);// 开启α混合gl.enable (gl.BLEND);// 设置混合函数gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);var u_MvpMatrix gl.getUniformLocation(gl.program, u_MvpMatrix);var mvpMatrix new Matrix4();mvpMatrix.setPerspective(30, 1, 1, 100);mvpMatrix.lookAt(3, 3, 7, 0, 0, 0, 0, 1, 0);gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}function initVertexBuffers(gl) {// v6----- v5// /| /|// v1------v0|// | | | |// | |v7---|-|v4// |/ |/// v2------v3var vertices new Float32Array([ // Vertex coordinates1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0,-1.0, 1.0, 1.0,-1.0, 1.0, // v0-v1-v2-v3 front1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0,-1.0,-1.0, 1.0, 1.0,-1.0, // v0-v3-v4-v5 right1.0, 1.0, 1.0, 1.0, 1.0,-1.0, -1.0, 1.0,-1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up-1.0, 1.0, 1.0, -1.0, 1.0,-1.0, -1.0,-1.0,-1.0, -1.0,-1.0, 1.0, // v1-v6-v7-v2 left-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, -1.0,-1.0, 1.0, // v7-v4-v3-v2 down1.0,-1.0,-1.0, -1.0,-1.0,-1.0, -1.0, 1.0,-1.0, 1.0, 1.0,-1.0 // v4-v7-v6-v5 back]);var colors new Float32Array([ // Colors0.5, 0.5, 1.0, 0.4, 0.5, 0.5, 1.0, 0.4, 0.5, 0.5, 1.0, 0.4, 0.5, 0.5, 1.0, 0.4, // v0-v1-v2-v3 front(blue)0.5, 1.0, 0.5, 0.4, 0.5, 1.0, 0.5, 0.4, 0.5, 1.0, 0.5, 0.4, 0.5, 1.0, 0.5, 0.4, // v0-v3-v4-v5 right(green)1.0, 0.5, 0.5, 0.4, 1.0, 0.5, 0.5, 0.4, 1.0, 0.5, 0.5, 0.4, 1.0, 0.5, 0.5, 0.4, // v0-v5-v6-v1 up(red)1.0, 1.0, 0.5, 0.4, 1.0, 1.0, 0.5, 0.4, 1.0, 1.0, 0.5, 0.4, 1.0, 1.0, 0.5, 0.4, // v1-v6-v7-v2 left1.0, 1.0, 1.0, 0.4, 1.0, 1.0, 1.0, 0.4, 1.0, 1.0, 1.0, 0.4, 1.0, 1.0, 1.0, 0.4, // v7-v4-v3-v2 down0.5, 1.0, 1.0, 0.4, 0.5, 1.0, 1.0, 0.4, 0.5, 1.0, 1.0, 0.4, 0.5, 1.0, 1.0, 0.4 // v4-v7-v6-v5 back]);var indices new Uint8Array([ // Indices of the vertices0, 1, 2, 0, 2, 3, // front4, 5, 6, 4, 6, 7, // right8, 9,10, 8,10,11, // up12,13,14, 12,14,15, // left16,17,18, 16,18,19, // down20,21,22, 20,22,23 // back]);var indexBuffer gl.createBuffer();if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, a_Position)) return -1;if (!initArrayBuffer(gl, colors, 4, gl.FLOAT, a_Color)) return -1;gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);return indices.length;
}function initArrayBuffer(gl, data, num, type, attribute) {var buffer gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, buffer);gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);var a_attribute gl.getAttribLocation(gl.program, attribute);gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);gl.enableVertexAttribArray(a_attribute);return true;
}透明与不透明物体共存
关闭隐藏面消除功能只是一个粗暴的解决方案并不能满足实际的需求。在绘制三维场景时场景中往往既有不透明的物体也有半透明的物体。如果关闭隐藏面消除功能那些不透明物体的前后关系就会乱套了。
同时实现隐藏面消除和α混合的5个步骤
实际上通过某种机制可以同时实现隐藏面消除和半透明效果我们只需要
1.开启隐藏面消除功能。 gl.enable(gl.DEPTH_TEST) 2.绘制所有不透明的物体α为1.0。
3.锁定用于进行隐藏面消除的深度缓冲区的写入操作使之只读。 gl.depthMask(false) 4.绘制所有半透明的物体α小于1.0注意它们应当按照深度排序然后从后向前绘制。
5.释放深度缓冲区使之可读可写。 gl.depthMask(true) gl.depthMask函数用来锁定和释放深度缓冲区其规范如下所示
gl.depthMask函数规范 我们知道深度缓冲区存储了每个像素的z坐标值归一化为0.0到1.0之间。假设场景中有两个前后重叠的三角形A和B。首先在绘制三角形A的时候将它的每个片元的z值写入深度缓冲区然后在绘制三角形B的时候将B中与A重叠的片元和深度缓冲区中对应像素的z值作比较如果深度缓冲区中的z值小就说明三角形A在前面那么B的这个片元就被舍弃了不会写入颜色缓冲区如果深度缓冲区中的z值大就说明三角形B在前面就把B的这个片元写入颜色缓冲区中将之前A的颜色覆盖掉。这样当绘制完成时颜色缓冲区中的所有像素都是最前面的片元而且每个像素的z值都存储在深度缓冲区中。这就是隐藏面消除的原理。注意所有这些操作都是在片元层面上进行的所以如果两个面相交也可以正常显示。
当我们按照上述步骤同时绘制透明和不透明物体时在第1步和第2步结束后所有不透明的物体都正确地绘制在了颜色缓冲区中深度缓冲区记录了每个像素最前面的片元的深度。然后进行第3、4和5步绘制所有半透明的物体。由于深度缓冲区的存在不透明物体后面的物体即使是半透明的也不会显示。这是因为深度缓冲区的写操作被锁定了所以在绘制不透明物体前面的透明物体时也不会更新深度缓冲区。