2012-05-27 102 views
0

我目前正在爲我的XNA遊戲開發一個類,用於渲染圖像上的燈光。當時,我已經讓源代碼繪製了我的光照貼圖,但是,我的來源中FPS非常低。我知道它在循環遍歷每個像素時被殘酷地減少了,但是,我不知道任何其他方式來讓我的紋理在XNA中設置每個像素,但使用「For」語句?燈光渲染效果低FPS

電流源:

public struct Light 
    { 
     public int Range; 
     public int Intensity; 
     public Color LightColor; 
     public Vector2 LightLocation; 

     public Light(int _Range, int _Intensity, Color _LightColor, Vector2 _LightLocation) 
     { 
      Range = _Range; 
      Intensity = _Intensity; 
      LightLocation = _LightLocation; 
      LightColor = _LightColor; 
     } 
    } 
    public class RenderClass 
    { 
     [System.Runtime.InteropServices.DllImport("User32.dll")] 
     public static extern bool MessageBox(IntPtr h, string S, string C, int a); 

     public static Texture2D RenderImage(Light[] LightLocations, Texture2D ScreenImage, Viewport v, bool ShadowBack = false) 
     { 
      Texture2D[] Images = new Texture2D[LightLocations.Count()]; 
      int curCount = 0; 

      /*LOOP THROUGHT EACH LIGHT*/ 
      foreach (Light LightLocation in LightLocations) 
      { 
       /*VARIABLES*/ 
       Color LightColor = LightLocation.LightColor; 
       int Range = LightLocation.Range; 
       int Intensity = LightLocation.Intensity; 

       /*GET COLORS*/ 
       int Width = v.Width; 
       int Height = v.Height; 
       Color[] Data = new Color[Width * Height]; 
       ScreenImage.GetData<Color>(Data); 

       /*VARIABLES TO SET COLOR*/ 
       Color[] SetColorData = new Color[Width * Height]; 

       /*CIRCEL*/ 
       int Radius = 15/2; // Define range to middle [Radius] 
       int Area = (int)Math.PI * (Radius * Radius); 

       for (int X = 0; X < Width; X++) 
       { 
        for (int Y = 0; Y < Height; Y++) 
        { 
         int Destination = X + Y * Width; 

         #region Light 
         /*GET COLOR*/ 
         Color nColor = Data[Destination]; 

         /*CREATE NEW COLOR*/ 
         Vector2 MiddlePos = new Vector2(LightLocation.LightLocation.X + Radius, LightLocation.LightLocation.Y + Radius); 
         Vector2 CurrentLocation = new Vector2(X, Y); 

         float Distance; 
         Distance = Vector2.Distance(MiddlePos, CurrentLocation); 
         Distance *= 100; 
         Distance /= MathHelper.Clamp(Range, 0, 100); 

         Vector3 newColors = nColor.ToVector3(); 

         nColor = new Color(
          newColors.X, 
          newColors.Y, 
          newColors.Z, 
          Distance/100); 


         /*SET COLOR*/ 
         SetColorData[Destination] = nColor; // Add to array 
         #endregion 
         #region Shadow 
         #endregion 
        } 
       } 


       ScreenImage.SetData<Color>(SetColorData); 
       Images[curCount] = ScreenImage; 
       curCount++; 
      } 

      return Images[0]; // Temporarily returning the first image of the array. 
     } 
    } 

正如你可以看到,這是一個緩慢而壞的方法。所以我想知道,有沒有更好的方法來設置每個像素&?

在此先感謝,dotTutorials! =)

+0

「OppositeColor」代表有什麼意義? –

+0

更早使用它。我的壞,我在這個來源非常混亂,atm。修復它現在=) – dotTutorials

+0

也許你應該清理它;刪除一些不必要的對象創建(例如Vector2 MiddlePos/CurrentLocation來計算距離),並可能對處理時間進行基準測試。我不知道是否有一種更有效的方法可以達到與您所要求的相同的整體效果,但是如果您循環渲染視圖中的每個像素,每個幀,那麼內部循環需要優化爲儘可能多。 –

回答

1

我認爲這項工作最好在像素着色器中完成。

您可以創建一次操作一盞燈的效果文件。
XNA使用DX9,因此您將被限制爲128個常量寄存器,我認爲您可以使用它來擠壓三盞燈。

因此,您將光照貼圖設置爲渲染目標,循環遍歷所有燈光,在效果上設置常量數據,渲染渲染目標大小的四邊形,並在像素着色器中計算光照方程。

在本質上類似的東西:

// In LoadContent 
RenderTarget2D lightmapRT = new RenderTarget2D(graphics.GraphicsDevice, 
               128, 
               128, 
               false, //No mip-mapping 
               SurfaceFormat.Color, 
               DepthFormat.Depth24); 

// We now render to the lightmap in Render method 
graphics.GraphicsDevice.SetRenderTarget(lightmapRT); 

// Lightmap is black by default 
graphics.GraphicsDevice.Clear(Color.Black); 

// Use the sprite batch to draw quads with custom shader 
spriteBatch.Begin(0, BlendState.Opaque, null, null, null, lightmapFx); 

foreach (var light in lights) 
{ 
    // Pass the light parameters to the shader 
    lightmapFx.Parameters["Viewport"].SetValue(new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height)); 
    lightmapFx.Parameters["Range"].SetValue(light.Range); 
    lightmapFx.Parameters["Intensity"].SetValue(light.Intensity); 
    lightmapFx.Parameters["LightColor"].SetValue(light.LightColor); 
    lightmapFx.Parameters["LightLocation"].SetValue(light.LightLocation); 

    // Render quad 
    spriteBatch.Draw(...); 
} 
spriteBatch.End(); 

與FX文件看起來類似的東西:

float Range; 
float Intensity; 
float3 LightColor; 
float2 LightLocation; 
float2 Viewport; 

struct VStoPS 
{ 
    float4 Position : POSITION0; 
    float2 TexCoord : TEXCOORD0; 
}; 

VStoPS VS(in float4 color : COLOR0, 
      in float2 texCoord : TEXCOORD0, 
      in float4 position : POSITION0) 
{ 
    VStoPS vsout = (VStoPS)0; 

    // Half pixel offset for correct texel centering. 
    vsout.Position.xy -= 0.5; 

    // Viewport adjustment. 
    vsout.Position.xy = position.xy/Viewport; 
    vsout.Position.xy *= float2(2, -2); 
    vsout.Position.xy -= float2(1, -1); 

    // Pass texcoords as is 
    vsout.TexCoord = texCoord; 

    return vsout; 
} 

float4 PS(VStoPS psin) 
{ 
    // Do calculations here 
    // Here I just set it to white 
    return float4(1.0f, 1.0f, 1.0f, 1.0f); 
} 

technique Main 
{ 
    pass p0 
    { 
     VertexShader = compile vs_3_0 VS(); 
     PixelShader = compile ps_3_0 PS(); 
    } 
} 

注意,這種非測試代碼,並可能完全錯誤的。我把它留給你來弄清楚在像素着色器中需要做什麼。