1. 程式人生 > 其它 >opengl 旋轉矩陣和紋理座標相乘_OpenGL-Rotating Points

opengl 旋轉矩陣和紋理座標相乘_OpenGL-Rotating Points

技術標籤:opengl 旋轉矩陣和紋理座標相乘

全球圖形學領域教育的領先者、自研引擎的倡導者、底層技術研究領域的技術公開者,東漢書院在致力於使得更多人群具備核心級競爭力的道路上,將帶給小夥伴們更多的公開技術教學和視訊,感謝一路以來有你的支援。我們正在用實際行動來幫助小夥伴們構建一套成體系的圖形學知識架構,你在我們這裡獲得的不止於那些毫無意義的程式碼,我們這裡更多的是程式碼背後的故事,以及精準、透徹的理解。我們不會扔給人們一本書或者給個思路讓人們去自學,我們是親自來設計出好的課程,讓人們明白到底背後還有哪些細節。

這裡插播一個引擎大賽的訊息,感興趣的同學可以看一眼,這也是東漢書院的立項使命:

東漢書院:自研引擎大賽​zhuanlan.zhihu.com 82bb566dbca9ce4ff65405f0bf2a1294.png

Because points in OpenGL are rendered as axis-aligned squares, rotating the point sprite must be done by modifying the texture coordinates used to read the sprite’s texture or to analytically calculate its shape. To do this, you can simply create a 2D rotation matrix in the fragment shader and multiply it by gl_PointCoord to rotate it around the z axis. The angle of rotation could be passed from the vertex or geometry shader to the fragment shader as an interpolated variable. The value of the variable can, in turn, be calculated in the vertex or geometry shader or be supplied through a vertex attribute. Listing 9.34 shows a slightly more complex point sprite fragment shader that allows the point to be rotated around its center.

由於OpenGL在繪製點精靈的時候會按照軸對齊的方式去繪製四邊形,所以如果你想旋轉一個點精靈的話就必須要修改點精靈的紋理座標或者去親手計算它的形狀。為了做到這一點,你可以簡單粗暴的建立一個2D的 旋轉矩陣,然後在fragment shader中使用它與gl_PointCoord相乘來讓點精靈繞z軸旋轉。輸入的旋轉角度可以從vertex shader或者是geometry shader中傳入,然後插值得到。這樣一來,這個變數的值就可以在 vertex shader計算得到或者geometry shader計算得到或者通過頂點的屬性提供。清單9.34展示了一個相對更復雜一點的點精靈的fragment shader,它使得點精靈可以繞著它的中心點旋轉。

#version 450 core
uniform sampler2D sprite_texture;
in float angle;
out vec4 color;
void main(void)
{
	const float sin_theta = sin(angle);
	const float cos_theta = cos(angle);
	const mat2 rotation_matrix = mat2(cos_theta, sin_theta, -sin_theta, cos_theta);
	const vec2 pt = gl_PointCoord - vec2(0.5);
	color = texture(sprite_texture, rotation_matrix * pt + vec2(0.5));
}

Listing 9.34: Naïve rotated point sprite fragment shader

This example allows you to generate rotated point sprites. However, the value of angle will not change from one fragment to another within the point sprite. That means sin_theta and cos_theta will be constant and the resulting rotation matrix constructed from them will be the same for every fragment in the point. It is therefore much more efficient to calculate sin_theta and cos_theta in the vertex shader and pass them as a pair of variables into the fragment shader rather than calculating them at every fragment. Here’s an updated vertex and fragment shader that allows you to draw rotated point sprites. First, the vertex shader is shown in Listing 9.35.

這個例子允許你去生成旋轉的點精靈。然而,這個角度的值不會因為點精靈上所在畫素位置的變化而變化。也就是說sin ——theta和cos_theta將是常量並且產生的結果旋轉矩陣對於每個點上的所有畫素來說都是一樣的。 因此,相比在fragment shader中進行計算,在vertex shader中計算出sin_theta和cos_theta的值然後把它們傳入fragment shader會更加的高效。下面展示了新版本的vertex shader和fragment shader的程式碼。首先, 清單9.35展示了vertex shader的程式碼。

#version 450 core
uniform matrix mvp;
in vec4 position;
in float angle;flat out float sin_theta;
flat out float cos_theta;
void main(void)
{
	sin_theta = sin(angle);
	cos_theta = cos(angle);
	gl_Position = mvp * position;
}

Listing 9.35: Rotated point sprite vertex shader

Next, the fragment shader is shown in Listing 9.36.

緊接著,清單9.36展示了fragment shader的程式碼

#version 450 core
uniform sampler2D sprite_texture;
flat in float sin_theta;
flat in float cos_theta;
out vec4 color;
void main(void)
{
	mat2 rotation_matrix = mat2(cos_theta, sin_theta, -sin_theta, cos_theta);
	vec2 pt = gl_PointCoord - vec2(0.5);
	color = texture(sprite_texture, rotation_matrix * pt + vec2(0.5));
}

Listing 9.36: Rotated point sprite fragment shader

As you can see, the potentially expensive sin and cos functions have been moved out of the fragment shader and into the vertex shader. If the point size is large, this pair of shaders performs much better than the earlier, brute-force approach of calculating the rotation matrix in the fragment shader.

如你所見到的一樣,sin和cos函式已經從fragment shader中移到了vertex shader中去了。如果點的大小很大的話,這組shader的效能相對於之前的那個簡單粗暴的在fragment shader中計算旋轉矩陣會更好一點。

Even though you are rotating the coordinates you derived from gl_PointCoord, the point itself is still square. If your texture or analytic shape spills outside the unit diameter circle inside the point, you will need to make your point sprite larger and scale your texture coordinate down accordingly to get the shape to fit within the point under all angles of rotation. Of course, if your texture is essentially round, you don’t need to worry about this at all.

即便你旋轉從gl_PointCoord中推匯出來的紋理座標,點精靈本身依然是一個矩形。如果你的紋理或者形狀玩到了點精靈的外面,你需要把點精靈弄大一點並且給它一個縮放,讓它的形狀適應當前點精靈的旋轉角度。當然 如果你的紋理基本上是個圓的的話,你不需要擔心這個事情。

我們核心關注和討論的領域是引擎的底層技術以及商業化方面的資訊,可能並不適合初級入門的同學。官方相關資訊主要包括了對市面上的引擎的各種視角的分析以及巨集觀方面的技術討論,相關領域感興趣的同學可以關注東漢書院以及圖形之心公眾號。

隻言片語,無法描繪出整套圖形學領域的方方面面,只有成體系的知識結構,才能夠充分理解和掌握一門科學,這是藝術。我們已經為你準備好各式各樣的內容了,東漢書院,等你來玩。