0

我的朋友,教我如何用着色器制作一个简单的 2d 点光源,所以我按照他的步骤完成了!

但是发生了一些事情,灯的形状像椭圆形而不是圆形,我的朋友无法解释为什么,

你能帮我解决它,并解释它为什么会发生吗?

这是它的样子http://dl.dropbox.com/u/2553973/screengrab/PointLight_07.png

着色器代码

Texture InputTexture;

sampler InputTextureSampler = sampler_state {
    texture = <InputTexture>;
    magfilter = LINEAR;
    minfilter = LINEAR;
    mipfilter = LINEAR;
    AddressU = mirror;
    AddressV = mirror;
};

struct VertexShaderOutput
{
    float4 Position  : POSITION0;
    float2 TexCoord  : TEXCOORD0;
    float4 Color     : COLOR0;
};

float4      ambientColor = float4(1.0,1.0,1.0,0.0);
float       ambientIntensity = 0.3f;


float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    //float4 color = float4(1, 0, 0, 1);
    float4 texCol = tex2D(InputTextureSampler, input.TexCoord);

    float4 color = ambientIntensity*ambientColor;
    float dist;

    //Light 1
    float  lightRadius = 0.2f;
    float  lightIntensity = 15.0f;
    float4 lightPos = float4(0.3f,0.3f,0.0f,0); 
    float4 lightColor =  float4(0, 0, 1, 1);

        dist = distance(lightPos, input.TexCoord);
    color += saturate((lightRadius-dist)*lightIntensity)*lightColor;

    texCol = saturate(color) *texCol;


    return texCol;
}

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

XNA 代码

    GraphicsDevice.SetRenderTarget(normalRender);
    GraphicsDevice.Clear(Color.Black);
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, effectLight);
      spriteBatch.Draw(background, Vector2.Zero, Color.White);
    spriteBatch.End();

    normalRenderTexture = normalRender;

    GraphicsDevice.SetRenderTarget(null);
    GraphicsDevice.Clear(Color.Black);
    spriteBatch.Begin();
       spriteBatch.Draw(normalRenderTexture, Vector2.Zero, Color.White);
    spriteBatch.End();
4

2 回答 2

1

I think the easy way for you to achieve it, is working in screen space.

So if your screen space size is (800,600) and your background texture size is (800,600) you only have to multiply the texture coordinates por (800,600).

float ScreenWidth = 800;
float ScreenHeight = 600;

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    //float4 color = float4(1, 0, 0, 1);
    float4 texCol = tex2D(InputTextureSampler, input.TexCoord);

    float4 color = ambientIntensity*ambientColor;
    float dist;

    //Light 1
    float  lightRadius = 200; // Pixeles in screen space
    float  lightIntensity = 15.0f;
    float4 lightColor =  float4(0, 0, 1, 1);
    float2 lightPos = float2(ScreenWidth/2, ScreenHeight/2);  // Center of the screen
    float2 pixelPos = input.TexCoord.xy * float2(ScreenWidth, ScreenHeight);     

    dist = distance(lightPos, pixelPos);

    float distanceFactor = (lightRadius-dist) / lightRadius;

    color += saturate(distanceFactor *lightIntensity)*lightColor;

    texCol = saturate(color) *texCol;

    return texCol;
}

Note: If you want work with textures with different size that screen and not in position (0,0), the pixelPos calculation need more math.

于 2012-02-26T12:39:50.503 回答
1

UV 坐标分别从 0f 到 1f。这意味着 UV 空间中的 1f、1f 可能是屏幕空间中的 800,600。这意味着纵横比在 UV 空间中被“拉伸”......并且由于您的纵横比将为 4:3 或 16:9(宽度:高度),因此您会得到一个椭圆形而不是圆形。

于 2012-02-26T00:20:04.403 回答