OpenGL Shader-爱心形状绘制

·  阅读 861

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战

爱心函数由来

说到爱心函数就要提起一个名人勒内·笛卡尔,法国著名哲学家、物理学家、数学家、神学家。他是17世纪欧洲哲学界和科学界最有影响力的名人之一誉为近代科学始祖。传说爱心函数是勒内·笛卡尔在欧洲游历邂逅瑞典公主克里斯汀并彼此产生爱慕之心,但因为种种原因两人无法相爱。勒内·笛卡尔在给公主寄出第十三封信的时候与世长辞,第十三封信的内容并是爱心公式。这就是关于爱心函数由来的传奇故事。

image.png

爱心公式:

x2+(yx23)2=1x^{2}+\left(y-\sqrt[3]{x^{2}}\right)^{2}=1

爱心实现效果

glsl中可以使用内置函数直接复刻出爱心公式。内置函数组合技就是length+sqrt+pow实现爱心公式。

x的y次方

genType pow (genType x, genType y)

x的开方

genType sqrt (genType x)

向量x的长度

float length (genType x)    

const vec3 white = vec3(1.);
const vec3 red = vec3(0.9608, 0.2745, 0.0275);
vec3 sdfHeart(vec2 uv){
    float value = uv.y - sqrt(pow(uv.x,2.));
    float d = length(vec2(uv.x,value)) - 0.2;
    return d > 0. ? white: red;
}
void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv -= 0.5; 
    uv.x *= iResolution.x/iResolution.y;
    gl_FragColor = vec4(sdfHeart(uv),1.0);
}

image.png 最终效果上来说好像并不能达到希望看到的爱心形状,这个爱心有点“瘦”。

升级版爱心

除了勒内·笛卡尔版本的爱心之外,还有其他爱心生成公式,例如桃型爱心、标准爱心等。

桃型爱心

公式如下: (x 2+y21)3=x2y3\left(x\ ^{2}+y^{2}-1\right)^{3}=x^{2}y^{3}

image.png

const vec3 white = vec3(1.);
const vec3 red = vec3(0.9608, 0.2745, 0.0275);

vec3 sdfHeart2(vec2 uv){
    float value = pow(length(uv)-0.2,3.);
    float d = value - pow(uv.x,2.)*pow(uv.y,3.);
    return d > 0.? white: red;
}
void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv -= 0.5; 
    gl_FragColor = vec4(sdfHeart2(uv),1.0);
}

image.png

标准爱心

标准爱心使用和桃型爱心相同公式但修改了公式参数以及glsl部分代码调整后得到更加饱满锐利的爱心形状。爱心的中心定位在inHeart函数内部来实现而不在全局去处理了。 image.png

float isHeart (vec2 uv, vec2 center)
{
    vec2 o = (uv - center) / (0.5);
    float a = o.x * o.x + o.y * o.y - 0.3;
    float s0 = a * a * a;
    float s1 = o.x * o.x * o.y * o.y * o.y;
    return step(s0, s1);
}

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    gl_FragColor = vec4(mix(
               white,
               red,
               inHeart(uv, vec2(0.5))
           ),1.);
}

image.png

爱心动画效果

增加一个progress参数,inHeart函数增加一个size调节爱心大小,实现爱心变大效果。

float progress = 0.f;
float inHeart (vec2 uv, vec2 center, float size)
{
    if (size == 0.0) 
        return 0.0;
    vec2 o = (uv - center) / (1.6 * size); 
    float a = o.x * o.x + o.y * o.y - 0.3;
    float s0 = a * a * a;
    float s1 = o.x * o.x * o.y * o.y * o.y;
    return step(s0, s1); 
}


void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    progress = fract(.4 * iTime); 
    gl_FragColor = vec4(mix(
               white,
               red,
               inHeart(uv, vec2(0.5), progress)
           ),1.);
}

c22f080009a83a6ab2989bd3a16c2181.gif

分类:
Android
标签:
分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改