tModLoader 认识一下Shader

如果要使用着色器 建议Begin时设置BlendStateBlendState.NonPremultiplied

语义
SV_POSITION float4 作为像素作色器输入 顶点在其次座标系 xyzw 中的位置
COLOR0 float4 作为像素着色器输入 顶点的RGBA颜色
TEXCOORD0 float2 作为像素着色器输入 纹理uv坐标

Effect的引入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
private const string shader = "path";
public static Asset<Effect> Bloom { get; private set; }
static EffectAssets()
{
    Bloom = GetEffect(nameof(Bloom));
}
public static Asset<Effect> GetEffect(string name)
{
    return Request<Effect>($"{shader}{name}");
}

//其实就一行
Request<Effect>("Path");

Effect的应用时机

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//在Begin的时候说明要使用的Effect
spriteBatch.Begin(effect: exampleEffect);

//在Begin后的Draw中将会实际应用
spriteBatch.Draw(exampleTexture, texturePosition, Color.White);
spriteBatch.DrawString(exampleFont, "Hello World", textPosition, Color.White);

// For most SpriteSortMode values, actual drawing with the effect happens here
//对于 SpriteSortMode 值的效果,会在End() 时生效
spriteBatch.End();

Effect的参数更改

立即模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 指定Immediate 这回造成严重的性能问题
spriteBatch.Begin(effect: exampleEffect, sortMode: SpriteSortMode.Immediate);

// 更改Effect参数值,这会立即生效并应用!
exampleEffect.Parameters["ExampleParameter"].SetValue(1.0f);
spriteBatch.Draw(texture1, position, color);

// 再次更改 也会立即生效
exampleEffect.Parameters["ExampleParameter"].SetValue(0.5f);
spriteBatch.Draw(texture2, position, color);

// 由于处于立即模式,此end的作用也只有结束
spriteBatch.End();

批处理模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 默认使用批处理,因此只有当调用End时才会实际应用效果
spriteBatch.Begin(effect: exampleEffect);

// 更改参数并绘制内容
exampleEffect.Parameters["ExampleParameter"].SetValue(1.0f);
spriteBatch.Draw(texture1, position, color);

// 更改参数并绘制其他内容
exampleEffect.Parameters["ExampleParameter"].SetValue(0.5f);
spriteBatch.Draw(texture2, position, color);

// 对于Effect的参数值,只有在调用End时才会应用
// 也代表 0.5f 会应用于两次绘制
// 而不是每次调用都使用不同的值
spriteBatch.End();

灰度fx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
sampler uImage0 : register(s0); // 原图像
float Saturation; //灰度的强度,0全色 1全灰

struct PSINPUT{
    float4 pos : SV_POSITION;   //顶点在其次座标系 xyzw 中的位置
    float4 color : COLOR0;      //颜色
    float2 uv : TEXCOORD0;      //纹理uv坐标
};

float4 Gray(PSINPUT input) : COLOR
{
    //对材质采样
    float4 color = tex2D(uImage0, input.uv);

    //计算灰度值
    float grayscale = dot(color.rgb, float3(0.3, 0.59, 0.11));

    //创建灰色
    // float3 graycolor = float3(grayscale, grayscale, grayscale);

    //利用灰度值在给定的强度间进行平滑计算
    float3 finalcolor = lerp(grayscale, color.rgb, Saturation);

    //不干扰透明度 只干扰颜色
    return float4(finalcolor, color.a);
}

technique GrayDraw
{
    pass p0
    {
        PixelShader = compile ps_2_0 Gray();
    }
}

计算亮度fx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
sampler uImage0 : register(s0); // 原图像
float Intensity = 0.6; //亮度强度

struct PSINPUT
{
    float4 pos : SV_POSITION;   //顶点在其次座标系 xyzw 中的位置
    float4 color : COLOR0;      //颜色
    float2 uv : TEXCOORD0;      //纹理uv坐标
};

// 计算亮度的方法
float CountLight(float4 color)
{
    return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
}
// 像素着色器:接收结构体
float4 PixelLight(PSINPUT input) : COLOR0
{
    float4 color = tex2D(uImage0, input.uv);
    float val = clamp(CountLight(color) - Intensity, 0.0, 1.0);
    return color * val;
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelLight();
    }
}
使用 Hugo 构建
主题 StackJimmy 设计