2011-03-01 30 views
9

我正在嘗試編寫一個非常簡單的着色器,它將隨機閃爍添加到適用的對象中。我希望這樣做的方法是在像素着色器中爲像素值添加隨機陰影(R = G = B)。我可以在像素着色器中生成一個隨機數嗎?

看來,noise()不工作,我希望它的方式:

float multiplier = noise(float3(Input.Position[0], Input.Position[1], time)); 

它給了我「錯誤X4532:不能映射表達像素着色指令集」指的是呼叫noise()

由於我不知道如何在調用着色器之間保留一個數字,我不認爲我可以根據渲染前傳入的種子編寫一個簡單的隨機數生成函數。

有沒有辦法在像素着色器中產生一個隨機數?如果有辦法,怎麼樣?

回答

5

沒有什麼說你必須重複使用隨機發生器的種子從運行到運行,你只需要任何種子。如果你使用像素座標,那麼你將得到一個確定性的結果(即像素x,y總是會有相同的隨機光暈),但整體而言,整個人臉將隨機分佈。

現在,如果您有可用的輸入信息,這些信息會根據環境而改變(我對像素着色器沒有任何瞭解),比如場景/相機組合中全局空間像素的整體位置相對於多邊形本身,那麼,尤其是在快速移動的環境中,您的結果將會有效地隨機。

如果全球環境中的一切恰好相同,那麼,是的,你將擁有完全相同的「隨機」分佈。但是這些因素中的任何一個都會改變(特別是基於用戶輸入,它可能是你最有活力的「噪聲源」),那麼整體效果可能會「足夠隨機」。

所以,關鍵是要避免你的種子不必是以前運行隨機數生成器的結果。它可以是任何東西。因此,根據着色器對您自己的RNG的輸入爲每個像素設計一個種子,可能會爲您提供所需的效果。

+0

雖然這兩個答案都有幫助,但這個更適合我所尋找的。謝謝! – chaosTechnician 2011-03-06 03:22:31

8

當你想要一個像素着色器中的隨機值時,你通常會做的是傳遞一個包含噪聲的紋理。雖然它實際上不是「隨機」 - 它看起來隨機。

例如,這裏是從像素着色器的一些代碼,我已經躺在附近:

float3 random = (tex2D(noiseTexture, texCoord * noiseScale + noiseOffset)); 

我使用的紋理是RGB噪聲紋理,它可以派上用場了一些時間。但是同樣的技術可以用於灰度級。

通過縮放它,我確保了噪點紋理中的像素與屏幕像素對齊(您可能還希望將紋理採樣器設置爲「點」模式,以免模糊噪點紋理)。

通過使用偏移量,您可以滾動紋理 - 這就像播種隨機數發生器。如果要避免「滾動」外觀,請使用隨機偏移量。

24

更新2017年7月:我做了 「僞隨機性」 更穩定

// Version 3 
float random(vec2 p) 
{ 
    vec2 K1 = vec2(
     23.14069263277926, // e^pi (Gelfond's constant) 
     2.665144142690225 // 2^sqrt(2) (Gelfondâ€「Schneider constant) 
    ); 
    return fract(cos(dot(p,K1)) * 12345.6789); 
} 

這是版本:

float random(vec2 p) 
{ 
    // e^pi (Gelfond's constant) 
    // 2^sqrt(2) (Gelfond–Schneider constant) 
    vec2 K1 = vec2(23.14069263277926, 2.665144142690225); 

    //return fract(cos(mod(12345678., 256. * dot(p,K1)))); // ver1 
    //return fract(cos(dot(p,K1)) * 123456.); // ver2 
    return fract(cos(dot(p,K1)) * 12345.6789); // ver3 
} 

// Minified version 3: 
float random(vec2 p){return fract(cos(dot(p,vec2(23.14069263277926,2.665144142690225)))*12345.6789);} 

在紋理產生噪聲傳遞(通常)超過工程設計。有些時候它很方便,但是對於大多數情況,只需計算一個隨機數就簡單快捷。

由於着色器變量是獨立於每個片段的,因此它們無法在它們之間重新使用現有變量。問題就成爲如何使用「好」隨機數種子的問題之一。不合理的數字似乎符合開始的法案。那麼選擇一個好的「排列」功能只是一個'簡單'的問題。

下面是一些免費代碼做的伎倆:

// Input: It uses texture coords as the random number seed. 
// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. 
// Author: Michael Pohoreski 
// Copyright: Copyleft 2012 :-) 
// NOTE: This has been upgraded to version 3 !! 
float random(vec2 p) 
{ 
    // We need irrationals for pseudo randomness. 
    // Most (all?) known transcendental numbers will (generally) work. 
    const vec2 r = vec2(
    23.1406926327792690, // e^pi (Gelfond's constant) 
    2.6651441426902251); // 2^sqrt(2) (Gelfond–Schneider constant) 
    return fract(cos(mod(123456789., 1e-7 + 256. * dot(p,r)))); 
} 

要理解它是如何工作的,如果我們打破公式分解成它的組成部分變得更容易想象這是怎麼回事:

const vec2 k = vec2(23.1406926327792690,2.6651441426902251); 
float rnd0(vec2 uv) {return dot(uv,k); } 
float rnd1(vec2 uv) { return 1e-7 + 256. + dot(uv,k); } 
float rnd2(vec2 uv) { return mod(123456789., 256. * dot(uv,k)); } 
float rnd3(vec2 uv) { return cos(mod(123456789., 256. * dot(uv,k))); } 

// We can even tweak the formula 
float rnd4(vec2 uv) { return fract(cos(mod(1234., 1024. * dot(uv,k)))); } 
float rnd5(vec2 uv) { return fract(cos(mod(12345., 1024. * dot(uv,k)))); } 
float rnd6(vec2 uv) { return fract(cos(mod(123456., 1024. * dot(uv,k)))); } 
float rnd7(vec2 uv) { return fract(cos(mod(1234567., 1024. * dot(uv,k)))); } 
float rnd8(vec2 uv) { return fract(cos(mod(12345678., 1024. * dot(uv,k)))); } 
float rnd9(vec2 uv) { return fract(cos(mod(123456780., 1024. * dot(uv,k)))); } 

void mainImage(out vec4 fragColor, in vec2 fragCoord) 
{ 
    mediump vec2 uv = fragCoord.xy/iResolution.xy; 
    float i = rnd9(uv); 
    fragColor = vec4(i,i,i,1.); 
} 

粘貼到上述:

我還創建與2層噪聲的功能,和圖2個隨機函數 「比較」 ShaderToy例如:

演示「[2TC 15]散斑交叉淡出」

「經典」隨機函數,有時也被稱爲snoise3是這樣bad one

return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); 

如果你想比較「僞隨機」功能檢查Dave的Hash without sine着色器。

+0

好的:D謝謝! – Raptormeat 2012-09-16 08:36:12

+0

有趣。雖然我不同意紋理方法是過度工程。您正在交易紋理提取以獲取不重要的指令。而且你仍然必須通過每幀的隨機偏移。我會說這兩種方法都是有效的。 – 2012-10-10 12:07:58

+0

@AndrewRussell隨着現代GPU的(通常)做計算(CPU綁定)然後紋理查找(IO綁定)是(通常)快得多。如果你需要每個像素有一個「隨機」數字,只需傳入紋理座標就很簡單。我通常把這個詞放在括號裏,因爲* * * *平臺的唯一方法就是同時處理這兩個問題。 ;-) – Michaelangel007 2012-10-11 19:36:25

相關問題