写在前面
虽然玩Shader不一定要webgl,但看看其其他工具,opengl和directx使用之前要经过一堆繁琐的设置,很容易劝退,unity玩起来需要考虑许多与shader无关的东西,shadertoy则是连顶点这个概念都没有。相比之下,webgl可要友好亲切得多了,况且wengl就是网页版的opengl,查起资料来也非常方便。
本系列假设读者已经对webgl有一定的了解。如果你还不知道webgl是什么的话,可以参考《webgl编程指南》,这是写的非常好的一本书。以及两个系列的csdn博客作为辅助,https://blog.csdn.net/charlee44/category_8676774.html以及https://blog.csdn.net/lufy_legend/category_9262828.html。
首先会使用http://www.ibiblio.org/e-notes/webgl/gpu/contents.htm上的Demo作为例子讲解,感谢作者Evgeny Demidov 。
本系列文章将会用到webgl2-compute,你可以试试打开下面这个网页http://www.ibiblio.org/e-notes/webgl/gpu/CSimage2D.htm,如果能看到下面图像的话,就可以了。
如果不行的话,请使用Google Chrome浏览器或者Microsoft Edge Insider Channels浏览器,后者下载地址:https://www.microsoftedgeinsider.com/en-us/download/?platform=win10。然后在属性框的目标栏加入参数
--enable-webgl2-compute-context --use-angle=gl --use-cmd-decoder=passthrough
但笔者的Chrome浏览器加了参数后似乎并不起作用,用来Edgeinsider才能正常显示。好了,那么开始吧!
加载2D图像
Demo地址:http://www.ibiblio.org/e-notes/webgl/gpu/CSimage2D.htm,源码请自己扒。
分析70行左右的代码。很明显,将每个像素分为RGBA四个通道,然后再用texSubImage2D函数将这些像素绘制出来,这样绘制了作为背景的绿色。
pix = new Float32Array(4*n*n)
for(var i = 0; i<n; i++)
for(var j = 0; j<n; j++){
pix[t++] = 0; pix[t++] = 1
pix[t++] = 0; pix[t++] = 1
}
texture = gl.createTexture()
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA32F, n,n)
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, n,n, gl.RGBA, gl.FLOAT,pix)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
蓝色则用着色器绘制,代码在14行左右
const CSs = `#version 310 es
layout (binding = 0, rgba32f) uniform writeonly highp image2D destTex;
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main() {
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
imageStore(destTex, storePos, vec4(0.,0.,1.,1.));
}
`;
87行创建Css着色器,然后94行用dispathCompute将其分别在x,y,z方向上重复绘制16,16,1次。这样就是8*16 = 128长的蓝色正方形了。
gl.dispatchCompute(16, 16, 1);