Frage

I friend of mine , taught me how to make a simple 2d point light with shader, so i follow his steps and finally done it !

but something happend , the light shape is like an oval and not like a circle , my friends couldnt explain me why,

could you help me how to fix it, and explain me why it happend?

here is how it looks like http://dl.dropbox.com/u/2553973/screengrab/PointLight_07.png

ShaderCode

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 CODE

    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();
War es hilfreich?

Lösung

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.

Andere Tipps

U-V coordinates are from 0f to 1f each. This means that 1f, 1f in U-V space may be 800,600 in screenspace. What this means is that the aspect ration gets "stretched" in U-V space... and since your aspect ratio will be 4:3 or 16:9 (width:height), you get an oval instead of a circle.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top