跳过正文

重生之我在OBS写Shader——OBS ShaderFilter插件

·1468 字·3 分钟
杂谈 Shader Animation OBS 渲染 色彩 插件
AxonSin
作者
AxonSin
梦想是复活在赛博世界,成为一名赛博垃圾人。

OBS ShaderFilter是一个可以使用HLSL/GLSL对图层进行处理的插件,而且内部会有很多OBS原生并不会带有的滤镜,比如box模糊和一堆搞怪滤镜。https://obsproject.com/forum/resources/obs-shaderfilter.1736/

直接下载exe文件,可以直接锁定到OBS目录并安装,还是很方便的。

使用方法
#

安装后,对某个图层右键——滤镜——+User Defined Filter。在这里你可以选择使用effect文件、还是shader文件、亦或是直接自行输入hlsl。

当然我自己的话比较熟悉HLSL,对于HLSL的一些函数比较眼熟,所以我偏向于直接用HLSL。当然用OpenGL也不是不行,要在快捷方式和高级设置中稍微改一下即可。

如何让OBS启用OpenGL渲染?
#

因为程序会优先启动微软的DirectX渲染,也就是hlsl,但是如果偏要使用OpenGL也是可以的。

Step1. 增加 –allow-opengl 启动参数,选中OBS快捷方式,在目标后面增加**** –allow-opengl

Step2. 设置中进行切换

进入obs设置界面,在 高级-视频-渲染器 中切换到OpenGL,切换应用设置之后需要重启

关于OBS和ShaderToy一些系统变量的变换
#

ShaderToy会有这些基础变量:

  • iTime:时间
  • iResolution:屏幕分辨率

OBS(hlsl)则会有这些变量:

  • elapsed_time:OBS的时间变量
  • uv_size :uv大小

同时由于语言不同,一些运算函数也会有所不同。比如HLSL需要使用fract()fract2()函数实现GLSL的mod()计算。

最后奉上一个我自己转换的shader;

// 立体线框立方体着色器 - 从Shadertoy (https://shadertoy.com/view/McS3DW) 转换为OBS格式

uniform float speed<
    string label = "动画速度";
    string widget_type = "slider";
    float minimum = 0.0;
    float maximum = 200.0;
    float step = 0.01;
> = 100.0;

uniform float thickness<
    string label = "线条粗细";
    string widget_type = "slider";
    float minimum = 0.1;
    float maximum = 50.0;
    float step = 0.1;
> = 15.0;

uniform float scale<
    string label = "图案缩放";
    string widget_type = "slider";
    float minimum = 1.0;
    float maximum = 50.0;
    float step = 0.1;
> = 10.0;

uniform float4 line_color<
    string label = "线条颜色";
    string widget_type = "color";
> = {1.0, 1.0, 1.0, 1.0};

uniform float opacity<
    string label = "整体不透明度";
    string widget_type = "slider";
    float minimum = 0.0;
    float maximum = 1.0;
    float step = 0.01;
> = 1.0;

// 辅助函数
float fract(float v){
    return v - floor(v);
}

float2 fract2(float2 v){
    return float2(v.x - floor(v.x), v.y - floor(v.y));
}

// 计算点到线段的距离
float segment(float2 p, float2 a, float2 b) {
    p -= a;
    b -= a;
    return length(p - b * clamp(dot(p, b) / dot(b, b), 0.0, 1.0));
}

// 旋转函数
float2 rotate(float2 p, float a) {
    float c = cos(a);
    float s = sin(a);
    return float2(p.x * c - p.y * s, p.x * s + p.y * c);
}

// 使用旋转变换3D点(现在接受旋转值作为参数,而不是使用全局变量)
float2 T(float3 p, float rotation) {
    p.xy = rotate(p.xy, -rotation);
    p.xz = rotate(p.xz, 0.785); // 约45度
    p.yz = rotate(p.yz, -0.625); // 约-36度
    
    return p.xy;
}

float4 mainImage(VertData v_in) : TARGET {
    // 采样背景图像
    float4 originalColor = image.Sample(textureSampler, v_in.uv);
    
    float2 R = uv_size;
    float2 u = v_in.uv;
    u.y = 1.0 - u.y; // 翻转Y坐标以匹配Shadertoy
    u = u * R; // 从0-1范围转换为像素坐标
    
    // 计算图案坐标
    float2 X, U = scale * u / R.y;
    float2 M = float2(2.0, 2.3); // 平铺大小
    float2 I = floor(U/M)*M;
    float2 J;
    
    // 计算平铺模数
    U = fract2(U/M)*M;
    
    // 初始无线条
    float lineIntensity = 0.0;
    
    // 绘制2x2网格中的四个瓦片
    for (int k = 0; k < 4; k++) {
        X = float2(k % 2, k / 2) * M;
        J = I + X;
        
        // 偏移每隔一个瓦片以增加视觉效果
        if (int((J.x / M.x) + (J.y / M.y)) % 2 > 0) X.y += 1.15;
        
        // 计算时间依赖的旋转(现在作为局部变量)
        float adjustedTime = elapsed_time * speed / 100.0;
        float t_rotation = tanh(-0.2 * (J.x + J.y) + fract(2.0 * adjustedTime / 10.0) * 10.0 - 1.6) * 0.785;
        
        // 绘制立方体的六个部分(共12条线)
        for (float a = 0.0; a < 6.0; a += 1.57) { // 每约90度
            float3 A = float3(cos(a), sin(a), 0.7);
            float3 B = float3(-A.y, A.x, 0.7);
            
            // 绘制立方体边缘的线条,将旋转值作为参数传递
            lineIntensity += smoothstep(thickness/R.y, 0.0, segment(U-X, T(A, t_rotation), T(B, t_rotation)));
            lineIntensity += smoothstep(thickness/R.y, 0.0, segment(U-X, T(A, t_rotation), T(A * float3(1.0, 1.0, -1.0), t_rotation)));
            
            // 镜像点用于立方体背面
            A.z = -A.z; 
            B.z = -B.z;
            lineIntensity += smoothstep(thickness/R.y, 0.0, segment(U-X, T(A, t_rotation), T(B, t_rotation)));
        }
    }
    
    // 限制值避免线条重叠区域过亮
    lineIntensity = min(lineIntensity, 1.0);
    
    // 应用线条颜色并与原始图像混合
    float4 finalColor = float4(
        lerp(originalColor.rgb, line_color.rgb, lineIntensity * opacity),
        originalColor.a
    );
    
    return finalColor;
}
Reply by Email

相关文章

TBDR+Forward vs. IMR+Deferred_ 两种设备的不同权衡
·6830 字·14 分钟
杂谈 Shader Animation 渲染 材质 光照 算法 色彩
算法原理解析
Unity的Post-Processing标准(V1、V2、V3)
·1020 字·3 分钟
杂谈 Unity Shader Git 渲染 色彩 配置 插件
Unity的Post-Processing标准
quixel导入blender的bl插件以及中文化适配&bug修改
·3382 字·7 分钟
杂谈 Unity Blender Shader 渲染 材质 色彩 插件
Blender导入Unity指南