2D Point Light XNA, Почему мой точечный световой радиус является овальным? - PullRequest
0 голосов
/ 26 февраля 2012

Я мой друг, научил меня, как сделать простой 2-точечный свет с помощью шейдера, так что я следую его шагам и, наконец, сделал это!

но что-то случилось, светлая форма похожа на овал, а не на круг, мои друзья не могли объяснить, почему,

Не могли бы вы помочь мне, как это исправить, и объясните, почему это произошло?

вот как это выглядит 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();

Ответы [ 2 ]

1 голос
/ 26 февраля 2012

Я думаю, что самый простой способ добиться этого - работать в пространстве экрана.

Так что, если ваш размер экрана (800 600) и размер фоновой текстуры (800 600), вам нужно только умножить координаты текстуры 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;
}

Примечание. Если вы хотите работать с текстурами с другим размером экрана и не в позиции (0,0), для вычисления pixelPos потребуется больше математики.

1 голос
/ 26 февраля 2012

U-V координаты от 0f до 1f каждая. Это означает, что 1f, 1f в пространстве U-V может быть 800 600 в пространстве экрана. Это означает, что соотношение сторон «растягивается» в пространстве U-V ... и поскольку ваше соотношение сторон будет 4: 3 или 16: 9 (ширина: высота), вы получите овал вместо круга.

...