OpenGL ES Shader 怎样绘制一颗“心”

今天讲一下绘制心形的两种方式,主要是为了扩展一下绘制复杂形状的思路,为后面讲特效做一些简单的铺垫。

心形绘制可以参考 ShaderToy 上的代码:
https://www.shadertoy.com/view/XsfGRn

OpenGL ES Shader 怎样绘制一颗“心”

上述代码绘制心形,首先将原点从左下角移至坐标系中央,这样所有片元的向量均以屏幕中心为起点,则向量 uv 就是画布中心与像素点坐标之间的方向向量。

  vec2 uv = (2.0 * fragCoord - iResolution.xy) / min(iResolution.y,iResolution.x); //坐标原点设置到中心位置

然后利用反正切函数值和当前片元(像素)与屏幕中心点的距离相比较,来确定心形状的边界。

GL ES 中的反正切函数 atan(p.x,p.y) 取值范围是[-π, π],然后除以 PI 后,取值范围变成了 [-1, 1] 。

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
  vec2 uv = (2.0 * fragCoord - iResolution.xy) / min(iResolution.y,iResolution.x); //坐标原点设置到中心位置

  float r = length(uv);  
  float d = atan(uv.x,uv.y)/PI; //[-1.0,1.0] 
  float s = abs(d);

  vec3 color = vec3(s) * vec3(1.0, 0.0, 0.0);

  fragColor = vec4(color,1.0);

}

我们把反正切的结果取绝对值,渲染出来:

OpenGL ES Shader 怎样绘制一颗“心”

可以看到,从中心向外辐射,每条直线上的值都是一样的,即每条直线上像素点得到的 s 值都是相同的。

OpenGL ES Shader 怎样绘制一颗“心”

我们用黄点表示距离屏幕中心的远近 length(uv),然后通过 s-r 的值来确定心形的边界,得到一个最简单的心形。

OpenGL ES Shader 怎样绘制一颗“心”

再贴一下代码:

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
  vec2 uv = (2.0 * fragCoord - iResolution.xy) / min(iResolution.y,iResolution.x);

  uv.y -= 0.3;// 向上移动一些
  float r = length(uv);  
  float d = atan(uv.x,uv.y)/PI; //[-1.0,1.0] 
  float s = abs(d);
  float col = smoothstep(-0.01, 0.01, s-r);//边缘过渡
  vec3 color = vec3(col) * vec3(1.0, 0.0, 0.0);

  fragColor = vec4(color,1.0);

}

增加一个函数使心的形状更加扁平化 float e = (13.0*s - 22.0*s*s + 10.0*s*s*s)/(6.0-5.0*s);

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
  vec2 uv = (2.0 * fragCoord - iResolution.xy) / min(iResolution.y,iResolution.x);

  uv.y -= 0.3;  
  float r = length(uv);  
  float d = atan(uv.x,uv.y)/PI; //[-1.0,1.0] 
  float s = abs(d);
  float e = (13.0*s - 22.0*s*s + 10.0*s*s*s)/(6.0-5.0*s);
  float col = smoothstep(-0.01, 0.01, e-r);
  vec3 color = vec3(col) * vec3(1.0, 0.0, 0.0);

  fragColor = vec4(color,1.0);
}

增加扁平化函数之后的心形:

OpenGL ES Shader 怎样绘制一颗“心”

上述反正切和距离判断绘制心形,实际上是有向距离场(SDF)算法思路,除此之外还有一种直接通过函数曲线绘制的思路。

float heart(vec2 p) {
    p.y += 0.3;
    float offset = 0.3;
    // (x^2+(1.2*y-sqrt(abs(x)))^2−1)
    float k = 1.2 * p.y - sqrt(abs(p.x)*1.2 + offset);
    return 1.0 - p.x * p.x - k * k;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
  vec2 uv = (2.0 * fragCoord - iResolution.xy) / min(iResolution.y,iResolution.x);

  uv.y += 0.3;   
  float d = heart(uv);
  float col = smoothstep(-0.01, 0.01, d);
  vec3 color = vec3(col) * vec3(1.0, 0.0, 0.0);

  fragColor = vec4(color,1.0);
}

函数曲线实际上是把整个画布当做一个原点位于中心坐标系,利用函数特效构建一个闭合的图形。你要问这个函数怎么得出来的,这个当然是图形大佬调出来的。

效果如下:

OpenGL ES Shader 怎样绘制一颗“心”

进技术交流群,扫码添加我的微信:Byte-Flow。

字节流动

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/31824.html

(0)

相关推荐

发表回复

登录后才能评论