1. 程式人生 > >OpenGL學習筆記之繪製三角形

OpenGL學習筆記之繪製三角形

參考https://learnopengl.com/

1、建立視窗

glfw是一個針對OpenGL的視窗管理庫,這裡使用glfw庫建立視窗並處理輸入,glfw庫可以在它的官網上下載,提供了動態庫和靜態庫供選擇,也可以下載原始碼自己編譯。

以官方下載的靜態庫glfw3.lib為例,將下載的靜態庫複製到自己方便管理的路徑,這裡放在工程路徑下的lib資料夾內,並將該檔案路徑新增到工程屬性的依賴庫裡


將glfw3.h複製到工程目錄下的glfw資料夾內,並在.cpp檔案內包含該標頭檔案#include "glfw/glfw3.h"
建立視窗的步驟:
(1)初始化glfw
glfwInit();
(2)配置OpenGL屬性項
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint設定相應的屬性,GLFW_CONTEXT_VERSION_MAJOR和GLFW_CONTEXT_VERSION_MINOR設定需要使用的OpenGL版本,這裡選擇3.3版本,GLFW_OPENGL_CORE_PROFILE表示我們使用core-profile版本,不需要相容低版本特性
(3)建立視窗
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);//建立一個800x600大小的視窗
if (window == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//將window設定為當前視窗
(4)顯示視窗並處理訊息
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwWindowShouldClose判斷視窗是否要關閉,點選關閉按鈕的時候返回true,也就是退出迴圈
glfwSwapBuffers交換緩衝區,將要顯示的畫素顏色顯示到螢幕
glfwPollEvents處理訊息
(5)結束
最後呼叫glfwTerminate()即可。
最後程式碼合起來

#include "glfw/glfw3.h"
int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL", NULL, NULL);
	if (window == NULL)
	{
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	while (!glfwWindowShouldClose(window))
	{
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwTerminate();
	return 0;
}

2、畫三角形

視窗建立後就可以在視窗上畫出三角形了,這裡需要用到OpenGL的api介面,如果自己寫程式碼獲取OpenGL動態庫中的函式就太麻煩了,而且OpenGL有很多版本,不同版本的api也有區別。
使用glad庫可以解決這個問題,glad中包含了OpenGL不同版本的API,使用上面的glfwWindowHint指定版本後,就可以獲取到指定版本的所有函數了。
glad檔案獲取:開啟網址http://glad.dav1d.de/,如下圖


Language選擇C/C++,Specification選擇OpenGL,gl選擇你需要的版本,這裡是Version 3.3,Profile選擇Core,勾選Generate a loader,點選GENERATE按鈕就會生成glad.zip檔案。
將zip檔案解壓出來有src和include資料夾,分別有glad解壓出來有src和include資料夾,分別有glad.h、khrplatform.h和glad.c,將include下面的兩個資料夾glad和KHR複製到工程的包含目錄,例如VS安裝目錄下的VC\inlcude目錄,glad.c檔案新增到工程中。
之後只要在需要使用的地方加上標頭檔案包含#include "glad/glad.h",並在使用OpenGL函式之前載入所有函式指標gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)就可以了,glfwGetProcAddress位於glfw3.h中。
接下來就可以開始準備畫三角形了
(1)編寫頂點著色器(vertex shader)和片段著色器(fragment shader)
頂點著色器和片斷著色器都是使用著色器程式語言GLSL編寫
//頂點著色器程式碼:
#version 330 core	//版本
layout (location = 0) in vec3 vertexPos;	//頂點位置,由程式傳入
void main()//著色器程式執行main函式
{
   gl_Position = vec4(vertexPos, 1.0);//gl_Position為內部定義變數,表示頂點的位置
}
//片段著色程式碼:
#version 330 core
void main()
{
   gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);//gl_FragColor為內部定義變數,表示畫素的顏色
}
(2)建立和編譯著色器
為了方便,將著色器建立和編譯放到CreateShader函式內
GLuint CreateShader(GLuint type,const GLchar* source)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);
	GLint success;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);//獲取編譯結果
	if (!success)
	{
		char infoLog[512];
		glGetShaderInfoLog(shader, 512, NULL, infoLog);//獲取具體錯誤描述infoLog
		std::cout << infoLog << std::endl;
	}
	return shader;
}
假設頂點著色器程式字串為const GLchar* vsSource,片段著色器程式字串為const GLchar* fsSource,則建立頂點著色器和片斷著色器的程式碼分別為
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER,vsSource);
GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER,fsSource);
(3)建立著色器程式
這裡將建立和編譯著色器以及建立著色器程式一起放到CreateShaderProgram函式內
GLuint CreateShaderProgram(const GLchar* vsSource,const GLchar* fsSource)
{
	GLuint vertexShader = CreateShader(GL_VERTEX_SHADER,vsSource);
	GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER,fsSource);
	GLuint program = glCreateProgram();
	glAttachShader(program, vertexShader);
	glAttachShader(program, fragmentShader);
	glLinkProgram(program);
	GLint success;
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	if (!success) 
	{
		char infoLog[512];
		glGetProgramInfoLog(program, 512, NULL, infoLog);
		std::cout << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	return program;
}
(4)將三角形頂點資料傳入著色器
GLfloat vertices[] = 
{
	-0.5f,  0.5f, 0.0f,  // 1
	-0.5f, -0.5f, 0.0f,  // 2
	0.5f, -0.5f, 0.0f,  // 3
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);//建立頂點陣列物件
glGenBuffers(1, &VBO);//建立頂點緩衝
glBindVertexArray(VAO);//設定當前頂點陣列物件為VAO
{
	glBindBuffer(GL_ARRAY_BUFFER, VBO);//繫結VBO到GL_ARRAY_BUFFER
	{
		//將定點資料賦值給GL_ARRAY_BUFFER,也就是VBO
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
		//將緩衝中的頂點資料和vertexPos關聯起來,這裡是通過第一個引數0和著色器中的location=0關聯的
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
		glEnableVertexAttribArray(0);
	}
	glBindBuffer(GL_ARRAY_BUFFER, 0);//取消VBO繫結
}
glBindVertexArray(0);//取消VAO繫結
為了看起來清晰,將部分程式碼用{}括起來,後面只要使用VAO就可以獲取到頂點資料,OpenGL的座標範圍為-1到1
glVertexAttribPointer引數說明:
第一個引數表示變數的位置,也就是著色器中的location=n中的n;
第二個引數表示一個頂點的資料個數,這裡是3個;
第三個引數為資料型別,這裡為GL_FLOAT;
第四個引數表示資料是否要做標準化處理,如果為true,資料將被對映到-1到1之間,false則不做處理;
第五個引數為頂點資料間隔,就是相鄰兩個資料的起始地址之間的間隔,這裡一個頂點3個GLfloat資料,所以間隔也是3*sizeof(GLfloat);
第六個引數為頂點資料起始地址偏移,這裡從0位置開始所以就是(void*)0;
(5)渲染三角形
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//設定清除顏色
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);//shaderProgram為CreateShaderProgram返回的著色器程式
glBindVertexArray(VAO);		//繫結VAO
glDrawArrays(GL_TRIANGLES, 0, 3);//畫三角形
(6)結束
程式退出前執行相應的清理工作,這裡只要刪除VAO、VBO和shaderProgram
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);

執行結果:


附上完整程式碼:
#include "glad/glad.h"
#include "glfw/glfw3.h"
#include<iostream>

const GLchar *vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 vertexPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(vertexPos, 1.0);\n"
"}\0";
const GLchar *fragmentShaderSource =
"#version 330 core\n"
"void main()\n"
"{\n"
"   gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
"}\n\0";

GLuint CreateShader(GLuint type, const GLchar* source)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);
	GLint success;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		char infoLog[512];
		glGetShaderInfoLog(shader, 512, NULL, infoLog);
		std::cout << infoLog << std::endl;
	}
	return shader;
}

GLuint CreateShaderProgram(const GLchar* vsSource, const GLchar* fsSource)
{
	GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, vsSource);
	GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER, fsSource);
	GLuint program = glCreateProgram();
	glAttachShader(program, vertexShader);
	glAttachShader(program, fragmentShader);
	glLinkProgram(program);
	GLint success;
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	if (!success)
	{
		char infoLog[512];
		glGetProgramInfoLog(program, 512, NULL, infoLog);
		std::cout << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	return program;
}

int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		return -1;
	}
	GLuint shaderProgram = CreateShaderProgram(vertexShaderSource,fragmentShaderSource);
	GLfloat vertices[] = {
		-0.5f,  0.5f, 0.0f,  // 1
		-0.5f, -0.5f, 0.0f,  // 2
		0.5f, -0.5f, 0.0f,  // 3
	};
	GLuint VBO, VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);
	{
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		{
			glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
			glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
			glEnableVertexAttribArray(0);
		}
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}
	glBindVertexArray(0);

	while (!glfwWindowShouldClose(window))
	{
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		glUseProgram(shaderProgram);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteProgram(shaderProgram);
	glfwTerminate();
	return 0;
}


相關推薦

OpenGL學習筆記繪製三角形

參考https://learnopengl.com/ 1、建立視窗 glfw是一個針對OpenGL的視窗管理庫,這裡使用glfw庫建立視窗並處理輸入,glfw庫可以在它的官網上下載,提供了動態庫和靜態庫供選擇,也可以下載原始碼自己編譯。以官方下載的靜態庫glfw3.lib為

opengl學習筆記 五 ——繪製複雜圖形

                本小節的程式碼參考了 http://www.cppblog.com/doing5552/arc

OpenGL學習筆記一(三角形

OpenGL學習筆記之三角形篇 在計算機圖形中三角形就如所有程式語言中的“hello world!”。所以接下來我們將要畫一個三角形。 在上一個篇部落格我已經講過OpenGL的環境配此次就不再詳細說明了(OpenGL的執行環境配置)。 參考資料(非

opengl es3.0遊戲開發學習筆記1-繪製旋轉的三角形

前段時間一直在看opengl es2.0遊戲開發的知識 ,這幾天買了本opengl es3.0遊戲開發的書   打算一邊學習一邊整理學習筆記,我的開發環境是Android studio 2.1.3,不過有個問題是Android studio自帶的模擬器只能支援es2

OpenGL學習繪製三角形

開發環境: MAC、xcode 上程式碼: 1.main.cpp // // main.cpp // GL_example // // Created by LiYong on 2018/2/28. // #include <

openGL幾何變換(繪製球體)---openGL學習筆記(六)

openGL中的變換包括:   ①檢視(modeling)---指定觀察者或者相機位置  GLU.glLookAt() 預設情況下,在透視投影中觀察者是從原點向Z軸負方向看去,也可以自行設定。   ②

Introduction to 3D Game Programming with DirectX 12 學習筆記 --- 第七章:在Direct3D中繪製(二)

程式碼工程地址: https://github.com/jiabaodan/Direct12BookReadingNotes 學習目標 理解本章中針對命令佇列的更新(不再需要每幀都flush命令佇列),提高效能; 理解其他兩種型別的根訊號引數型別:根描述

Introduction to 3D Game Programming with DirectX 12 學習筆記 --- 第六章:在Direct3D中繪製

程式碼工程地址: https://github.com/jiabaodan/Direct12BookReadingNotes 學習目標 熟悉Direct3D介面的定義,儲存和繪製幾何資料 ; 學習編寫基本的頂點和畫素著色器; 學習使用渲染流水線狀態

學習筆記Openlayers3】要素繪製篇(第三篇)

直接以專案例項來進行講解要素繪製 需求(假如): 1.實現在地圖上畫點線面功能 2.自定義其樣式 3.支援編輯功能 需要用到的openlayers3中的ol.interaction.Draw 類。這是openlayers3提供的內建互動方式,除了這

影象處理學習筆記直方圖的計算與繪製

影象直方圖包含豐富的影象細節資訊,反映了影象畫素點的概率分佈情況,它統計了每一個強度值具有的畫素個數。灰度級範圍是[0,L-1]的數字影象的直方圖是離散函式h(rk)=nk,其中是rk第k級灰度值,nk是影象中灰度為rk的畫素個數。在實踐中,經常用乘積MN表示的影象畫素總數

OpenGL_Qt學習筆記_04(3D圖形的繪製和旋轉)

     繪製四稜錐      四稜錐由5個面構成一個封閉的立體圖,其中4個共頂點的側面是三角形,底面是個四邊形。如果我們要繪製一個3D的四稜錐只需要繪製這5個面即可,繪製的方法和前一篇文章OpenGL_Qt學習筆記之_03(平面圖形的著色和旋轉)的相同。只不過這裡的頂點座標是3維的,所以影象深度那一維不

OpenGL學習筆記(三)OpenGL繪製方式

(1)OpenGL圖元    點:void glPointSize()    線、條帶、迴圈線:void glLineWidth()    三角形、條帶、扇面:    將多邊形渲染為點集、輪廓或者實體:   P68 正反面採用不同的方式繪製: glPolygonMode(GL

openGL三角形---openGL學習筆記(四)

在openGL中,所有面狀圖形的繪製都是使用畫三角形方法,而針對不同需求,openGL給出三種不同的畫三角形方法: ①traingles:畫三角形集 ②traingle_strip:畫三角形帶 ③traingle_fan:畫三角形扇面 畫三角形集在筆記(一)中已經實現

OpenGL_Qt學習筆記_02(繪製簡單平面幾何圖形)

#include "glwidget.h" #include "ui_glwidget.h" #include <QtGui> #include <QtCore> #include <QtOpenGL> #ifndef GL_MULTISAMPLE #define

Android OpenGL ES學習筆記新增顏色

一、分類 新增顏色的種類有兩種 - Flat coloring 單色 - Smooth coloring 平滑著色 單色 顧命思義就是一種單一的顏色,呼叫 glColor4f(float red,

Android OpenGL ES學習筆記常用API

上一篇文章Android OpenGL ES學習筆記之繪製點涉及到了一些API,在這篇文章配合一些例項給大家詳細的講解下,會持續更新。 我這裡有OpenGl ES 的API中文文件,不過不全,可以配合著看 開啟連結 密碼:gjlz 一、緩衝區 在O

【caffe學習筆記5】Win10系統下Caffe的Python介面設定方法並繪製網路結構圖

【準備工作】 前面幾節介紹了win10系統下caffe-master的配置方法以及cifar10資料集的訓練方法,並簡要介紹了Matlab介面如何配置。想要更為形象的瞭解caffe框架下諸多網路模型的

openGL圓環---openGL學習筆記(七)

畫圓環的想法與畫球體的想法大致相同,不同的是,圓環中間為空,而環體的直徑又相同,所以通過設定兩個半徑,用兩個半徑和角度就可以確定每個點的x,y,z座標。 首先,還是先把環體切成幾個部分,每個部分開啟之

openGL學習筆記1(入門----如何繪製 直線、多邊形、圓、利用圖片繪製圖形等)

#include <GL/glut.h> void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT);//GL_COLOR_BUFFER_BIT表示清除顏色 glRectf(-0.5f, -0.5f, 0.5f,

OpenGl學習筆記3模型變換、檢視變換、投影變換、視口變換介紹

模型變換、檢視變換、投影變換、視口變換介紹 opengl中存在四種變換,分別是模型變換,檢視變換,投影變換,視口變換。這四種變換是圖形渲染的基本操作,實質上這四種變換都是由矩陣乘法表示(這些操作都是由一個4*4的矩陣來完成的),通過變換,我們可以看到各種通的顯示效果,最簡單