网站seo搜索引擎优化案例,网站 什么语言开发的,asp.net 网站开发实例,如何开发小程序?文章目录 搭建简易的webgl环境绘制简单三角形#xff08;不带stencilTest)绘制另一个三角形#xff08;不带模板测试#xff09;加入模板测试总结调参练习 搭建简易的webgl环境 一直以来#xff0c;我只是想通过搭建纯webgl环境#xff0c;进行开发#xff0c;来清楚地了… 文章目录 搭建简易的webgl环境绘制简单三角形不带stencilTest)绘制另一个三角形不带模板测试加入模板测试总结调参练习 搭建简易的webgl环境 一直以来我只是想通过搭建纯webgl环境进行开发来清楚地了解基础webgl功能如果在C环境里面使用opengl还需要配置加载各种 lib以及编译容易错而且里面有很多是其他各种库里面的函数不能最大限度地接近原理。偶然间发现了一个很简单的方法基于最基本的webgl函数WebGLRenderingContext里面的api。下面推荐一下可以方便大家一起学习。 进入mdn在线文档 https://developer.mozilla.org/zh-CN/ 这里面不仅有详细地说明还有一个平台给我们实践各种代码如下图所示点击其中的play 则进入写代码平台 https://developer.mozilla.org/zh-CN/play 平台就这么搭建好了不用写任何东西也不用安装任何软件编译任何代码。否则很多情况下我的耐心都在各种无关的操作中被消磨掉了到头来什么也没学到。
绘制简单三角形不带stencilTest)
把下面这段js代码复制到上面写代码平台的最下面js框里面,然后右边会出现一个三角形
const canvas document.createElement(canvas);
canvas.width 300;
canvas.height 300;
document.body.append(canvas); // 创建和将 canvas 加入页面
const gl canvas.getContext(webgl);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
const vertexShader gl.createShader(gl.VERTEX_SHADER);
// 创建一个顶点着色器
gl.shaderSource(vertexShader,attribute vec4 a_position;void main() {gl_Position a_position; // 设置顶点位置}
,
); // 编写顶点着色器代码
gl.compileShader(vertexShader); // 编译着色器代码const fragmentShader gl.createShader(gl.FRAGMENT_SHADER);
// 创建一个片元着色器
gl.shaderSource(fragmentShader,precision mediump float;uniform vec4 u_color;void main() {gl_FragColor u_color; // 设置片元颜色}
,
); // 编写片元着色器代码
gl.compileShader(fragmentShader); // 编译着色器代码const program gl.createProgram(); // 创建一个程序
gl.attachShader(program, vertexShader); // 添加顶点着色器
gl.attachShader(program, fragmentShader); // 添加片元着色器
gl.linkProgram(program); // 连接 program 中的着色器gl.useProgram(program); // 告诉 webgl 用这个 program 进行渲染const colorLocation gl.getUniformLocation(program, u_color);
// 获取 u_color 变量位置
gl.uniform4f(colorLocation, 0.93, 0, 0.56, 1); // 设置它的值const positionLocation gl.getAttribLocation(program, a_position);
// 获取 a_position 位置
const positionBuffer gl.createBuffer();
// 创建一个顶点缓冲对象返回其 ID用来放三角形顶点数据
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 将这个顶点缓冲对象绑定到 gl.ARRAY_BUFFER
// 后续对 gl.ARRAY_BUFFER 的操作都会映射到这个缓存
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([0, 0.5, 0.5, 0, -0.5, -0.5]), // 三角形的三个顶点// 因为会将数据发送到 GPU为了省去数据解析这里使用 Float32Array 直接传送数据gl.STATIC_DRAW, // 表示缓冲区的内容不会经常更改
);
// 将顶点数据加入的刚刚创建的缓存对象gl.vertexAttribPointer(// 告诉 OpenGL 如何从 Buffer 中获取数据positionLocation, // 顶点属性的索引2, // 组成数量必须是123或4。我们只提供了 x 和 ygl.FLOAT, // 每个元素的数据类型false, // 是否归一化到特定的范围对 FLOAT 类型数据设置无效0, // stride 步长 数组中一行长度0 表示数据是紧密的没有空隙让OpenGL决定具体步长0, // offset 字节偏移量必须是类型的字节长度的倍数。
);
gl.enableVertexAttribArray(positionLocation);
// 开启 attribute 变量额使顶点着色器能够访问缓冲区数据gl.clearColor(0, 1, 1, 1); // 设置清空颜色缓冲时的颜色值
gl.clear(gl.COLOR_BUFFER_BIT); // 清空颜色缓冲区也就是清空画布gl.drawArrays(// 从数组中绘制图元gl.TRIANGLES, // 画三角形0, // 从哪个点开始画3, // 需要用到多少个点
); 上面是绘制简单三角形的webgl js代码为了便于理解这篇文章从这个最一般的helloworld讲起通过加入一些变化说明stenciltest的原理因为我在网上看到很多有各种复杂的部分什么贴纹理啊绘制地板box啊甚至还加了动画实在不方便对单个模板测试功能的理解。
绘制另一个三角形不带模板测试
把以下这一小段代码加入到刚才的js代码后面可以绘制两个重叠的三角形
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1.0, 0.0, 0.0, -1.0, 1., 0.0]), // 三角形的三个顶点// 因为会将数据发送到 GPU为了省去数据解析这里使用 Float32Array 直接传送数据gl.STATIC_DRAW, // 表示缓冲区的内容不会经常更改
);
gl.drawArrays(// 从数组中绘制图元gl.TRIANGLES, // 画三角形0, // 从哪个点开始画3, // 需要用到多少个点
);加入模板测试
在刚才的基础上做如下修改
修改初始化gl的代码 原来的const gl canvas.getContext(webgl);改成const gl canvas.getContext(webgl,{stencil: true});在绘制第一个三角形之前加入如下代码
gl.enable(gl.STENCIL_TEST);
gl.colorMask(false, false, false, false);
gl.stencilFunc(gl.ALWAYS, 1, 255);
gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE);其中第一句是开启模板测试第二句设置color遮罩目的是不让它真正显示在结果框中但是还是影响了模板测试并且可以修改了stencilbuffer里面的值第三句是设置通过模板测试的条件gl.ALWAYS也就是永远通过1代表ref参照值255代表位掩码这里没用因为是always通过模板测试第四句是设置模板测试不通过或者通过而深度测试不通过或者模板测试和深度测试都通过以后干什么这里都设置为REPLACE表示不管咋样要把模板buffer里面的值全部替换成ref参照值第三句已设定参照值为1。这些都要在绘制第一个三角形时生效还记得第一个三角形是什么吗那是一个倾斜的三角形可以回头看截图。
这样设置后在绘制完第一个三角形以后stencilbuffer里面是这样子的示意图 其中只有在中间三角形地方的片源都是1其他都是0因为模板测试缓冲区默认是0其他没绘制的地方保持不变绘制地方也就是三角形区域不论是深度测试和模板测试是否通过都用ref值1替换。
这样设置以后整体运行后是看不到任何三角形的因为gl.colorMask(false, false, false, false)这句话的原因。
在绘制第二个三角形之前加入以下代码
gl.colorMask(true, true, true, true);
gl.stencilFunc(gl.NOTEQUAL, 1, 255);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);第一句是设置color遮罩这里红绿蓝透明都是true意思是都可以绘制出来了所以第二个三角形就能看到了下面一句话是设置模板测试通过的条件不等于1具体是ref1 mask255令逐片源看stenbuffer里面当前存储值buf设置为NOTEQUAL则意思是refmask!bufmask翻译过来就是ref按位与mask的值不等于逐片源stencilbuffer里面当前值按位与mask的值其中ref按位与mask为1恒定逐片源stencilbuffer里面当前值按位与mask则是非第一个三角形绘制区域为0第一个三角形绘制区域为1所以这里模板测试通过的条件就是非第一个三角形绘制区域将通过模板测试。
而第三句规定了不通过模板测试和通过模板测试以及通过模板测试和深度测试之后都不改变stencilbuffer的当前值。 在以上设置完成后绘制的第二个三角形如下所示 从图中看第二个三角形中在第一个三角形区域的片源被去掉了因为那些片源没有通过模板测试。符合我们之前的设置结果。
修改后的整体js代码如下
const canvas document.createElement(canvas);
canvas.width 300;
canvas.height 300;
document.body.append(canvas); // 创建和将 canvas 加入页面
const gl canvas.getContext(webgl,{stencil:true});
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
const vertexShader gl.createShader(gl.VERTEX_SHADER);
// 创建一个顶点着色器
gl.shaderSource(vertexShader,attribute vec4 a_position;void main() {gl_Position a_position; // 设置顶点位置}
,
); // 编写顶点着色器代码
gl.compileShader(vertexShader); // 编译着色器代码const fragmentShader gl.createShader(gl.FRAGMENT_SHADER);
// 创建一个片元着色器
gl.shaderSource(fragmentShader,precision mediump float;uniform vec4 u_color;void main() {gl_FragColor u_color; // 设置片元颜色}
,
); // 编写片元着色器代码
gl.compileShader(fragmentShader); // 编译着色器代码const program gl.createProgram(); // 创建一个程序
gl.attachShader(program, vertexShader); // 添加顶点着色器
gl.attachShader(program, fragmentShader); // 添加片元着色器
gl.linkProgram(program); // 连接 program 中的着色器gl.useProgram(program); // 告诉 webgl 用这个 program 进行渲染const colorLocation gl.getUniformLocation(program, u_color);
// 获取 u_color 变量位置
gl.uniform4f(colorLocation, 0.93, 0, 0.56, 1); // 设置它的值const positionLocation gl.getAttribLocation(program, a_position);
// 获取 a_position 位置
const positionBuffer gl.createBuffer();
// 创建一个顶点缓冲对象返回其 ID用来放三角形顶点数据
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 将这个顶点缓冲对象绑定到 gl.ARRAY_BUFFER
// 后续对 gl.ARRAY_BUFFER 的操作都会映射到这个缓存
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([0, 0.5, 0.5, 0, -0.5, -0.5]), // 三角形的三个顶点// 因为会将数据发送到 GPU为了省去数据解析这里使用 Float32Array 直接传送数据gl.STATIC_DRAW, // 表示缓冲区的内容不会经常更改
);
// 将顶点数据加入的刚刚创建的缓存对象gl.vertexAttribPointer(// 告诉 OpenGL 如何从 Buffer 中获取数据positionLocation, // 顶点属性的索引2, // 组成数量必须是123或4。我们只提供了 x 和 ygl.FLOAT, // 每个元素的数据类型false, // 是否归一化到特定的范围对 FLOAT 类型数据设置无效0, // stride 步长 数组中一行长度0 表示数据是紧密的没有空隙让OpenGL决定具体步长0, // offset 字节偏移量必须是类型的字节长度的倍数。
);
gl.enableVertexAttribArray(positionLocation);
// 开启 attribute 变量额使顶点着色器能够访问缓冲区数据gl.clearColor(0, 1, 1, 1); // 设置清空颜色缓冲时的颜色值
gl.clear(gl.COLOR_BUFFER_BIT); // 清空颜色缓冲区也就是清空画布
gl.enable(gl.STENCIL_TEST);
gl.colorMask(false, false, false, false);
gl.stencilFunc(gl.ALWAYS, 1, 255);
gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE);gl.drawArrays(// 从数组中绘制图元gl.TRIANGLES, // 画三角形0, // 从哪个点开始画3, // 需要用到多少个点
);
gl.colorMask(true, true, true, true);
gl.stencilFunc(gl.NOTEQUAL, 1, 255);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1.0, 0.0, 0.0, -1.0, 1., 0.0]), // 三角形的三个顶点// 因为会将数据发送到 GPU为了省去数据解析这里使用 Float32Array 直接传送数据gl.STATIC_DRAW, // 表示缓冲区的内容不会经常更改
);
gl.drawArrays(// 从数组中绘制图元gl.TRIANGLES, // 画三角形0, // 从哪个点开始画3, // 需要用到多少个点
);总结 通过实践我发现模板测试是这样的一个思路总结如下 在各种绘制语句之前加入一些配置项这些配置项的目的是修改stencilbuffer以及决定这次的绘制是不是能通过模板测试因为只有通过模板测试和深度测试的片源才能最终被绘制出来而修改后的stencilbuffer里面的值会影响下次绘制是否能通过模板测试所以模板测试并不会修改绘制出的东西的颜色啥的他是一种高级裁剪。通过这种方式经过多次不清空stencilbuffer的绘制过程在stencilbuffer里面形成一幅独一无二的图像这种图像是前面多次绘制的结果它可能是复杂的不是简单的行列排布而是依赖于之前图像的一些特征不断地影响着后面的绘制结果。
调参练习 为了便于理解我们可以修改其中的某些参数来测试自己是不是真正理解比如我们把第二次绘制之前的模板测试条件设置语句中notequal改成equalgl.stencilFunc(gl.EQUAL, 1, 255);那么我们将得到另一个三角形 最后留一道思考题如何修改以上代码绘制出以下图形呢 快来尝试一下吧。
最近在学习英语所以想用英语表达一下一点学习感悟 Many engineers want to create the complex system which looks like cool and amazing at the beginning and ignore the easy and basic things, I know this feeling and experienced that, it is about anxiety, about unexpectable future, which tells me that we must work hard. After years of working, I found it is impossible, every skill need to practice from the easy, little, looks boring system, it may not be needed by our boss, by the society, we can not get any afford from that, but we need to face that, if we just copy any other code from the internet, and make out something that looks well, it doesn’t mean I have mastered that skill. Perhaps, it listened stupid, what? to make wheels by ourselves? What time is now? yeah, I confess it is stupid, but I just want to be the person, only in my way to understand the world.