(Python OpenGL)【3】着色器 PyOpenGL


(Python OpenGL)現在開始我們使用着色器來進行渲染。着色器是目前做3D圖形最流行的方式。

OpenGL的渲染管線流程:

數據傳輸到OpenGL—>頂點處理器—>細分着色—>幾何處理器—>圖元裝配—>裁剪器—>光柵器(片段處理器)

詳細信息可以參考《OpenGL編程指南》 原書第8版  王銳譯   中的P8 -P10

 

一些Shader的注意:

Shader着色器的使用跟C/C++程序的創建過程類似。

1、寫一個shader着色器文本並使其在你的程序中有效可用

2、Shader着色器文本全為字符串類型          例如     S = “ coding部分” 代碼部分為字符串

3、將字符串編譯為Shader對象

4、使用GLSL編譯器(編譯器的語法見《OpenGL編程指南》 原書第8版  王銳譯)

 

對於每一個着色器程序需要進行下面的步驟設置:

對於着色器對象:

1、創建Shader對象

2、編譯

3、驗證編譯成功?

 

然后將上述的着色器對象鏈接為一個着色器程序:

1、創建程序

2、將Shader對象關聯到着色器程序

3、鏈接程序

4、判斷鏈接是否成功

5、使用着色器處理數據

 Shader程序:

 1 __author__ = "WSX"
 2 
 3 import numpy as np
 4 from OpenGL.GLUT import *
 5 from OpenGL.GL import *
 6 import ctypes
 7 #頂點着色器部分
 8 VERTEX_SHADER = """   
 9 #version 330
10 
11 layout (location = 0) in vec3 Position;
12 
13 void main()
14 {
15     gl_Position = vec4(0.5 * Position.x, 0.5 * Position.y, Position.z, 1.0);
16     }
17 """
18 #片段着色器部分,字符串類型
19 FRAGMENT_SHADER = """ 
20 #version 330
21 out vec4 FragColor;
22 void main()
23 {
24     FragColor = vec4(1.0, 0.0, 0.0, 1.0);
25     }
26 """
27 def Create_Shader( ShaderProgram, Shader_Type , Source):  #創建並且添加着色器(相當於AddShader)Shader_Type為類型
28     ShaderObj = glCreateShader( Shader_Type )  #創建Shader對象
29     glShaderSource(ShaderObj , Source)
30     glCompileShader(ShaderObj)  #進行編譯
31     glAttachShader(ShaderProgram, ShaderObj)  #將着色器對象關聯到程序上
32 
33 
34 def Compile_Shader():  #編譯着色器
35     Shader_Program = glCreateProgram()  #創建空的着色器程序
36     Create_Shader(Shader_Program , GL_VERTEX_SHADER , VERTEX_SHADER)
37     Create_Shader(Shader_Program , GL_FRAGMENT_SHADER , FRAGMENT_SHADER)
38     glLinkProgram(Shader_Program)
39     glUseProgram(Shader_Program)
40 
41 def Draw():
42     glClear(GL_COLOR_BUFFER_BIT)
43     glEnableVertexAttribArray(0)
44     glBindBuffer(GL_ARRAY_BUFFER, VBO)
45     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) #這里的None不能寫為0
46     glDrawArrays(GL_TRIANGLES, 0, 3)
47     glDisableVertexAttribArray(0)  #解析數據 例如一個矩陣里含有 位置 、顏色、多種信息
48     glutSwapBuffers()
49 
50 
51 def CreateBuffer():  #創建頂點緩存器
52     global VBO   #設置為全局變量
53     vertex = np.array([[-1.0,-1.0,0.0],
54                        [1.0,-1.0,0.0],
55                        [0.0,1.0,0.0]],dtype="float32")   #創建頂點數組
56     VBO = glGenBuffers(1)  #創建緩存
57     glBindBuffer(GL_ARRAY_BUFFER , VBO)   #綁定
58     glBufferData(GL_ARRAY_BUFFER , vertex.nbytes , vertex , GL_STATIC_DRAW)   #輸入數據
59 
60 
61 def main():
62     glutInit([])
63     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)  # 顯示模式 雙緩存
64     glutInitWindowPosition(100, 100)  # 窗口位置
65     glutInitWindowSize(500, 500)  # 窗口大小
66     glutCreateWindow("sanjiao")  # 創建窗口
67     glutInitContextVersion(4,3)   #為了兼容
68     glutInitContextProfile(GLUT_CORE_PROFILE)   #為了兼容
69     glutDisplayFunc(Draw)  # 回調函數
70     glClearColor(0.0, 0.0, 0.0, 0.0)
71     CreateBuffer()
72     Compile_Shader()
73     glutMainLoop()
74 
75 main()

結果:

 

 

關於着色器代碼部分(字符串)的解釋:

#version 330

這告訴編譯器我們的目標是3.3版的GLSL。如果編譯器不支持它,它會發出錯誤。

 

layout (location = 0) in vec3 Position;

該語句出現在頂點着色器中。它聲明了一個頂點特定屬性,它是3個浮點數的向量,在着色器中將被稱為'位置'。“特定於頂點”表示對於GPU中每個對着色器的調用,將提供緩沖區中新頂點的值。

 layout (location = 0)創建緩沖區中屬性名稱和屬性之間的綁定。

 

您可以通過將多個着色器對象鏈接在一起來創建着色器。但是,每個着色器階段(VS,GS,FS)只能有一個主要函數,用作着色器的入口點。例如,您可以創建一個具有多個函數的光照庫,並將其與着色器鏈接,前提是這些函數中沒有任何一個函數名為“main”。

gl_Position = vec4(0.5 * Position.x, 0.5 * Position.y, Position.z, 1.0);

這里我們對輸入的頂點位置進行硬編碼轉換。我們將X和Y值減半,並保持Z不變。'gl_Position'是一個特殊的內置變量,它應該包含齊次(包含X,Y,Z和W分量)頂點位置。光柵化器將查找該變量並將其用作屏幕空間中的位置(在進行了幾次轉換之后)。將X和Y值減半意味着我們將看到一個三角形,它是前一教程中三角形大小的四分之一。請注意,我們將W設置為1.0。這對於正確顯示三角形非常重要。從3D到2D的投影實際上分兩個階段完成。首先,您需要將所有頂點乘以投影矩陣(我們將在一些教程中開發),然后GPU在位置屬性到達光柵化器之前自動執行所謂的“透視分割”。這意味着它將W組件的所有組件分割成W組件。在本教程中,我們尚未在頂點着色器中進行任何投影,但透視分割階段是我們無法禁用的。無論我們從頂點着色器輸出的gl_Position值是用HW分量還是HW分量。我們需要記住,否則我們不會得到我們期望的結果。為了規避視角分割的影響,我們將W設置為1.0。由1除。

如果一切工作正常,則具有值(-0.5,-0.5),(0.5,-0.5)和(0.0,0.5)的三個頂點到達光柵器。裁剪器不需要做任何事情,因為所有的頂點都在標准化的框內。這些值被映射到屏幕空間坐標,並且光柵化器開始運行三角形內的所有點。對於每個點,執行片段着色器。以下着色器代碼是從片段着色器中獲取的。

out vec4 FragColor;

通常片段着色器的工作是確定片段(像素)的顏色。此外,片段着色器可以完全丟棄像素或更改其Z值(這會影響后續Z測試的結果)。通過聲明上述變量來輸出顏色。四個分量表示R,G,B和A(對於alpha)。您設置到該變量中的值將由光柵化器接收並寫入幀緩沖區。

FragColor = vec4(1.0, 0.0, 0.0, 1.0);

在之前的幾個教程中,沒有片段着色器,因此所有內容都以白色的默認顏色繪制。在這里,我們將FragColor設置為紅色。

更多關於着色器部分的解釋:http://ogldev.atspace.co.uk/www/tutorial04/tutorial04.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM