HLSL着色器的优化

标签 optimization xna shader hlsl pixel-shader

我的问题是下面的像素着色器 (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);
   } 
}

最佳答案

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

请注意,我不太热衷于 asin of something,但多项式形式不适合您的用例。我确信有一个比使用 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;

}

关于HLSL着色器的优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19664643/

相关文章:

algorithm - 模拟退火中的概率计算和比较

C#:XNA 与无 XNA(性能)

c++ - 读取dll文件中的文本文件

c - 在 C : Is it faster to access a char* = malloc() used like a 2D array than an array[][]?

将 32 位数字转换为 16 位或更少

linux - 优化 Bash 脚本,移除 subshel​​l

C# XNA 桨球游戏

c# - 如何让敌人面对角色

opengl - GLSL 物体发光

iOS Metal 计算管道比搜索任务的 CPU 实现慢