opengl學習心得

2021-08-20 22:18:02 字數 5027 閱讀 6363

vao 即 vertex array object ,是乙個包含乙個或多個vbo的物件,被設計用來儲存乙個完整被渲染物件所需的資訊。

3d座標轉為2d座標的處理過程是由opengl的圖形渲染管線(graphics pipeline,大多譯為管線,實際上指的是一堆原始圖形資料途經乙個輸送管道,期間經過各種變化處理最終出現在螢幕的過程)管理的。第一部分把你的3d座標轉換為2d座標,第二部分是把2d座標轉變為實際的有顏色的畫素。

圖形渲染管線可以被劃分為幾個階段,每個階段將會把前乙個階段的輸出作為輸入。

為了讓opengl知道我們的座標和顏色值構成的到底是什麼,opengl需要你去指定這些資料所表示的渲染型別。我們是希望把這些資料渲染成一系列的點?一系列的三角形?還是僅僅是乙個長長的線?做出的這些提示叫做圖元(primitive),任何乙個繪製指令的呼叫都將把圖元傳遞給opengl。這是其中的幾個:gl_points、gl_********s、gl_line_strip。

每個階段的輸出是下一階段的輸入

圖形渲染管線的第乙個部分是頂點著色器(vertex shader),它把乙個單獨的頂點作為輸入。頂點著色器主要的目的是把3d座標轉為另一種3d座標(後面會解釋),同時頂點著色器允許我們對頂點屬性進行一些基本處理。

圖元裝配(primitive assembly)階段將頂點著色器輸出的所有頂點作為輸入(如果是gl_points,那麼就是乙個頂點),並所有的點裝配成指定圖元的形狀;本節例子中是乙個三角形。

圖元裝配階段的輸出會傳遞給幾何著色器(geometry shader)。幾何著色器把圖元形式的一系列頂點的集合作為輸入,它可以通過產生新頂點構造出新的(或是其它的)圖元來生成其他形狀。例子中,它生成了另乙個三角形。

幾何著色器的輸出會被傳入光柵化階段(rasterization stage),這裡它會把圖元對映為最終螢幕上相應的畫素,生成供片段著色器(fragment shader)使用的片段(fragment)。在片段著色器執行之前會執行裁切(clipping)。裁切會丟棄超出你的檢視以外的所有畫素,用來提公升執行效率。其實就是計算機圖形學的裁剪,決定哪一部分在視窗內顯示,哪一些在視窗外。

opengl中指定的所有座標都是3d座標(x、y和z)。opengl不是簡單地把所有的3d座標變換為螢幕上的2d畫素;opengl僅當3d座標在3個軸(x、y和z)上都為-1.0到1.0的範圍內時才處理它。

標準化裝置座標(normalized device coordinates, ndc)

一旦你的頂點座標已經在頂點著色器中處理過,它們就應該是標準化裝置座標了,標準化裝置座標是乙個x、y和z值在-1.0到1.0的一小段空間。任何落在範圍外的座標都會被丟棄/裁剪,不會顯示在你的螢幕上。下面你會看到我們定義的在標準化裝置座標中的三角形(忽略z軸):

與通常的螢幕座標不同,y軸正方向為向上,(0, 0)座標是這個影象的中心,而不是左上角。最終你希望所有(變換過的)座標都在這個座標空間中,否則它們就不可見了。

你的標準化裝置座標接著會變換為螢幕空間座標(screen-space coordinates),這是使用你通過glviewport函式提供的資料,進行視口變換(viewport transform)完成的。所得的螢幕空間座標又會被變換為片段輸入到片段著色器中。

通常深度可以理解為z座標,它代表乙個畫素在空間中和你的距離,如果離你遠就可能被別的畫素遮擋,你就看不到它了,它會被丟棄,以節省資源。

頂點緩衝物件(vbo)是我們在opengl教程中第乙個出現的opengl物件。就像opengl中的其它物件一樣,這個緩衝有乙個獨一無二的id,所以我們可以使用glgenbuffers函式和乙個緩衝id生成乙個vbo物件:

gluint vbo;

glgenbuffers(1, &vbo);

opengl有很多緩衝物件型別,頂點緩衝物件的緩衝型別是gl_array_buffer。opengl允許我們同時繫結多個緩衝,只要它們是不同的緩衝型別。我們可以使用glbindbuffer函式把新建立的緩衝繫結到gl_array_buffer目標上:

glbindbuffer(gl_array_buffer, vbo);
從這一刻起,我們使用的任何(在gl_array_buffer目標上的)緩衝呼叫都會用來配置當前繫結的緩衝(vbo)。然後我們可以呼叫glbufferdata函式,它會把之前定義的頂點資料複製到緩衝的記憶體中:

float vertices = ;

glbufferdata(gl_array_buffer, sizeof(vertices), vertices, gl_static_draw);

glbufferdata是乙個專門用來把使用者定義的資料複製到當前繫結緩衝的函式。它的第乙個引數是目標緩衝的型別:頂點緩衝物件當前繫結到gl_array_buffer目標上。第二個引數指定傳輸資料的大小(以位元組為單位);用乙個簡單的sizeof計算出頂點資料大小就行。第三個引數是我們希望傳送的實際資料。

第四個引數指定了我們希望顯示卡如何管理給定的資料。它有三種形式:

gl_static_draw :資料不會或幾乎不會改變。

gl_dynamic_draw:資料會被改變很多。

gl_stream_draw :資料每次繪製時都會改變。

接下來編寫著色器shader

以下是最簡單的用glsl編寫的頂點著色器vertexshader**:

#version 330 core

layout (location = 0) in

vec3 apos;

void main()

因為之前說過每個階段的輸入是上一階段的輸出,但是對於頂點著色器來說,比較特殊,因為它沒有上一階段的輸出,它是直接接受頂點資料,所以它的輸入必須做一些規範,以避免降低效率,通過用layout修飾符來修飾in和out

locaiton=0暫時不清楚是來幹什麼的

編譯著色器

接下來編譯之前寫的頂點著色器

unsigned

int vertexshader;

vertexshader = glcreateshader(gl_vertex_shader);

gl_vertex_shader作為引數告訴建立的著色器型別是頂點著色器

緊接著把著色器原始碼source附加在著色器物件上,然後進行編譯:

glshadersource(vertexshader, 1, &vertexshadersource, null);

glcompileshader(vertexshader);

檢測是否編譯成功:

呼叫glcompileshader後編譯是否成功了,如果沒成功的話,你還會希望知道錯誤是什麼,這樣你才能修復它們。檢測編譯時錯誤可以通過以下**來實現:

int  success;

char infolog[512];

glgetshaderiv(vertexshader, gl_compile_status, &success);

首先我們定義乙個整型變數來表示是否成功編譯,還定義了乙個儲存錯誤訊息(如果有的話)的容器。然後我們用glgetshaderiv檢查是否編譯成功。如果編譯失敗,我們會用glgetshaderinfolog獲取錯誤訊息,然後列印它。

if(!success)

顏色rgba 分別表示紅色、綠色、藍色和alpha(透明度)分量,值範圍在0.0到1.0之間。透明度設為1.0(代表不透明)用於後面的裁剪部分,之後會做說明

寫乙個簡單的著色器**

#version 330 core

out vec4 fragcolor;

void main()

片段著色器只需要乙個輸出變數out,這個變數是乙個4分量向量,它表示的是最終的輸出顏色,我們應該自己將其計算出來。我們可以用out關鍵字宣告輸出變數,這裡我們命名為fragcolor。下面,我們將乙個alpha值為1.0(1.0代表完全不透明)的橘黃色的vec4賦值給顏色輸出。

接著就是著色器編譯了,與定點著色器相似,著色器引數型別變為gl_fragment_shader

unsigned

int fragmentshader;

fragmentshader = glcreateshader(gl_fragment_shader);

glshadersource(fragmentshader, 1, &fragmentshadersource, null);

glcompileshader(fragmentshader);

著色器程式物件(shader program object)是多個著色器合併之後並最終鏈結完成的版本。如果要使用剛才編譯的著色器我們必須把它們鏈結(link)為乙個著色器程式物件,然後在渲染物件的時候啟用這個著色器程式。已啟用著色器程式的著色器將在我們傳送渲染呼叫的時候被使用。

建立著色器程式

gluint shaderprogram;

shaderprogram =glcreateprogram();

glattachshader(shaderprogram, vertexshader);

glattachshader(shaderprogram, fragmentshader);

gllinkprogram(shaderprogram);

檢測是否失敗

glgetprogramiv(shaderprogram, gl_link_status, &success);

if(!success)

頂點著色器的輸出傳入片段著色器的輸入時,變數名稱和型別必須一致

學習心得 python學習心得

自從來了深圳工作以後,尤其是屢屢面試碰壁以後。發現其實自己的知識面很窄,做筆試題的時候絞盡腦汁還是漏洞百出,並不是不會做,而是出現一大堆不該有的失誤。每次被問道,對資料庫了解嗎?說一大堆看起來很高階的東西 好啊,那我們寫幾個sql語句吧。馬上完蛋了,沒了手冊關鍵字都記不起。了解哪幾種指令碼語言,sh...

學習心得 我的學習心得

我是乙個已經步入中年的70後,離開校園已經20年了,因為當年的政策因素而未能圓我的大學夢,在20年的工作過程中總是因為缺少一張大學文憑而失去了很多機會,曾經也考慮過自考,但是乙個人去面對的時候總感覺心有餘而力不足。2018年3月份偶然讓我認識了尚德,原來自考還可以這樣學習。一直懷疑自己年紀大了記憶力...

Spring學習心得

不看不知道,一看便學到,會不會與您產生共鳴呢?喜歡再捧場拍磚 spring使用從一年前開始,邊學習邊開發。這裡講講我的學習心得。第一條 記住ioc就是spring的一切。而掌握ioc的唯一方法就是使用和思考。spring是ioc為核心的,所以第一步就是要深刻理解ioc,最好是能盡快把ioc作為教條式...