5

我有以下像素着色器(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);
   } 
}
4

3 回答 3

5

也有一些零碎的东西,你有 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;

}
于 2013-11-04T14:13:35.943 回答
4

几个建议

  • 您可以为准 sigmoid 使用一维采样器(作为查找表)。如果power从 0 到 1,则创建 1 x 256 的纹理(或任何水平尺寸最能保留您的功能),并简单地power使用tex1D查找当前的值。您需要在 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 上编译为汇编指令),从而节省您的指令。
于 2013-10-29T18:10:12.860 回答
1

使用更多的 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;
 }
于 2013-11-03T00:17:06.763 回答