OpenGL-座標系統,進入3D世界(深度測試)

目錄ios

座標系統簡介git

z緩衝github

舉個栗子數組

代碼安全

main.cppide

vertexSource.txt函數

fragmentSource.txt性能

截圖測試


參考:LearnOpenGLspa

座標系統簡介

座標變換爲標準化設備座標(Normalized Device Coordinate, NDC),接着再轉化爲屏幕座標的過程一般是分步進行的,也就是相似於流水線那樣子。在流水線中,物體的頂點在最終轉化爲屏幕座標以前還會被變換到多個座標系統(Coordinate System)。將物體的座標變換到幾個過渡座標系(Intermediate Coordinate System)的優勢在於,在這些特定的座標系統中,一些操做或運算更加方便和容易,這一點很快就會變得很明顯。對咱們來講比較重要的總共有5個不一樣的座標系統:

  • 局部空間(Local Space,或者稱爲物體空間(Object Space))
  • 世界空間(World Space)
  • 觀察空間(View Space,或者稱爲視覺空間(Eye Space))
  • 裁剪空間(Clip Space)
  • 屏幕空間(Screen Space)

爲了將座標從一個座標系變換到另外一個座標系,咱們須要用到幾個變換矩陣,最重要的幾個分別是模型(Model)、觀察(View)、投影(Projection)三個矩陣。

來源於LearnOpenGL
  1. 局部座標是對象相對於局部原點的座標,也是物體起始的座標。
  2. 下一步是將局部座標變換爲世界空間座標,世界空間座標是處於一個更大的空間範圍的。這些座標相對於世界的全局原點,它們會和其它物體一塊兒相對於世界的原點進行擺放。
  3. 接下來咱們將世界座標變換爲觀察空間座標,使得每一個座標都是從攝像機或者說觀察者的角度進行觀察的。
  4. 座標到達觀察空間以後,咱們須要將其投影到裁剪座標。裁剪座標會被處理至-1.0到1.0的範圍內,並判斷哪些頂點將會出如今屏幕上。
  5. 最後,咱們將裁剪座標變換爲屏幕座標,咱們將使用一個叫作視口變換(Viewport Transform)的過程。視口變換將位於-1.0到1.0範圍的座標變換到由glViewport函數所定義的座標範圍內。最後變換出來的座標將會送到光柵器,將其轉化爲片斷。

接下來採用透視投影,即人眼所感到的近大遠小。

 

z緩衝

接下來咱們將畫多個立方體,問題來了,若是多個立方體有重疊部分,按照咱們視覺來講,前面的物體,應該遮擋住後面的物體。

那麼在OpenGL中該如何實現呢?

OpenGL存儲它的全部深度信息於一個Z緩衝(Z-buffer)中,也被稱爲深度緩衝(Depth Buffer)。GLFW會自動爲你生成這樣一個緩衝(就像它也有一個顏色緩衝來存儲輸出圖像的顏色)。深度值存儲在每一個片斷裏面(做爲片斷的z值),當片斷想要輸出它的顏色時,OpenGL會將它的深度值和z緩衝進行比較,若是當前的片斷在其它片斷以後,它將會被丟棄,不然將會覆蓋。這個過程稱爲深度測試(Depth Testing),它是由OpenGL自動完成的。

使用下面代碼開啓深度測試

glEnable(GL_DEPTH_TEST);

使用glclear函數進行清除

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
舉個栗子

代碼

相對於上篇文章,咱們修改了main.cpp(畫了6個面,添加了深度測試)、vertexSource.txt(教程沒有給顏色,去除了Color)、fragmentSource.txt(教程沒有給顏色,去除了Color)

main.cpp

//頭文件
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

//函數聲明
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// 設置窗體寬高
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

//主函數
int main()
{
	// glfw: 初始化和配置
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 
#endif
	// glfw 窗體生成
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "rectwithtex", NULL, NULL);//設置標題
	//判斷窗體是否生成
	if (window == NULL)
	{
		std::cout << "生成GLFW窗口失敗" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	// glad: 加載全部的OpenGL功能指針----------------------------------------------------------
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "初始化GLAD失敗" << std::endl;
		return -1;
	}
	//開啓深度測試
	glEnable(GL_DEPTH_TEST);
	// 創建並編譯着色器--------------------------------------------------------------------
	Shader* myShader = new Shader("vertexSource.txt", "fragmentSource.txt");

	// 設置點數據 (還有緩衝) 配置點的屬性(包含點座標等) 這裏設置了4個,將以索引的方式選擇點來畫三角形
	float vertices[] = {
		-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
		0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
		0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
		0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
		0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
		-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

		-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

		0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
		0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
		0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
		0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
		-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

		-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
		0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
		0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
		-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
		-0.5f,  0.5f, -0.5f,  0.0f, 1.0f
	};
	unsigned int indices[] = {  
		0, 1, 2,  // 第一個三角形選擇索引爲 0 1 3的三個點
		2, 3, 0,  // 第一個三角形選擇索引爲 1 2 3的三個點
	};
	unsigned int VBO, VAO, EBO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);  //注意,這裏使用EBO做爲緩衝對象
	// 綁定頂點數組, 而後綁定並設置緩衝, 最後配置頂點屬性-------------------------------
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
	//修改屬性-----------------------------------------------------------------------------
	glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(6);
	//glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	//glEnableVertexAttribArray(7);
	glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(8);
	//紋理-------------------------------------------------------------------------------
	unsigned int TexBufferA, TexBufferB;
	stbi_set_flip_vertically_on_load(true);//y軸翻轉
	//木箱部分
	glGenTextures(1, &TexBufferA);
	//激活
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	/*glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);*/
	glDrawArrays(GL_TRIANGLES, 0, 36);
	glBindTexture(GL_TEXTURE_2D, TexBufferA);//綁定
	int width, height, nrChannels;
	unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
	if (data)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		glGenerateMipmap(GL_TEXTURE_2D);//生成多級漸遠紋理
	}
	else
	{
		std::cout << "加載紋理失敗" << std::endl;
	}
	stbi_image_free(data);//釋放
	//笑臉部分
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE3);
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
	glBindTexture(GL_TEXTURE_2D, TexBufferB);//綁定
	unsigned char *data2 = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
	if (data)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);//注意,有Alpha通道
		glGenerateMipmap(GL_TEXTURE_2D);//生成多級漸遠紋理
	}
	else
	{
		std::cout << "加載紋理失敗" << std::endl;
	}
	stbi_image_free(data2);

	//注意這是容許的,對glVertexAttribPointer的調用將VBO註冊爲頂點屬性的綁定頂點緩衝區對象,因此以後咱們能夠安全地解除綁定
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	// 記住:當VAO處於活動狀態時,不要取消綁定EBO,由於綁定元素緩衝對象IS存儲在VAO中; 保持EBO的約束力。
	//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	// 您能夠在以後取消綁定VAO,以便其餘VAO調用不會意外地修改此VAO,但這種狀況不多發生。不管如何, 
	// 修改其餘VAO須要調用glBindVertexArray,所以咱們一般不會在不直接須要時解除VAO(VBO一樣)的綁定。
	glBindVertexArray(0);

	// 取消註釋此調用會繪製線框多邊形。
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	//glm相關------------------------------------------------------------------
	// 下面就是矩陣初始化的一個例子,若是使用的是0.9.9及以上版本
	// 下面這行代碼就須要改成:
	// glm::mat4 trans = glm::mat4(1.0f)
	glm::mat4 trans;
	//trans = glm::translate(trans, glm::vec3(1.0f, 0.0f, 0.0f));
	//trans = glm::rotate(trans, glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f));
	//trans = glm::scale(trans, glm::vec3(1.30, 1.30, 1.30));
	glm::mat4 modelMat;
	//modelMat = glm::rotate(modelMat, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
	
	glm::mat4 viewMat;
	// 注意,咱們將矩陣向咱們要進行移動場景的反方向移動。
	viewMat = glm::translate(viewMat, glm::vec3(0.0f, 0.0f, -3.0f));
	glm::mat4 projMat;
	projMat = glm::perspective(glm::radians(45.0f),800.0f / 600.0f,0.1f, 100.0f);//(透視投影,遠小近大)


	while (!glfwWindowShouldClose(window))
	{
		//隨時間旋轉
		modelMat = glm::rotate(modelMat, (float)glfwGetTime() * glm::radians(1.0f), glm::vec3(0.5f, 1.0f, 0.0f));
		// 輸入
		processInput(window);
		Sleep(200);
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		//清除顏色及深度測試
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		//綁定紋理
		glActiveTexture(GL_TEXTURE0); // 在綁定紋理以前先激活紋理單元
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE3); // 在綁定紋理以前先激活紋理單元
		glBindTexture(GL_TEXTURE_2D, TexBufferB);
		glBindVertexArray(VAO);
		/*glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);*/
		glDrawArrays(GL_TRIANGLES, 0, 36);
		//使用着色器
		myShader->use();
		glUniform1i(glGetUniformLocation(myShader->ID, "ourTexture"), 0); // 手動設置
		//glUniform1i(glGetUniformLocation(myShader->ID, "ourFace"), 3); // 手動設置
		myShader->setInt("ourFace", 3); // 或者使用着色器類設置
		/*unsigned int transformLoc = glGetUniformLocation(myShader->ID, "transform");*/
		/*glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));*/
		unsigned int modelMatLoc = glGetUniformLocation(myShader->ID, "modelMat");
		unsigned int viewMatLoc = glGetUniformLocation(myShader->ID, "viewMat");
		unsigned int projMatLoc = glGetUniformLocation(myShader->ID, "projMat");
		glUniformMatrix4fv(modelMatLoc, 1, GL_FALSE, glm::value_ptr(modelMat));
		glUniformMatrix4fv(viewMatLoc, 1, GL_FALSE, glm::value_ptr(viewMat));
		glUniformMatrix4fv(projMatLoc, 1, GL_FALSE, glm::value_ptr(projMat));


		// 畫矩形--------------------------------------------------------------------------
		//能夠知道咱們只有一個三角形VAO,不必每次都綁定它,可是咱們這麼作會讓代碼有一點組織性
		glBindVertexArray(VAO);
		//glDrawArrays(GL_TRIANGLES, 0, 6);
		/*glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);*/
		glDrawArrays(GL_TRIANGLES, 0, 36);
		// glBindVertexArray(0); //不必每次都解綁 
		// 交換buffers和poll的IO事件 (按鍵按下/釋放,鼠標移動等.)
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	//一旦他們超出已有的資源,就取消全部資源的分配:
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteBuffers(1, &EBO);
	// glfw:終止,清空以前全部的GLFW的預分配資源
	glfwTerminate();
	return 0;
}
//查詢GLFW相關按鍵是否被按下/釋放,根據狀況做出反應
void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
}
// g不管窗口大小什麼時候改變(由操做系統或用戶本身)這個回調函數將會被執行
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	//肯定viewport與新的窗口尺寸匹配; 請注意,寬度和高度將明顯大於顯示器上指定的寬度和高度。
	glViewport(0, 0, width, height);
}

vertexSource.txt

#version 330 core
layout (location = 6) in vec3 aPos;
//layout (location = 7) in vec3 aColor;
layout (location = 8) in vec2 aTexCoord;
//out vec4 vertexColor;
out vec2 TexCoord;

uniform mat4 transform;

uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;

void main()
{
   //gl_Position = transform * vec4(aPos.x, aPos.y, aPos.z, 1.0);
   gl_Position = projMat *  viewMat  * modelMat * vec4(aPos.x, aPos.y, aPos.z, 1.0);
   //vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);
   TexCoord = aTexCoord;
}

fragmentSource.txt

#version 330 core
out vec4 FragColor;
//in vec4 vertexColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
uniform sampler2D ourFace;
void main()
{
   //FragColor = vertexColor;
   FragColor = mix(texture(ourTexture, TexCoord), texture(ourFace, TexCoord), 0.6);
}

截圖

結果截圖

注:隨時間增大,旋轉速度加快,電腦性能很差請及時關閉程序,省得變成暖寶寶。

更多OpenGL知識:現代OpenGL入門教程

有問題請下方評論,轉載請註明出處,並附有原文連接,謝謝!若有侵權,請及時聯繫。

相關文章
相關標籤/搜索