因为 shader 里面的变量没有打印方法,所以我做了一个logger。
要打印一个值,但是没有迭代,没有动态循环,也没有动态数组。这个过程比较漫长,因为我改了好几种写法,逐一发现了以上特性是不支持的。
算法完成之后发现了 float 失精的问题:千万级别的数只剩下整数位是准确的,小数部分已经没有了;更小级别的数大约支持到小数点后3~5位。
在字体的渲染方面,试了一下数字打印的最小规格是 5*3 的点阵,基本上是活字印刷;
另:这里使用了正负形减少了绘制的判断次数,思路来源于:https://www.cnblogs.com/freeblues/p/5724833.html。
然后想尝试这个logger在通用场景中的使用方式,所以继续做了第五章的颜色与纹理的内容。
第一次按照示例代码尝试,我的贴图黑屏了:
打印发现texture2D
读进来的 rgb 通道都是0,只有 a 通道默认是1.
一下午又一上午过去了,么得进展。
最后查资料发现 需要指定纹理坐标在ST方向的填充方法:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
手上的项目很紧张,所以这里因为后续的黑屏这两天就暂时搁置了。
这里是后来在晚饭后逛到的TA百人计划的资料:【技术美术百人计划】图形 1.3 纹理的秘密
纹理映射设置 Wrap Mode 决定了UV坐标被对应函数映射到 0~1 范围外时的纹理表现。
在 OpenGL 中的概念为 包装模式 Wrapping Model
在 DirectX 中为 纹理寻址模式 Texture Addressing Model
模式有GL_REPEAT
重复、GL_MIRRORED_REPEAT_ARB
镜像重复、GL_CLAMP
截取/边缘重复、CLAMP_TO_BORDER_ARB
定值边框、GL_CLAMP_TO_EDGE
边缘截取
webgl 参数文档:WebGLRenderingContext.texParameter
写到这里,我突然意识到,用叉积判断坐标在三角形内的方法返回了定值验证正确的数据,但是画面依然一片漆黑的原因,想必是FragCoord
完全忘记归一化这种事。。。
在正确的归一化 (coord/scale) * 2. -1.
之后,带着贴图的三角形出现了:
虽然怎么看这个贴图都像是 CLAMP 了呢( ̄ω ̄;) 哦呼
修正了贴图坐标计算方式之后(为了让贴图和三角形一起动,给三个角定位了UV坐标):
写了两天的东西丢了,撤销的时候文本失焦,撤销执行到目录栏了。
新建的文件丢了,回收站只剩下空文件夹了。完蛋。
及时commit!及时commit!及时commit!
webgl context
中通过readPixels
获取帧缓冲数据的时候,如果是只有初始化一次绘制的情况,需要在创建 context
上下文时设置preserveDrawingBuffer: true
,使缓冲区保存而不被清除,否则缓冲区清除后只有rgba全0的数据。
还有另一种直白的、幽默的方法:https://newbedev.com/how-do-you-save-an-image-from-a-three-js-canvas
展示经过滤镜前后的像素时,会从绘制源图片作为对比的 2d context
和进行滤镜应用的webgl context
中分别读取数据,前者的getImageData
方法获取的数据是格式为{data : Uint8ClampedArray}
的ImageData
,后者的readPixels
方法获取的数据是格式为Uint8Array
的ArrayBufferView
。
Uint8ClampedArray
和Uint8Array
在这里用的时候没区别;
二者差异仅在创建指定值时,Uint8ClampedArray
会将值固定在0~255
范围内。
所以这里把ImageData.data
作为ArrayBufferView
使用的效果是一样的。
PS: 2d context
读取像素的起点坐标为左上角,而webgl context
读取像素的起点坐标为左下角。
向纹理传输数据的texImage2D
方法传参分为两种情况:target, level, internalformat, (width, height, border), format, type, pixels
,当pixels
数据为ArrayBufferView
时,需要指定width, height, border
的值,其余情况的pixels
数据则不需要,详见:
https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/texImage2D
参数
width, height, border
中的width, height
指定纹理宽高,而border
只能传 0(现代OpenGL中已弃用(?),此处附关于border
0值争议的讨论:https://www.zhihu.com/question/322311188/answer/667887183)
覆盖了原生样式的 select,直接appearance: none
要重写小箭头,这里用 border-right
的空间安排的小箭头位置。
select {
padding: 1rem;
border-radius: 0.5rem;
border: 0;
border-right: 14px #fff solid;
outline: #aaa 1px solid;
// cursor: pointer;// 会在select展开的时候全屏pointer ૮₍˃⤙˂₎ა还是算了8
&:hover {
outline: #444 1px solid;
}
}
初步结果(๑╹っ╹๑):
这里是后续:我想试一下大面积的模糊,就像是超大毛玻璃弥散光的那种。
刚开始尝试了完全不优化的200规模的方框模糊,单片元40000次循环平均,非常粗暴,大约两秒:
后来尝试增加取值间隔来缩短循环次数,间隔10个单元的时候出现了栅格;刚开始没理解这样的表现,所以把采样变成间隔100单元的九宫格,结果出现了符合直觉的叠加的三层图样:
决定换另外的方法,在外面间隔取样后传进来插值,就像初始教程里的渐变三角形一样。
只取绘制背景的四个角自动内插的情况,效果不好:
四个角手动插值的情况:
说是模糊也不是不行,但怎么看都是大渐变诶0 0
4*4采样插值的时候遇到了动态索引的问题:
Index expression must be constant.
一些动态的善解人意的编程方式正在离开我。
然后就不得不出现了一串类似于index==0 && color+= u_colors[0]
或者是静态遍历的代码。
有没有别的优雅的方式来解决动态索引的问题呢?
栅格的感觉很重,要不然是插得不对,而且感觉RGB空间插值效果太雾太灰了
看得出来,我还是蛮喜欢搞这种东西:
下一本书想试试读一下冈萨雷斯的《数字图像处理》,在这次的很多尝试中都有很多疑惑和迷茫的地方,还是应该看书才行
后记:看了几页,比张凤霞的煎饼还硬,暂时没有精力深挖这个方向了
TODO: