【问题标题】:Optimization of HLSL shaderHLSL着色器的优化
【发布时间】:2013-10-29 17:01:21
【问题描述】:

我的问题是以下像素着色器 (HLSL) 编译为 68 指令(具有以下建议的优化)。但是,我想将它与着色器模型 2 一起使用,因此不幸的是我最多只能使用 64 指令。有没有人在不改变着色器结果的情况下看到任何可能的优化?

着色器将屏幕的一个或多或少的球形区域(带有正弦形边框)从 RGB 转换为白色渐变 -> 红色 -> 黑色,并进行一些额外的亮度等修改。

着色器代码为:

// Normalized timefactor (1 = fully enabled)
float timeFactor;

// Center of "light"
float x;
float y;

// Size of "light"
float viewsizeQ;
float fadesizeQ;

// Rotational shift
float angleShift;

// Resolution
float screenResolutionWidth;
float screenResolutionHeight;
float screenZoomQTimesX;

// Texture sampler
sampler TextureSampler : register(s0);

float4 method(float2 texCoord : TEXCOORD0) : COLOR0
{
// New color after transformation
float4 newColor;

// Look up the texture color.
float4 color = tex2D(TextureSampler, texCoord);

// Calculate distance
float2 delta = (float2(x, y) - texCoord.xy)
             * float2(screenResolutionWidth, screenResolutionHeight);

// Get angle from center
float distQ = dot(delta, delta) - sin((atan2(delta.x, delta.y) + angleShift) * 13) * screenZoomQTimesX;

// Within fadeSize
if (distQ < fadesizeQ)
{
   // Make greyscale
   float grey = dot(color.rgb, float3(0.3, 0.59, 0.11));

   // Increase contrast by applying a color transformation based on a quasi-sigmoid gamma curve
   grey = 1 / (1 + pow(1.25-grey/2, 16) );

   // Transform Black/White color range to Black/Red/White color range
   // 1 -> 0.5f ... White -> Red
   if (grey >= 0.75)
   {
   newColor.r = 0.7 + 0.3 * color.r;
   grey = (grey - 0.75) * 4;
   newColor.gb = 0.7 * grey + 0.3 * color.gb;
   }
   else // 0.5f -> 0 ... Red -> Black
   {
   newColor.r = 1.5 * 0.7 * grey + 0.3 * color.r;
   newColor.gb = 0.3 * color.gb ;
   }

   // Within viewSize (Full transformation, only blend with timefactor)
   if (distQ < viewsizeQ)
   {
 color.rgb = lerp(newColor.rgb, color.rgb, timeFactor);
   }
   // Outside viewSize but still in fadeSize (Spatial fade-out but also with timefactor)
   else
   {
      float factor = timeFactor * (1 - (distQ  - viewsizeQ) / (fadesizeQ - viewsizeQ));
      color.rgb = lerp(newColor.rgb, color.rgb, factor);
   } 
}

【问题讨论】:

    标签: optimization xna shader hlsl pixel-shader


    【解决方案1】:

    还有一些零碎的东西,你有 x,y 表示光中心 + 屏幕宽度/高度。

    替换为:

    float2 light;
    float2 screenResolution;
    

    然后在你的代码中:

    float2 delta = (light - texCoord.xy) * screenResolution;
    

    应该再删除 2 条指令。

    接下来是atan2的使用,可能是最饿的那个了。

    您可以声明另一个 float2 (float2 vecshift),其中 x = cos(AngleShift) 和 y = sin(angleShift)。只需在 CPU 中预先计算这个。

    然后你可以做以下事情(基本上是做一个叉积来提取角度而不是使用atan2):

    float2 dn = normalize(delta);
    float cr = dn.x *vecshift.y -dn.y * vecshift.x;
    float distQ = dot(delta, delta) - sin((asin(cr))*13) *screenZoomQTimesX;
    

    请注意,我不太热衷于某事的罪恶,但多项式形式不适合您的用例。我敢肯定有一个比使用 sin*asin tho 更干净的版本来调制))

    使用 ?构造而不是 if/else 也可以(有时)帮助您的指令计数。

    color.rgb = lerp(newColor.rgb, color.rgb, distQ < viewsizeQ ? timeFactor : timeFactor * (1 - (distQ  - viewsizeQ) / (fadesizeQ - viewsizeQ)));
    

    确实减少了 2 条指令。

    这里是完整版,设置为 60 条指令。

    // Normalized timefactor (1 = fully enabled)
    float timeFactor;
    
    float2 light;
    
    float viewsizeQ;
    float fadesizeQ;
    
    float2 screenResolution;
    float screenZoomQTimesX;
    
    float2 vecshift;
    
    // Texture sampler
    sampler TextureSampler : register(s0);
    
    float4 method(float2 texCoord : TEXCOORD0) : COLOR0
    {
    // New color after transformation
    float4 newColor;
    
    // Look up the texture color.
    float4 color =tex2D(Samp, texCoord);
    
    // Calculate distance
    float2 delta = (light - texCoord.xy) * screenResolution;
    
    float2 dn = normalize(delta);
    float cr = dn.x *vecshift.y -dn.y * vecshift.x;
    
    float distQ = dot(delta, delta) - sin((asin(cr))*13) *screenZoomQTimesX;
    //float distQ = dot(delta, delta) - a13 *screenZoomQTimesX;
    
    if (distQ < fadesizeQ)
    {
       // Make greyscale
       float grey = dot(color.rgb, float3(0.3, 0.59, 0.11));
    
       // Increase contrast by applying a color transformation based on a quasi-sigmoid gamma curve
       grey = 1 / (1 + pow(1.25-grey/2, 16) );
    
       // Transform Black/White color range to Black/Red/White color range
       // 1 -> 0.5f ... White -> Red
       if (grey >= 0.75)
       {
           newColor.r = 0.7 + 0.3 * color.r;
           grey = (grey - 0.75) * 4;
           newColor.gb = 0.7 * grey + 0.3 * color.gb;
       }
       else // 0.5f -> 0 ... Red -> Black
       {
           newColor.r = 1.5 * 0.7 * grey + 0.3 * color.r;
           newColor.gb = 0.3 * color.gb ;
       }
    
       color.rgb = lerp(newColor.rgb, color.rgb, distQ < viewsizeQ ? timeFactor : timeFactor * (1 - (distQ  - viewsizeQ) / (fadesizeQ - viewsizeQ)));
    }
    return color;
    
    }
    

    【讨论】:

      【解决方案2】:

      几个建议

      • 您可以为您的准 sigmoid 使用一维采样器(作为查找表)。如果 power 从 0 变为 1,则创建 1 x 256 的纹理(或任何水平尺寸最能保留您的功能)并使用 tex1D 简单地查找当前 power 的值。您需要在 CPU 上运行此函数来填充此纹理,但它只会在加载期间完成一次。
      • 您可以使用lerp 函数而不是将其拼写为color.rgb = /*0.7 */ factor * newColor.rgb + /*0.3 **/ (1 - factor) * color.rgb;,而是使用color.rgb = lerp(newColor.rgb, color.rgb, factor);(lerp 通常在大多数 GPU 上编译为汇编指令),从而节省您的指令。

      【讨论】:

      • 感谢您的建议!如何在 HLSL 中实现查找表 - 你能给我一个例子吗?上面代码中哪一部分可以通过lerp指令进行优化?
      • 添加了解释作为上述答案的一部分。
      • 谢谢,lerp(现在包含在上面的着色器代码中)保存了一条指令,它使我们达到了 68(从 69)。
      • 你试过查找表了吗?那应该再把它拿下来。
      • 还没有,但我会尽快尝试。
      【解决方案3】:

      使用更多的 lerps,我能够得到低于 64 条指令的指令。查找表没有帮助,因为 atan2 实际上导致的指令比查找纹理要少。

      // Normalized timefactor (1 = fully enabled)
      float timeFactor;
      
      // Center of "light"
      float x;
      float y;
      
      // Size of "light"
      float viewsizeQ;
      float fadesizeQ;
      
      // Rotational shift
      float angleShift;
      
      // Resolution
      float screenResolutionWidth;
      float screenResolutionHeight;
      float screenZoomQTimesX;
      
      // Texture sampler
      sampler TextureSampler : register(s0);
      
      float4 method(float2 texCoord : TEXCOORD0) : COLOR0
      {
      float4 newColor;
      
      // Look up the texture color.
      float4 color = tex2D(TextureSampler, texCoord);
      
      // Calculate distance
      float2 delta = (float2(x, y) - texCoord.xy)
                   * float2(screenResolutionWidth, screenResolutionHeight);
      
      // Get angle from center
      float distQ = dot(delta, delta) - sin((atan2(delta.x, delta.y) + angleShift) * 13) * screenZoomQTimesX;
      
      // Outside fadeSize: No color transformation
      if (distQ >= fadesizeQ) return color;
      
      // Otherwise (within color transformed region) /////////////////////////////////////////////////////////
      
      // Make greyscale
      float grey = dot(color.rgb, float3(0.3, 0.59, 0.11));
      
      // Increase contrast by applying a color transformation based on a quasi-sigmoid gamma curve
      grey = 1 / (1 + pow(1.25-grey/2, 16));
      
      // Transform greyscale to white->red->black gradient
      // 1 -> 0.5f ... White -> Red
      if (grey >= 0.5)
      {
      newColor = lerp(float4(0.937,0.104,0.104,1), float4(1,1,1,1), 2 * (grey-0.5)
      }
      else // 0.5f -> 0 ... Red -> Black
      {
      newColor = lerp(float4(0,0,0,1), float4(0.937,0.104,0.104,1), 2 * grey);
      }
      
      float factor = saturate(timeFactor * (1 - (distQ  - viewsizeQ) / (fadesizeQ - viewsizeQ)));
      color.rgb = lerp(color.rgb, newColor.rgb, factor);
      
      return color;
       }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-06
        • 2017-07-03
        • 1970-01-01
        • 2019-03-04
        相关资源
        最近更新 更多