理解GL管线(二)着器(认识顶点着器和片段着器)

理解GL管线(⼆)着⾊器(认识顶点着⾊器和⽚段着⾊器)1.GLSL语⾔
GLSL是着⾊器语⾔的⼀种,其他的着⾊器语⾔如HLSL,微软的3D框架DirectX等。着⾊器语⾔程序主要运⾏在GPU上。
GLSL是与OpenGL兼容的专⽤着⾊器语⾔,因此我们需要⽤GLSL编写着⾊器使⽤的程序代码。并将编写完的代码载⼊各个着⾊器阶段。其过程如下:
(1)编写GLSL程序代码(可以写进⽂件中,也可以硬编码在C++程序的字符串中。)
(2)使⽤C++获取GLSL程序代码。
(3)创建OpenGL着⾊器对象,并将GLSL程序代码加载进着⾊器对象。
(4)⽤OpenGL命令编译并链接着⾊器对象,并将其安装进GPU。
实践中,⾄少要顶点着⾊器和⽚段着⾊器阶段的GLSL代码,⽽曲⾯细分着⾊器和⼏何着⾊器阶段是可选的。
2.图元
  OpenGL只允许绘制三类图形:点、线、三⾓形。它们叫做图元。即便是复杂的3D模型通常也是由许多三⾓形构成的。
  图元由顶点组成。例如三⾓形有三个顶点。
  顶点的来源可以是任意的,从⽂件中读取、硬编码在C++程序中或者直接在GLSL代码中。加载的顶点会被载⼊管线,经由着⾊器处理,最终变成屏幕上的各种形状。
  Gl通过【glDrawArrays(GLenum mode,Glint first,Glsizei count)】⽅法绘制图元,其中mode是图元类型,first是从那个顶点开始绘制(通常是顶点0)。当调⽤该⽅法时,管线中的着⾊器(顶点着⾊器开始)开始执⾏。
商用微波炉
3.光栅化
  我们的显⽰器屏幕由光栅(矩形像素阵列)组成。当光栅化后,OpenGL将物体中的图元转化为⽚段,⽚段拥有关于像素的信息。光栅化过程确定了所有像素需要绘制的位置,这个过程会进⾏插值,以便确定两个顶点间的所有像素的位置。通过【glpolygonMode】⽅法可以设置呈现线框效果还是填充效果。
  光栅化不仅可以对像素插值,任何顶点着⾊器的输出变量和⽚段着⾊器的输⼊变量都可以基于对应
的像素插值。利⽤该功能可以实现平滑的颜⾊渐变和真是光照等效果。
4.着⾊器
液晶屏保护膜
  顶点着⾊器:即处理顶点的着⾊器,所有顶点被载⼊管线后都会经由顶点着⾊器(即会对每个顶点执⾏⼀次(通常时并⾏的)),处理后载⼊管线的下⼀步。通过顶点着⾊器可以改变绘制内容的形状,包括形状⼤⼩、位置、⾓度、投影等等。
  ⽚段着⾊器:⽚段着⾊器负责为光栅化的像素指定颜⾊,所有顶点光栅化后经由⽚段着⾊器都会被赋值颜⾊,并且也会被插值处理。
代码⽰例:画⼀个三⾓形,并且左边为红⾊,右边为蓝⾊。
//GLSL程序代码(顶点着⾊器),写在【vertShrfer.glsl】中
#version 430
uniform float offset;
void main(void)
{
if(gl_VertexID == 0)
gl_Position = vec4(0.25 + offset, -0.25, 0.0, 1.0);
if(gl_VertexID == 1)
gl_Position = vec4(-0.25 + offset, -0.25, 0.0, 1.0);
if(gl_VertexID == 2)
gl_Position = vec4(0.25 + offset, 0.25, 0.0, 1.0);
}
//GLSL程序代码(⽚段着⾊器),写在【fragShrfer.glsl】中
#version 430
out vec4 color;
void main(void)
{ if(gl_FragCoord.x < 200)
color = vec4(1.0, 0.0, .0, 1.0);
 else color = vec4(0.0,0.0,1.0,1.0);
}
#include <GL\glew.h>
#include <GLFW\glFW3.h>
#include <string>
#include <iostream>
#include <fstream>
#define numVAOs 1
GLuint renderingProgram;
GLuint vao[numVAOs]; //定义voa
float x = 0.0f;//三⾓形在X轴偏移量
float inc = 0.01f;//三⾓形的移动步长
//读取⽂件内容并转成String
string readShaderSource(const char *filePath) {
string content;
ifstream fileStream(filePath, ios::in);
string line = "";
while (!f()) {
getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
//创建着⾊器程序
GLuint createShaderProgram() {
iesp-144string vertShaderStr = readShaderSource("vertShader.glsl"); //从⽂件中读取着⾊器程序代码字符串    string fragShaderStr = readShaderSource("fragShader.glsl"); //同上
const char *vertShaderSrc = vertShaderStr.c_str();
const char *fragShaderSrc = fragShaderStr.c_str();
GLuint vShader = glCreateShader(GL_VERTEX_SHADER); //创建顶点着⾊器对象,返回对象ID
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER); //创建⽚段着⾊器对象,返回对象ID    glShaderSource(vShader, 1, &vertShaderSrc, NULL); //将GLSL代码载⼊空着⾊器对象
glShaderSource(fShader, 1, &fragShaderSrc, NULL); //同上
glCompileShader(vShader); //编译着⾊器
glCompileShader(fShader); //同上
GLuint vfProgram = glCreateProgram(); //创建OpenGL程序对象,它包含⼀系列编译过的着⾊器对象。    glAttachShader(vfProgram, vShader); //将着⾊器对象加⼊程序对象
glAttachShader(vfProgram, fShader); //同上
glLinkProgram(vfProgram); //请求GLSL编译器确保新加⼊着⾊器对象的兼容性
//返回程序对象ID
return vfProgram;
}
int main(void) {
//初始化glfw库
if (!glfwInit())
{
exit(EXIT_FAILURE);
}
//设置gl主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
//设置gl次版本号,与主版本号⼀起指定了机器必须与opengl4.3版本兼容
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//创建glfw窗⼝,⼤⼩1280x640像素,窗⼝标题(window1)
38ggg
GLFWwindow* window = glfwCreateWindow(1280,640,"window1", NULL, NULL);
//通知GLFW将我们窗⼝的上下⽂设置为当前opengl线程的主上下⽂
glfwMakeContextCurrent(window);
//初始化glew库
wan-107if (glewInit() != GLEW_OK)
{
exit(EXIT_FAILURE);
}
//设置缓冲区交换间隔(帧)。默认情况下,交换间隔为0,但因缓冲区
//有可能在屏幕更新的中间交换,出现屏幕撕裂的情况。
//所以,可以将该间隔设为1,即每帧更新⼀次。它可以设置为更⾼的
/
/值,但这可能导致输⼊延迟。
glfwSwapInterval(1);
init(window);
//检查GLFW是否被要求退出
while (!glfwWindowShouldClose(window)) {
display(window, glfwGetTime()); //glfwGetTime:获取glfw初始化后经过的时间
//交换缓冲区
glfwSwapBuffers(window);
下变频器//glfwPollEvents函数检查有没有触发什么事件(⽐如键盘输⼊、⿏标移动等)、更新窗⼝状态,并调⽤对应的回调函数(可以通过回调⽅法⼿动设置)。
glfwPollEvents();
}
//glfw销毁窗⼝
glfwDestroyWindow(window);
//glfw终⽌运⾏
glfwTerminate();
exit(EXIT_SUCCESS);
}
void init(GLFWwindow* window) {
renderingProgram = createShaderProgram(); //创建OpenGL程序对象,它包含⼀系列编译过的着⾊器对象
glGenVertexArrays(numVAOs, vao); //创建Vao
glBindVertexArray(vao[0]);//激活VAO
}
void display(GLFWwindow* window, double currentTime) {
glClear(GL_DEPTH_BUFFER_BIT);//清除深度缓冲区
glClearColor(0.0,0.0,0.0,0.1);//清除颜⾊缓冲区
glClean(GL_COLOR_BUFFER_BIT)//将背景清除为⿊⾊
glUseProgram(renderingProgram); //将OpenGL程序(包含我们编译进去的两个着⾊器对象)载⼊管线阶段(在GPU上);这⼀步并没有运⾏着⾊器,只是将着⾊器加载进硬件 x += inc;
if(x > 1.0f) inc = -0.001f;
if(x < -1.0f) inc = 0.01f;
GLuint offsetLoc = glGetUniformLocation(renderingProgram,"offset");//获取offset统⼀变量指针
glProgramUniform1f(renderingProgram,offsetLoc,x);//给统⼀变量赋值
glDrawArrays(GL_TRIANGLES, 0, 3);//启动管线,描绘内容,图元是点。即描画⼀个点。
}
5.着⾊器代码解析:
顶点着⾊器:
  #version 430 //指明GL版本:4.3
  void main(void) //着⾊器是⼀个程序,与C++类似,也是从main函数开始
  gl_Position//这是⼀个预定义的输出变量。⽤来设置顶点。并发送⾄下⼀个管线。
  gl_VertexID//这也是⼀个预定义变量,会在每次调⽤时⾃增。
  gl_FragCoord//这也是⼀个预定义变量,他可以访问输⼊⽚段的坐标
  vec4//四元组,这⾥⽤来存储x,y,z,和齐次坐标值。
  offset//统⼀变量,CPU传给GPU的数据
  createShaderProgram//这个⽅法应该⽀持重载,以便加载不同的着⾊器组合。
⽚段着⾊器:
  out vec4 color; //指定⼀个输出变量,类型为四元组,名称是color。输出变量会⾃动输出到管线的下⼀阶段。
VAO:
  vao是⽤来管理缓冲区的,所有的缓冲区都会被存⼊VAO。即便不使⽤任何缓冲区,OpenGl仍然需要创建⾄少⼀个VAO。

本文发布于:2024-09-22 10:37:23,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/1/251559.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:顶点   变量   对象   像素   程序   光栅
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议