2016-01-02 39 views
2

所以我有一個相當簡單的實時2D遊戲,我試圖添加一些不錯的光芒。將其簡化成最基本的形式,就是在黑色表面上繪製圓圈和謊言。如果您從hsv色彩空間角度考慮場景,所有顏色(黑色除外)的「v」值均爲100%。實時發光着色器混淆

目前我有一種「積累」緩衝區,其中當前幀與前一幀連接。它通過使用兩個離屏緩衝區和一個黑色紋理來工作。

  1. 緩衝區一個激活-------------
  2. 線和點繪製
  3. 緩衝區一個停用
  4. 緩衝兩個活化--------- ----
  5. 緩衝區繪製成FUL屏四兩個內容
  6. 黑色質地有輕微的透明度繪製在全屏
  7. 緩衝區一個內容繪製
  8. 兩臺帶緩衝區停用
  9. 屏幕緩衝激活-------
  10. 緩衝二的吸引到屏幕

現在所有的「滯後」迄今爲止來自延遲對cpu的內容。 GPU可以很好地處理這一切。

所以我想通過給事情添加輝光效果來讓事情變得更好。我在考慮第10步,而不是使用常規紋理着色器,我可以使用除紋理之外的其他紋理。

不幸的是我對如何做到這一點感到困惑。這是一些原因

  • 模糊的東西。大多數人認爲高斯模糊可以實時完成,而其他人則認爲你不應該。此外,人們提到另一種稱爲「焦點」模糊的模糊,我不知道它是什麼。
  • 我可以找到的大多數示例都使用XNA。我需要有一個像OpenGL ES 2.0那樣的着色語言編寫的語言。
  • 有人稱之爲發光,別人稱之爲發花
  • 不同的混合模式?可以用來將輝光添加到原始紋理。
  • 如何結合垂直和水平模糊?也許在一個平局?

反正我理解用於渲染輝光方法因此

  1. 從它
  2. 模糊切出暗數據(使用高斯?)
  3. 混合在光數據的光數據(屏幕混合?)

到目前爲止,我已經到了一個着色器繪製紋理的地步。我的下一步是什麼樣的?

//Vertex 
percision highp float; 

attrivute vec2 positionCoords; 
attribute vec2 textureCoords; 
uniform mat4 matrix; 
uniform float alpha; 
varying vec2 v_texcoord; 
varying float o_alpha; 

void main() 
{ 
    gl_Position = matrix * vec4(positionCoords, 0.0, 1.0); 
    v_texcoord = textureCoords.xy; 
    o_alpha = alpha; 
} 



//Fragment 
varying vec2 v_texcoord; 
uniform sampler2D s_texture; 
varying float o_alpha; 

void main() 
{ 
    vec4 color = texture2D(s_texture, v_texcoord); 
    gl_FragColor = vec4(color.r, color.g, color.b, color.a - o_alpha); 
} 

也是這是一個可行的事情做實時?

編輯:我可能想要做一個5像素或更低模糊

回答

0

爲了解決您最初的混亂項目:

  • 基於其原有的任何一種模糊濾鏡將有效地傳播每個像素將一個blob位置,併爲所有像素累加該結果。過濾器之間的區別在於blob的形狀。
    • 對於高斯模糊,這個斑點應該是一個平滑的漸變,逐漸變爲零邊緣。你可能想要一個高斯模糊。
    • 「焦點」模糊會模仿失焦相機:而不是逐漸衰減到零,它的斑點會將每個像素散佈在硬邊圓圈上,從而產生細微差別的效果。
  • 對於直觀的單程效果,計算成本與模糊寬度成正比。這意味着窄的(例如5px或更小)模糊可能作爲實時單程效果是可行的。 (可以通過使用多遍和多分辨率金字塔來實時實現寬高斯模糊,但我建議先嚐試一些更簡單的方法......)
  • 您可以合理地將這種效果稱爲「輝光「或」開花「。然而,對我而言,「發光」意味着狹窄的模糊導致霓虹般的效果,而「開花」意味着使用寬泛的模糊來模擬高動態範圍視覺環境中明亮物體的視覺效果。
  • 混合模式決定了您如何繪製與目標緩衝區中的現有顏色相結合。在OpenGL中,激活與glEnable(GL_BLEND)的混合並將模式設置爲glBlendFunc()
  • 對於一個狹窄的模糊,你應該能夠做一個水平和垂直過濾。

要做到快一通全屏採樣,你需要確定你的源紋理像素增量。這是最快的靜態確定這一點,讓您的片段着色器不需要計算它在運行時:

float dx = 1.0/x_resolution_drawn_over; 
float dy = 1.0/y_resolution_drawn_over; 

你可以做一個3像素(1,2,1)的高斯模糊的一個通過您的紋理採樣模式設置爲GL_LINEAR,和從源紋理t服用4個樣品通過如下:

float dx2 = 0.5*dx; float dy2 = 0.5*dy; // filter steps 

[...] 

vec2 a1 = vec2(x+dx2, y+dy2); 
vec2 a2 = vec2(x+dx2, y-dy2); 
vec2 b1 = vec2(x-dx2, y+dy2); 
vec2 b2 = vec2(x-dx2, y-dy2); 
result = 0.25*(texture(t,a1) + texture(t,a2) + texture(t,b1) + texture(t,b2)); 

你可以做5個像素(1,4,6,4,1)的一個高斯模糊通過將紋理採樣模式設置爲GL_LINEAR,並從源紋理t中取9個樣本,如下所示:

float dx12 = 1.2*dx; float dy12 = 1.2*dy; // filter steps 
float k0 = 0.375; float k1 = 0.3125; // filter constants 

vec4 filter(vec4 a, vec4 b, vec4 c) { 
    return k1*a + k0*b + k1*c; 
} 

[...] 

vec2 a1 = vec2(x+dx12, y+dy12); 
vec2 a2 = vec2(x,  y+dy12); 
vec2 a3 = vec2(x-dx12, y+dy12); 
vec4 a = filter(sample(t,a1), sample(t,a2), sample(t,a3)); 

vec2 b1 = vec2(x+dx12, y ); 
vec2 b2 = vec2(x,  y ); 
vec2 b3 = vec2(x-dx12, y ); 
vec4 b = filter(sample(t,b1), sample(t,b2), sample(t,b3)); 

vec2 c1 = vec2(x+dx12, y-dy12); 
vec2 c2 = vec2(x,  y-dy12); 
vec2 c3 = vec2(x-dx12, y-dy12); 
vec4 c = filter(sample(t,c1), sample(t,c2), sample(t,c3)); 

result = filter(a,b,c); 

我不能告訴你,如果這些過濾器將在您的平臺上實時可行;全分辨率下9個樣本/像素可能會變慢。

任何更寬的高斯將使單獨的水平和垂直通道有利;實質上更寬的高斯將需要用於實時性能的多分辨率技術。(需要注意的是,不同的是高斯,過濾器,如「專注」模糊是不可分離的,這意味着它們不能被分離成水平和垂直傳遞...)

0

一切,@comingstorm一直說的是真的,但有一個更簡單的方法。不要寫模糊或發光自己。既然你是在iOS上,爲什麼不使用CoreImage,它有許多有趣的過濾器可供選擇,哪些已經實時工作?例如,他們有一個Bloom過濾器,它可能會產生你想要的結果。另外感興趣的可能是Gloom過濾器。

串聯起來CoreImage過濾器是比寫的着色器容易得多。您可以通過[+CIImage imageWithTexture:size:flipped:colorSpace:]從OpenGL紋理創建CIImage