2013-10-29 200 views
5

我有一個問題,下面的像素着色器(HLSL)編譯爲指令(使用下面的建議優化)。但是,我想將它與着色器模型2一起使用,因此不幸的是,我只能使用最多指令。有沒有人看到任何可能的優化而不改變着色器的結果?HLSL着色器的優化

着色器將屏幕(帶有正弦形邊框)的或多或少球形區域從RGB轉換爲白色 - >紅色 - >黑色的漸變,並具有一些額外的亮度等修改。

的shader代碼是:

// 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); 
    } 
} 

回答

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; 

請注意:不是我不上的東西ASIN的罪惡過於激烈,但多項式表單不適合你的用例。我敢肯定有一個更清潔的版本來調製比使用sin * asin壽))

使用?構造而不是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; 

} 
4

一些建議

  • 你可以使用一維採樣(查找表)爲您準乙狀結腸。如果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上的彙編指令),從而爲您節省指令。
+0

感謝您的建議!我如何在HLSL中實現查找表 - 你能給我一個例子嗎?上述代碼的哪一部分可以通過lerp指令進行優化? –

+1

作爲上述答案的一部分添加了解釋。 – Ani

+0

謝謝,lerp(現在包含在上面的着色器代碼中)保存了一條指令,使我們達到68(從69)。 –

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; 
}