2015-06-30 133 views
5

我的目標是將一個點數組傳遞給着色器,計算它們到片段的距離並用一個帶有漸變色的圓圈繪製它們,具體取決於該計算。統一點陣列和管理片段着色器座標系統

例如:
enter image description here
(從working example I set up on shader toy

不幸的是,我不清楚我應該如何計算並通過轉換處理着色器內的座標。

我目前正在嘗試的是通過兩個浮點數組 - 一個用於x位置,一個用於每個點的y位置 - 通過統一着色器。然後着色器內通過每個點重複,像這樣:

#ifdef GL_ES 
precision mediump float; 
precision mediump int; 
#endif 

uniform float sourceX[100]; 
uniform float sourceY[100]; 
uniform vec2 resolution; 

in vec4 gl_FragCoord; 

varying vec4 vertColor; 
varying vec2 center; 
varying vec2 pos; 

void main() 
{ 
    float intensity = 0.0; 

    for(int i=0; i<100; i++) 
    { 
     vec2 source = vec2(sourceX[i],sourceY[i]); 
     vec2 position = (gl_FragCoord.xy/resolution.xy); 
     float d = distance(position, source); 
     intensity += exp(-0.5*d*d); 
    } 

    intensity=3.0*pow(intensity,0.02); 

    if (intensity<=1.0) 
     gl_FragColor=vec4(0.0,intensity*0.5,0.0,1.0); 
    else if (intensity<=2.0) 
     gl_FragColor=vec4(intensity-1.0, 0.5+(intensity-1.0)*0.5,0.0,1.0); 
    else 
     gl_FragColor=vec4(1.0,3.0-intensity,0.0,1.0); 
} 

但是,這並不工作 - 我相信這可能是因爲我努力工作,與像素不正確轉換這些座標。任何人都可以向我解釋如何使這項工作?

更新:

目前的結果是: current result 草圖的代碼是:

PShader pointShader; 

float[] sourceX; 
float[] sourceY; 


void setup() 
{ 

    size(1024, 1024, P3D); 
    background(255); 

    sourceX = new float[100]; 
    sourceY = new float[100]; 
    for (int i = 0; i<100; i++) 
    { 
    sourceX[i] = random(0, 1023); 
    sourceY[i] = random(0, 1023); 
    } 


    pointShader = loadShader("pointfrag.glsl", "pointvert.glsl"); 
    shader(pointShader, POINTS); 
    pointShader.set("sourceX", sourceX); 
    pointShader.set("sourceY", sourceY); 
    pointShader.set("resolution", float(width), float(height)); 
} 


void draw() 
{ 
    for (int i = 0; i<100; i++) { 
    strokeWeight(60); 
    point(sourceX[i], sourceY[i]); 
    } 
} 

,而頂點着色器:

#define PROCESSING_POINT_SHADER 

uniform mat4 projection; 
uniform mat4 transform; 


attribute vec4 vertex; 
attribute vec4 color; 
attribute vec2 offset; 

varying vec4 vertColor; 
varying vec2 center; 
varying vec2 pos; 

void main() { 

    vec4 clip = transform * vertex; 
    gl_Position = clip + projection * vec4(offset, 0, 0); 

    vertColor = color; 
    center = clip.xy; 
    pos = offset; 
} 
+0

你能就如何爲「不工作」展開?除了不處理點比例或視口寬高比外,沒有任何東西看起來立即錯誤。事實上,我不確定統一陣列的數量是否有限制。你如何設定他們的價值?你使用統一緩衝區嗎? – jozxyqk

+0

忽略這一點,[設置一個統一的數組](http://stackoverflow.com/a/8100273/1888983)是好的,它看起來像你不會用完[至少1024](https:/ /www.opengl.org/wiki/Uniform_(GLSL)),但你可能想看看統一的緩衝區對象。 – jozxyqk

+0

感謝您的回覆,問題在於着色器將所有圈子繪製爲黑色。從我所能得到的結果來看,d的價值存在一些問題。下面是我得到的結果:[Image](http://i.imgur.com/TIZ0TIq.png) – Giuseppe

回答

2

更新:

基礎上,似乎你混淆了兩種不同的方法的註釋:

  1. 繪製一個全屏幕的多邊形,通過在點,並使用着色器循環每個片段一旦計算出最終值。
  2. 爲每個點繪製邊界幾何圖形,計算片段着色器中僅一個點的密度,並使用加法混合來求和所有點的密度。

的另一個問題是在像素中給出你的觀點,但是代碼需要一個0到1的範圍內,所以d大,點是黑色的。解決這個問題爲@RetoKoradi describes應該解決黑點問題,但是我懷疑當很多接近時你會發現斜坡限制問題。將點傳入着色器會限制可伸縮性,並且效率不高,除非點覆蓋整個視口。

如下,我認爲堅持方法2更好。調整你的代碼它,消除環路,不點的數組中傳遞,並使用center爲點座標,而不是:

//calc center in pixel coordinates 
vec2 centerPixels = (center * 0.5 + 0.5) * resolution.xy; 

//find the distance in pixels (avoiding aspect ratio issues) 
float dPixels = distance(gl_FragCoord.xy, centerPixels); 

//scale down to the 0 to 1 range 
float d = dPixels/resolution.y; 

//write out the intensity 
gl_FragColor = vec4(exp(-0.5*d*d)); 

​​(從評論:opengl-tutorial.orgcodethis question)與添加劑blending:現在

glEnable(GL_BLEND); 
glBlendFunc(GL_ONE, GL_ONE); 

紋理將包含intensity,因爲它是你原來的循環之後。在全屏通期間另一個片段着色器(繪製一個覆蓋整個視口一個三角形),繼續:

uniform sampler2D intensityTex; 
... 
float intensity = texture2D(intensityTex, gl_FragCoord.xy/resolution.xy).r; 
intensity = 3.0*pow(intensity, 0.02); 
... 

你所示的代碼是好的,假設您繪製的全屏幕多邊形所以片段着色器爲每個像素運行一次。潛在的問題是:

  • resolution沒有範圍爲0正確
  • 點座標未設置爲1的屏幕上。
  • 儘管較小,d將被縱橫比所拉伸,所以您可能會更好地將點像素座標和潛水距離縮放resolution.y

這看起來非常類似於爲2D metaballs創建密度字段。爲了提高性能,您最好限制每個點的密度函數,以便它不會永遠持續下去,然後使用添加劑混合將光盤噴射到紋理中。這可以節省處理點不影響的像素(就像在延遲着色中一樣)。結果是密度字段,或者在您的情況下,每像素intensity

這是一個有點相關:

+0

全屏多邊形是什麼意思?從我得到的(上面的圖像)數字是正確繪製,而有關顏色的邏輯不是。我認爲這個決議是正確的 - 因爲它應該通過處理 - 但我可能對通過制服傳遞的點座標犯了一個錯誤,因爲它們不在0-1範圍內,但我隨機地初始化爲0-1023 ,因爲處理會接受:我能更好地解釋他們應該怎麼做?在面對着色器的座標之前,如何在「glsl」座標中手動轉換它們?我已經更新了第一篇文章 – Giuseppe

+0

我開始看到你的解決方案如何,希望它至少能起作用。你會介意更詳細地解釋如何進行紋理繪製嗎?我已經閱讀過你所鏈接的文件,但他們說實話對我來說並不是很清楚,我不清楚這段文字是如何做到的。或者你能否給我一個例子來開始?我發現這個[link](http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/),但我不知道它是否可以應用到您提供的解決方案。 – Giuseppe

+0

此外,是否有必要啓動另一個着色器來渲染紋理? Afaik Processing讓每個草圖渲染1個着色器,所以,我不相信(並且文檔\上的例子很少見),可以使用「數學」和另一個來有效渲染紋理。 – Giuseppe

0

它看起來像點中心和片段的位置在不同的座標空間當你減去他們:

vec2 source = vec2(sourceX[i],sourceY[i]); 
vec2 position = (gl_FragCoord.xy/resolution.xy); 
float d = distance(position, source); 

根據您的說明和代碼,sourcesource位於窗口座標中,這意味着它們以像素爲單位。 gl_FragCoord位於相同的座標空間中。即使你沒有直接顯示,我認爲resolution是以像素爲單位的窗口大小。

這意味着:

vec2 position = (gl_FragCoord.xy/resolution.xy); 

計算窗口內的片段的歸一化的位置,在範圍[0.0,1.0]爲x和y。但隨後下一行:

float d = distance(position, source); 

你部分追蹤source,這仍然是在窗口座標,在歸一化座標這個位置。

因爲它看起來像你想在歸一化座標的距離,這是有道理的,你還需要正常化source

vec2 source = vec2(sourceX[i],sourceY[i])/resolution.xy; 
+0

不知道,但我懷疑這將有長寬比問題。可能是'd = length((position-source)* vec2(resolution.x/resolution.y,1.0))'或者讓source保持原樣並且'position = gl_FragCoord.xy'後面加上'd/= resolution.y' ? – jozxyqk

+0

@jozxyqk該窗口在OP代碼中是方形的。是的,如果窗口不是方形的,這會產生省略號。 –

+0

試圖運行正常化來源你如何說,但結果是所有的圓仍然是黑色的 - 無論我如何嘗試調整gl_FragColor的值。必須有其他的東西不能工作,或者這種解決方案來獲取相同座標中的值是不正確的,因爲某些我不明白的原因。我很樂意接受任何其他想法,同時我會嘗試查看是否以及如何實施上述評論中提出的解決方案[@jozxyqk](http://stackoverflow.com/a/31141725/5065842) – Giuseppe