为什么XNA 4.0 HLSL像素着色器影响整个纹理,而不是像素一样工作?

时间:2013-01-18 02:39:56

标签: shader xna-4.0 hlsl

我正在尝试实施2D照明系统来学习如何使用着色器。我今晚刚刚开始运行第一台着色器。

目前,游戏非常简单,我只是使用此代码在后台渲染80x80px图块。

protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);

        Texture2D tile = this.Content.Load<Texture2D>("tile");

        Effect effect = this.Content.Load<Effect>("test");

        MouseState ms = Mouse.GetState();

        effect.Parameters["LightPosition"].SetValue(new Vector2(ms.X, ms.Y));

        spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, effect);

        for (int row = 0; row < 10; row++)
        {
            for (int col = 0; col < 6; col++)
            {
                Vector2 tilePos = new Vector2(row * 80, col * 80);
                effect.Parameters["TilePosition"].SetValue(tilePos);
                spriteBatch.Draw(tile, tilePos, Color.White);
            }
        }
        spriteBatch.End();

        // TODO: Add your drawing code here

        base.Draw(gameTime);
    }

我想要做的是让鼠标指针作为光源,然后计算鼠标位置和每个图块上每个像素位置之间的差异(毕达哥拉斯),并使用它逐渐变暗瓷砖每个像素离鼠标指针越远。

然而,正在发生的是,任何给定图块上的所有像素一次“亮起”或“变暗”,这取决于鼠标指针离图块左上角的距离。

这是我的着色器代码。

texture TileTexture;

float2 LightPosition : VPOS;
float2 TilePosition : VPOS;

sampler TextureSampler = sampler_state
{
    Texture = <TileTexture>;
};

float4 PixelShaderFunction(float2 TextureCoordinate : TEXCOORD0) : COLOR0
{
    float4 color = tex2D(TextureSampler, TextureCoordinate);
    float x_dist;
    float y_dist;
    float distance;
    // Calculate distance formula (pythagorean - a2 = b2 + c2)
    x_dist = abs(LightPosition.x - (TextureCoordinate.x + TilePosition.x));
    y_dist = abs(LightPosition.y - (TextureCoordinate.y + TilePosition.y));
    distance = pow(x_dist, 2) + pow(y_dist, 2);
    distance = sqrt(distance);
    color.r = color.r - distance * 0.01;
    color.g = color.g - distance * 0.01;
    color.b = color.b - distance * 0.01;

    return color;
}


technique Lighting
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

奇怪的是,这段代码实际上确实影响了每个瓷砖的每个像素,而我真的没有看到我改变了什么阻止了它的工作。

float4 PixelShaderFunction(float2 TextureCoordinate : TEXCOORD0) : COLOR0
{
    float4 color = tex2D(TextureSampler, TextureCoordinate);

    //float value = (color.r + color.g + color.b) / 3; 
    color.r = color.r + TextureCoordinate.x + TextureCoordinate.y - 0.75;
    color.g = color.g + TextureCoordinate.x + TextureCoordinate.y - 0.75;
    color.b = color.b + TextureCoordinate.x + TextureCoordinate.y - 0.75;

    return color;
}

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

TEXCOORD语义不是用整数表示纹理的像素,而是用0.0到1.0的浮点值表示它们。改变这些行:

x_dist = abs(LightPosition.x - (TextureCoordinate.x + TilePosition.x));
y_dist = abs(LightPosition.y - (TextureCoordinate.y + TilePosition.y));

对此:

x_dist = abs(LightPosition.x - ((TextureCoordinate.x * 80) + TilePosition.x));
y_dist = abs(LightPosition.y - ((TextureCoordinate.y * 80) + TilePosition.y));

其中80表示纹理的高度和宽度......

解决了这个问题。