簡體   English   中英

具有不同旋轉度的OpenGL ES 2.0點精靈-在着色器中計算矩陣?

[英]OpenGL ES 2.0 point sprites with distinct rotations - calculate matrix in shader?

我試圖找到一種解決方案,使我可以使點精靈圍繞z軸旋轉,並具有不同的屬性(即統一不會這樣做)。

在我的應用程序中,每幀繪制了成百上千的點精靈,然后將它們存儲在VBO中(最終可能> 100萬)。 因此,我正在尋找內存使用和性能之間的最佳折衷。

頂點和片段着色器當前看起來像這樣:

// VERTEX SHADER
attribute vec4 a_position;
attribute vec4 a_color;
attribute float a_size;
uniform mat4 u_mvpMatrix;
varying vec4 v_color;

void main()
{
    v_color = a_color;
    gl_Position = u_mvpMatrix * a_position;
    gl_PointSize = a_size;
}


// FRAGMENT SHADER
precision mediump float;
uniform sampler2D s_texture;
varying vec4 v_color;

void main()
{
    vec4 textureColor = texture2D(s_texture, gl_PointCoord);
    gl_FragColor = v_color * textureColor;
}

我目前可以想象以下可能性:

  • mat4 rotMatrix屬性添加到我的點精靈數據中。 將其傳遞到片段着色器並旋轉每個片段:

     vec2 texCoord = (rotMatrix * vec4(gl_PointCoord, 0, 1)).xy gl_FragColor = v_color * texture2D(s_texture, texCoord); 
    • 好處:
      • 使着色器保持簡單。
      • 用於在着色器外部計算矩陣的簡單代碼(例如,使用GLKit )。
    • 缺點:
      • 大量增加了我的點精靈數據的大小(對於4x4矩陣,從16字節/點增加到80字節/點;對於3x3矩陣,則從52字節/點增加了……我相信可以使用3x3旋轉矩陣嗎?)。 這可能會導致我的應用程序更快崩潰3-5次!
      • 將更多計算推入CPU(每幀數百/數千矩陣計算)。


  • float angle屬性添加到我的點精靈數據中,然后在頂點着色器中計算旋轉矩陣。 如上所述,將旋轉矩陣傳遞給片段着色器。

    • 好處:
      • 將點精靈數據的大小保持較小(從16到20字節/點)。
      • 將繁重的矩陣運算推入GPU。
    • 缺點:
      • 需要編寫自定義GLSL函數來創建旋轉矩陣。 這不是一個大問題,但是我的矩陣數學很生疏,所以這可能容易出錯,尤其是當我試圖找出3x3矩陣解決方案時...
      • 鑒於這必須在成百上千的頂點上發生,這是否會嚴重影響性能(盡管由GPU處理)?


  • 實際上,我可以為angle屬性處理1個字節(255個不同的角度就足夠了)。 有什么方法可以使用某種查找方式,而不用不必要地重新計算相同的旋轉矩陣? 將常量存儲在頂點着色器中是我的第一個想法,但是我不想開始在我的着色器中放置分支語句。

有什么好的方法的想法嗎?

最后我得到的解決方案是問題的第二個解決方案:在頂點着色器中計算旋轉矩陣。 這具有以下優點:

  • 將點精靈數據的大小保持較小。
  • 旋轉計算由GPU執行。

我猜想的缺點似乎並不適用。 即使在第一代iPad上運行,我也沒有注意到性能下降。 GLSL中的矩陣計算有些麻煩,但效果很好。 為了使其他任何人都可以嘗試這樣做,下面是頂點着色器的相關部分:

//...
attribute float a_angle;
varying mat4 v_rotationMatrix;

void main()
{
    //...

    float cos = cos(a_angle);
    float sin = sin(a_angle);
    mat4 transInMat = mat4(1.0, 0.0, 0.0, 0.0,
                           0.0, 1.0, 0.0, 0.0,
                           0.0, 0.0, 1.0, 0.0,
                           0.5, 0.5, 0.0, 1.0);
    mat4 rotMat = mat4(cos, -sin, 0.0, 0.0,
                       sin, cos, 0.0, 0.0,
                       0.0, 0.0, 1.0, 0.0,
                       0.0, 0.0, 0.0, 1.0);
    mat4 resultMat = transInMat * rotMat;
    resultMat[3][0] = resultMat[3][0] + resultMat[0][0] * -0.5 + resultMat[1][0] * -0.5;
    resultMat[3][1] = resultMat[3][1] + resultMat[0][1] * -0.5 + resultMat[1][1] * -0.5;
    resultMat[3][2] = resultMat[3][2] + resultMat[0][2] * -0.5 + resultMat[1][2] * -0.5;
    v_rotationMatrix = resultMat;

    //...
}

考慮到沒有明顯的性能影響,此解決方案是理想的,因為無需創建紋理貼圖/查找並消耗額外的內存,並且可以使其余代碼保持簡潔。

我不能說為每個頂點計算矩陣都沒有任何缺點(例如,減少了電池壽命),並且在不同情況下性能可能是一個問題,但這對我的需求很好。

您是否考慮過使用不同的預先計算和旋轉的紋理(紋理圖集)? 如果只有幾個角度足以達到您想要實現的效果,那么這將是一個非常快速的解決方案。

另一方面,片段着色器(間接紋理查找)中紋理坐標的計算會降低性能。 這對您的情況可能並不重要,但請記住。

這是您的預乘旋轉矩陣:

v_rotationMatrix = mat3(cos, sin, 0.0,
                        -sin, cos, 0.0,
                        (sin-cos+1.0)*0.5, (-sin-cos+1.0)*0.5, 1.0);

FWIW,這是我得到的與Stuart的代碼匹配的3x3預先計算的矩陣:

v_rotationMatrix = mat3(cos,-sin,0.0,sin,cos,0.0,(1.0-cos-sin)* 0.5,(1.0 + sin-cos)* 0.5,1.0);

請注意,glsl矩陣采用主列格式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM