2012-01-30 154 views
4

我跟隨this tutorial來學習更多關於OpenGL和特別是點精靈的東西。但我被困在頁面末尾的一個練習中:OpenGL點精靈在片段着色器中的旋轉

嘗試通過更改片段着色器來旋轉45度角點。

本章沒有提及這類事情,也沒有提到過這些。而且我沒有找到任何有關如何去做的文檔。這是我的頂點和片段着色器:

的Vertex Shader

#version 140 

attribute vec2 coord2d; 

varying vec4 f_color; 

uniform float offset_x; 
uniform float scale_x; 
uniform float point_size; 

void main(void) { 
    gl_Position = vec4((coord2d.x + offset_x) * scale_x, coord2d.y, 0.0, 1.0); 
    f_color = vec4(coord2d.xy/2.0 + 0.5, 1.0, 1.0); 
    gl_PointSize = point_size; 
} 

片段着色器

#version 140 

varying vec4 f_color; 

uniform sampler2D texture; 

void main(void) { 
    gl_FragColor = texture2D(texture, gl_PointCoord) * f_color; 
} 

我想到在FS採用2×2矩陣旋轉gl_PointCoord,但我不知道如何填充矩陣來完成它。我是否應該將其作爲制服直接傳遞給FS?

回答

8

傳統方法是將矩陣傳遞給着色器,無論是頂點還是片段。如果你不知道如何填寫旋轉矩陣,Google和Wikipedia可以提供幫助。

最主要的是,你會遇到的是一個簡單的事實,即2D旋轉是不夠的。 gl_PointCoord從[0,1]開始。純旋轉矩陣圍繞原點旋轉,原點是點座標空間中的左下角。所以你需要的不僅僅是一個純粹的旋轉矩陣。

您需要一個3x3矩陣,它具有部分旋轉和部分平移。這個矩陣應該如下(使用GLM的數學東西)來生成:

glm::mat4 currMat(1.0f); 
currMat = glm::translate(currMat, glm::vec3(0.5f, 0.5f, 0.0f)); 
currMat = glm::rotate(currMat, angle, glm::vec3(0.0f, 0.0f, 1.0f)); 
currMat = glm::translate(currMat, glm::vec3(-0.5f, -0.5f, 0.0f)); 

然後,您可以通過currMat到着色器作爲一個4x4矩陣。你的shader做到這一點:

vec2 texCoord = (rotMatrix * vec4(gl_PointCoord, 0, 1)).xy 
gl_FragColor = texture2D(texture, texCoord) * f_color; 

我會離開它作爲一個練習,你就如何翻譯從第四欄移動到第三,以及如何將它傳遞一個3x3矩陣。當然,在這種情況下,你會爲​​矩陣乘法做vec3(gl_PointCoord, 1)

+0

謝謝你的例子,它的工作。 – 2012-01-30 16:35:35

1

你是對的 - 一個2x2的旋轉矩陣將做你想要的。

此頁面:http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche31.html顯示如何計算元素。請注意,您將旋轉紋理座標,而不是頂點位置 - 結果可能不會是您期望的結果 - 例如,它將圍繞0,0紋理座標旋轉。

您可能還需要將point_size乘以2並將gl_PointCoord縮小2以確保整個紋理在旋轉時適合點精靈。但是,這樣做是第二次改變。請注意,紋理座標的直線比例將其移向紋理座標原點,而不是精靈的中間。

如果您使用更高維矩陣(3x3),那麼您將能夠將偏移,比例和旋轉合併爲一個操作。

+0

謝謝,但正如你所說,結果不是我所期望的,因爲我在錯誤的位置上旋轉。 – 2012-01-30 16:35:02

2

我也陷入了同樣的問題,但我找到了一個教程,解釋如何在同一片段着色器中執行2d紋理旋轉,僅傳遞旋轉值(vRotation)。

#version 130 

uniform sampler2D tex; 
varying float vRotation; 
void main(void) 
{ 

    float mid = 0.5; 
    vec2 rotated = vec2(cos(vRotation) * (gl_PointCoord.x - mid) + sin(vRotation) * (gl_PointCoord.y - mid) + mid, 
         cos(vRotation) * (gl_PointCoord.y - mid) - sin(vRotation) * (gl_PointCoord.x - mid) + mid); 

    vec4 rotatedTexture=texture2D(tex, rotated); 
    gl_FragColor = gl_Color * rotatedTexture; 
} 

也許這方法是緩慢的,但僅是爲了證明/顯示您有一個替代以執行片段着色器內的紋理2D旋轉而不是傳遞矩陣的。

注意:vRotation應該在Radians中。

乾杯,