Shadertoy 进阶 01
上一篇中简单阐述了下shader入门级hello world。
想了想,可以再深入的讲下我认识的 shadertoy 。
1. 坐标系
身为画家,最重要的当然是清楚自己的画布布局,专业一点,坐标系。shader中画图同样,需要我们首先了解坐标系,熟悉了坐标系才好在脑海中形成坐标系并进行构思几何。
除了听别人说的坐标系是什么,不如自己测试验证下记忆更深刻。这里我们写一段shader来测试下shadertoy的坐标系,代码如下,根据纹理坐标的范围进行了简单的逻辑判断,做出不同的颜色绘制。【这里请忽略性能问题,if else不适合gpu做并行计算 这里不重要哦>.<】
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
vec3 col = vec3(0,0,0);
if(uv.x<0.5 && uv.y<0.5)
col = vec3(1.0,0.0,0.0);
else if(uv.x>0.5 && uv.y<0.5)
col = vec3(0.0,1.0,0.0);
else if(uv.x<0.5 &&uv.y>0.5)
col = vec3(0.0,0.0,1.0);
else if(uv.x>0.5 && uv.y>0.5)
col = vec3(1.0,1.0,0.0);
fragColor = vec4(col,1.0);
}
很明显,可以一眼看出来坐标系是左下角为(0.0,0.0),右上角为(1.0,1.0)。这样相信你就对自己的画布有了大概的认识了。
2、渲染一张纹理
再认识一个操作,渲染一张纹理到目标缓存区。操作见下图:
修改着色器代码,来展示你选中的纹理
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
vec3 col = texture(iChannel0,uv).rgb;
fragColor = vec4(col,1.0);
}
新引入的函数texture()采样函数,参数同glsl中一致,第一个参数为纹理id,第二个参数为纹理坐标
代码中写的是iChannel0,机智如你,相信你已经看到了,就是上图中“1.点击这里”指向位置的下标文本,如果想用更多的纹理,可以点击iChannel1,iChannel2,iChannel3,选择你要用的图,然后就这么方便。
3、示例体验
接下来,我打算列举几个简单的计算,理解一下shader中的绘图
eg1. 将一张图片横向绘制N次
线上效果图:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
const float LineNum = 5.0;
vec2 tmpUV = vec2(uv.x*LineNum,uv.y);
vec2 realUV = vec2(tmpUV.x-floor(tmpUV.x),tmpUV.y);
vec3 col = texture(iChannel0,realUV).rgb;
fragColor = vec4(col,1.0);
}
shader逻辑:
uv:x,y[0.0,1.0]归一化纹理坐标
tmpUV:将x范围扩大到[0.0,5.0],y范围还是[0.0,1.0]
realUV: 将tmpUV的范围进一步处理,y照旧;x取值为当前值减去当前值向下取整剩余的浮点值,这个值范围刚好为[0.0,1.0]。因为texture函数的纹理坐标只能是[0.0,1.0]所以我们计算出这个值,对应的一采样就如效果图所示了。
eg2. 将一张图片弄成4宫格或者9宫格
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
const float hLineNum = 3.0;
const float vLineNum = 3.0;
vec2 tmpUV = vec2(uv.x*hLineNum,uv.y*vLineNum);
vec2 realUV = vec2(tmpUV.x-floor(tmpUV.x),tmpUV.y-floor(tmpUV.y));
vec3 col = texture(iChannel0,realUV).rgb;
fragColor = vec4(col,1.0);
}
eg3. 将一张图片弄成的6宫格中个别区域弄上特殊处理
先上效果:[iChannel1是上面提到的选择了第二个纹理,图片任选]
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
float hLineNum = 2.0;
float vLineNum = 3.0;
vec2 tmpUV = vec2(uv.x*hLineNum,uv.y*vLineNum);
vec2 realUV = vec2(tmpUV.x-floor(tmpUV.x),tmpUV.y-floor(tmpUV.y));
vec3 col = texture(iChannel0,realUV).rgb;
if(uv.x>0.5&&uv.y>0.5)
{
vec3 col2 = texture(iChannel1,realUV).rgb;
col = col*col2;
}else if(uv.x<0.5 && uv.y<0.5)
{
col = col*vec3(1.0,0.0,0.0);
}
fragColor = vec4(col,1.0);
}
eg4. 绘制图片,但只绘制中间的一个椭圆区域
效果图如下,新引入函数distance,参数需要两个,这里使用的是vec2,计算两个二维空间点的距离,距离外的用默认颜色【黑色】渲染,距离内的使用纹理颜色渲染。
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
vec3 col = vec3(0.0,0.0,0.0);
vec2 tmpUV = uv-vec2(0.5,0.5); //[]
float dis = distance(tmpUV,vec2(0.0,0.0));
if(dis<0.4)
col = texture(iChannel0,uv).rgb;
fragColor = vec4(col,1.0);
}
作者:阿凯 来源:https://zhuanlan.zhihu.com/p/448215305
技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。
私信领取相关资料
推荐阅读:
音视频开发工作经验分享 || 视频版
OpenGL ES 学习资源分享
开通专辑 | 细数那些年写过的技术文章专辑
Android NDK 免费视频在线学习!!!
你想要的音视频开发资料库来了
推荐几个堪称教科书级别的 Android 音视频入门项目
觉得不错,点个在看呗~