opengl常用形状着色器

圆角矩形

在这里插入图片描述

// 常量定义:用于设置边框的半厚度、边框颜色、填充颜色和圆角半径
const float borderHalfThickness = 2.0; // 边框的半厚度
const vec4 borderColor = vec4(1.0, 1.0, 0.0, 1.0); // 边框颜色(黄色)
const vec4 fillColor = vec4(1.0, 0.0, 0.0, 1.0); // 填充颜色(红色)
const float cornerRadius = 45.0; // 圆角半径(像素单位)

// 计算点 p 到矩形边界的有符号距离场(Signed Distance Field, SDF)
// p:相对于矩形中心的坐标
// halfSize:矩形的半尺寸
// radius:圆角半径
float computeRectSDF(vec2 p, vec2 halfSize, float radius) {
    vec2 dist = abs(p) - halfSize + vec2(radius); // 计算点到矩形的最小距离
    return min(max(dist.x, dist.y), 0.0) + length(max(dist, 0.0)) - radius; // 返回到矩形边界的距离,考虑圆角
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    // 设置矩形的半尺寸,手动定义
    vec2 halfRectSize = vec2(300.0, 150.0) - vec2(borderHalfThickness);

    // 计算当前像素相对于屏幕中心的位置
    vec2 centeredPos = fragCoord - iResolution.xy / 2.0;
    
    // 计算当前像素到矩形边界的距离(考虑圆角和边框厚度)
    float distToEdge = computeRectSDF(centeredPos, halfRectSize, cornerRadius - borderHalfThickness);

    // 使用 mix 函数替代 if 语句
    vec4 colorInside = mix(vec4(0.0, 0.0, 0.0, 0.0), fillColor, step(0.0, -distToEdge));

    // 计算边框影响下的距离
    distToEdge = abs(distToEdge) - borderHalfThickness;

    // 通过平滑插值计算混合比例,实现颜色的过渡效果
    float blendFactor = smoothstep(-1.0, 1.0, distToEdge);

    // 最终输出的颜色,通过边框颜色和目标颜色的插值实现
    fragColor = mix(borderColor, colorInside, blendFactor);
}

实心圆[效率高]

在这里插入图片描述

/**
 * @author jonobr1 / http://jonobr1.com/
 */

/**
 * Convert r, g, b to normalized vec3
 */
vec3 rgb(float r, float g, float b) {
	return vec3(r / 255.0, g / 255.0, b / 255.0);
}

/**
 * Draw a circle at vec2 `pos` with radius `rad` and
 * color `color`.
 */
vec4 circle(vec2 uv, vec2 pos, float rad, vec3 color) {
	float d = length(pos - uv) - rad;
	float t = clamp(d, 0.0, 1.0);
	return vec4(color, 1.0 - t);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {

	vec2 uv = fragCoord.xy;
	vec2 center = iResolution.xy * 0.5;
	float radius = 0.25 * iResolution.y;

    // Background layer
	vec4 layer1 = vec4(rgb(210.0, 222.0, 228.0), 1.0);
	
	// Circle
	vec3 red = rgb(225.0, 95.0, 60.0);
	vec4 layer2 = circle(uv, center, radius, red);
	
	// Blend the two
	fragColor = mix(layer1, layer2, layer2.a);

}

线条圆

在这里插入图片描述

// 定义一个宏 step(b, a),用于平滑插值计算。
// 该宏使用 smoothstep 函数计算输入 b 在区间 [a - (fwidth(b) * 2.0), a] 之间的平滑插值。
// fwidth(b) 返回输入 b 在屏幕上的微分宽度,因此该宏用于根据 b 值的变化生成平滑过渡。
#define step(b, a) smoothstep(a, a - (fwidth(b) * 2.0), b)

void mainImage(out vec4 col, in vec2 uv)
{
    // 参数定义
    float borderWidth = 0.025; // 边框宽度
    vec4 outColor = vec4(0.0, 0.0, 0.0 , 0.0); // 外部区域的颜色,初始为全透明黑色
    vec4 color = vec4(1.0, 1.0, 1.0 , 0.0); // 内部区域的颜色,初始为白色
    vec4 borderColor = vec4(0.0, 0.0, 1.0 , 0.0); // 边框颜色,初始为蓝色

    // 将屏幕空间坐标 uv 转换为以屏幕中心为原点的坐标系
    vec3 r = iResolution; // iResolution 是屏幕分辨率,r 是屏幕中心的坐标
    uv = ((2.0 * uv) - r.xy) / r.y; // 转换后的 uv 坐标以屏幕高度为单位长度,并以屏幕中心为原点

    // 计算从原点到当前像素的距离,即 Signed Distance Field (SDF)
    float sdf = length(uv);

    // 计算内部区域的平滑插值
    // 如果 sdf 小于 (1.0 - borderWidth),则 step 函数返回 1.0(即完全填充 color 的值)
    float inner = step(sdf, (1.0 - borderWidth));  

    // 计算边框区域的平滑插值
    // 如果 sdf 小于 1.0,则 step 函数返回 1.0(即完全填充 borderColor 的值)
    float borderInner = step(sdf, 1.0); 

    // 将内区域颜色与 outColor 混合,生成最终的内区域颜色
    color = mix(outColor, color, inner); // 在内部填充白色

    // 将边框颜色与前一步生成的颜色混合,生成最终的颜色
    // 边框颜色只会填充在 inner 区域外部
    color = mix(color, borderColor, borderInner * (1.0 - inner));

    // 将最终颜色赋值给输出颜色 col
    col = color;
}

多边形[抗锯齿效果]

在这里插入图片描述

// 计算向量的平方长度(即点到原点的平方距离)
float dot2( in vec2 v ) { return dot(v, v); }

// 计算两个二维向量的叉积
float cross2d( in vec2 v0, in vec2 v1 ) { return v0.x * v1.y - v0.y * v1.x; }

const int N = 5; // 定义多边形的边数,这里是一个正五边形

// 计算点 p 到多边形的最短距离
float sdPolygon( in vec2 p, in vec2[N] v )
{
    const int num = v.length(); // 获取多边形顶点的数量
    float d = dot(p - v[0], p - v[0]); // 初始化距离为点 p 到第一个顶点的距离
    float s = 1.0; // 符号,用于确定点 p 是在多边形内还是外

    // 遍历多边形的每一条边
    for( int i = 0, j = num - 1; i < num; j = i, i++ )
    {
        // 计算点 p 到边的距离
        vec2 e = v[j] - v[i]; // 边向量
        vec2 w = p - v[i];    // 点 p 到边起点的向量
        vec2 b = w - e * clamp( dot(w, e) / dot(e, e), 0.0, 1.0 ); // 点 p 到边的最近点的向量
        d = min( d, dot(b, b) ); // 更新到最短距离

        // 使用旋转数法判断点是否在多边形内
        // 条件成立时,符号 s 会翻转,用于表示点 p 在多边形内或外
        bvec3 cond = bvec3( p.y >= v[i].y, 
                            p.y < v[j].y, 
                            e.x * w.y > e.y * w.x );
        if( all(cond) || all(not(cond)) ) s = -s;  
    }
    
    return s * sqrt(d); // 返回带符号的距离,表示点 p 到多边形的有符号距离
}

// 着色器的主函数
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // 将屏幕坐标标准化到 [-1, 1] 范围
    vec2 p = (2.0 * fragCoord - iResolution.xy) / iResolution.y;

    // 将鼠标坐标也标准化到 [-1, 1] 范围
    vec2 m = (2.0 * iMouse.xy - iResolution.xy) / iResolution.y;
    
    // 动态计算五边形的顶点位置,使其随时间旋转
    vec2 v0 = 0.8 * cos( 0.40 * iTime + vec2(0.0, 2.00) + 0.0 );
    vec2 v1 = 0.8 * cos( 0.45 * iTime + vec2(0.0, 1.50) + 1.0 );
    vec2 v2 = 0.8 * cos( 0.50 * iTime + vec2(0.0, 3.00) + 2.0 );
    vec2 v3 = 0.8 * cos( 0.55 * iTime + vec2(0.0, 2.00) + 4.0 );
    vec2 v4 = 0.8 * cos( 0.60 * iTime + vec2(0.0, 1.00) + 5.0 );
    
    // 将顶点放入一个数组中,构成五边形
    vec2[] polygon = vec2[](v0, v1, v2, v3, v4);
    
    // 计算点 p 到五边形的距离
    float d = sdPolygon(p, polygon);

    // 根据距离 d 来设置颜色
    float borderLineWidth = 0.005;
    vec4 outColor = vec4(0.0,0.0,0.0,0.0);
    vec4 fillColor = vec4(0.0,0.0,0.0,1.0);
    vec4 borderColor = vec4(1.0,0.0,0.0,1.0);
    vec4 col = (d > 0.0) ? outColor : fillColor;

    // 自适应抗锯齿的计算
    float aa = fwidth(d) * 0.5; // 使用 fwidth 来自适应地调整抗锯齿
    col = mix( col, borderColor, 1.0 - smoothstep(borderLineWidth - 0.006 - aa, borderLineWidth + 0.002 + aa, abs(d)) ); 

    // 输出最终的片段颜色,alpha 通道设置为 1.0(完全不透明)
    fragColor = col;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值