着色器

GLSL:
着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。
顶点着色器的每个输入变量也叫顶点属性,至少16个包含4分量的顶点属性够用。
数据类型:
int、float、double、uint和bool。
两个容器:向量(Vector)和矩阵(Matrix)。
vecn 包含n个float分量的默认向量
bvecn 包含n个bool分量的向量
ivecn 包含n个int分量的向量
uvecn 包含n个unsigned int分量的向量
dvecn 包含n个double分量的向量


访问时按照.x.y.z.w,或者颜色rgba,纹理stpq
重组(Swizzling):
vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
传参方式:
vec2 vect = vec2(0.5f, 0.7f);
vec4 result = vec4(vect, 0.0f, 0.0f);
vec4 otherResult = vec4(result.xyz, 1.0f);


输入与输出:
为了定义顶点数据该如何管理,我们使用location这一元数据指定输入变量,这样我们才可以在CPU上配置顶点属性
片段着色器:发送vec5

链接程序做的事情就是从一个着色器像另一个着色器发送数据。

着色器用in out数据传递

const GLchar* vertexShaderSource = "#version 330 core\n"
"layout(location = 0) in vec3 position;\n"
"out vec4 vertexColor;\n"
"void main()\n"
"{\n"
"	gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f);\n"
"}\0";

const GLchar* fragmentShaderSource = "#version 330 core\n"
"in vec4 vertexColor;\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vertexColor;\n"
"}\0";

Uniform:相当于去全局的顶点属性。

const GLchar* fragmentShaderSource = "#version 330 core\n"

"out vec4 color;\n"
"uniform vec4 ourColor;\n"
"void main()\n"
"{\n"
"color = ourColor;\n"
"}\0";

GLfloat timeValue = glfwGetTime();
GLfloat greenValue = (sin(timeValue) / 2) + 0.5;
GLint vertexColorLocation = glGetUniformLocation(shaderProgramOrange, "ourColor");
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
/*
首先我们通过glfwGetTime()获取运行的秒数。然后我们使用sin函数让颜色在0.0到1.0之间改变,最后将结果储存到greenValue里
接着,我们用glGetUniformLocation查询uniform ourColor的位置值。我们为查询函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)。
如果glGetUniformLocation返回-1就代表没有找到这个位置值。最后,我们可以通过glUniform4f函数设置uniform值。
注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个unform之前你必须先使用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置unform的。
*/


之后颜色会随时间变化。


之后是添加更多属性:

更新了属性后的VBO内存中的数据:


// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#include <iostream>

void key_callback(GLFWwindow* windows, int key, int scancode, int action, int mode);


//顶点着色器源码:
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout(location = 0) in vec3 position;\n"
"layout(location = 1) in vec3 color;\n"
//这里用layout标识符把color属性设置为1
"out vec3 ourColor;\n"
"void main()\n"
"{\n"
"	gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"ourColor = color;\n"
"}\0";

const GLchar* fragmentShaderSource = "#version 330 core\n"

"in vec3 ourColor;\n"
"out vec4  color;\n"
"void main()\n"
"{\n"
"color = vec4(ourColor, 1.0f);\n"
"}\n\0";

int main()
{

	std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;

	//这都是初始化GLFW,后面的要看文档
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);


	//创建窗口,
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);//通知GLFW将我们窗口的上下文设置为当前线程的主上下文


	//不知道回调函数为什么要加在这里??
	//glfwSetKeyCallback(window, key_callback2);回调函数只有最下面那个有作用
	glfwSetKeyCallback(window, key_callback);


	//初始化GLEW(管理OpenGL的函数指针)
	glewExperimental = GL_TRUE;
	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to initialize GLEW" << std::endl;
		return -1;
	}

	//视口,OpenGl知道相对于窗口大小显示数据和坐标
	int width, height;
	glfwGetFramebufferSize(window, &width, &height);
	glViewport(0, 0, width, height);//前两个控制左下角的位置,后面是窗口宽度高度(像素)

	//动态编译着色器源码:
	GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
	GLuint fragmentShaderOrange = glCreateShader(GL_FRAGMENT_SHADER);

	GLuint shaderProgramOrange = glCreateProgram();

	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	glShaderSource(fragmentShaderOrange, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShaderOrange);

	glAttachShader(shaderProgramOrange, vertexShader);
	glAttachShader(shaderProgramOrange, fragmentShaderOrange);
	glLinkProgram(shaderProgramOrange);



 
	GLfloat vertices[] = {
		//位置                      //颜色
		0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // 右下
		-0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // 左下
		0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // 顶部
	};

	

	


	GLuint VBO, VAO;
	//使用glGenBuffers函数和一个缓冲ID生成一个VBO对象??
	glGenBuffers(1, &VBO);
	glGenVertexArrays(1, &VAO);
	

	//绑定VAO
	glBindVertexArray(VAO);
	//复制顶点数组到缓冲中,glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数
	glBindBuffer(GL_ARRAY_BUFFER, VBO);//glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


	

	//设置顶点属性指针,和颜色属性
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
	glEnableVertexAttribArray(1);
	//因为现在是两个属性,需要向右移动步长,6个

	glBindVertexArray(0);
	//安全?
	
	





	//防止退出的循环
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents();


		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		//glClearColor是一个状态设置函数,glClear是一个状态应用函数

		//绘图
		glUseProgram(shaderProgramOrange);


	
	

		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);//绘制图形函数,0-3是数组索引
		glBindVertexArray(0);

		

		glfwSwapBuffers(window);
	}

	//回调函数
	
	//释放:
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);

	glfwTerminate(); //释放/删除之前的分配的所有资源
	return 0;
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{

	std::cout << key << std::endl;
	//用户按下ESC键,我们设置window窗口WindowShouldClose属性为true
	//关闭应用程序
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);
}



效果图:

其中的渐变色就是片段插值(Fragment Interpolation)的结果。

练习1:Adjust the vertex shader so that the triangle is upside down:

这个被脑筋急转弯了,修改y轴为负即可。

练习2:Specify a horizontal offset via a uniform and move the triangle to the right side of the screen in the vertex shader using this offset value:

const GLchar* vertexShaderSource = "#version 330 core\n"
"layout(location = 0) in vec3 position;\n"
"layout(location = 1) in vec3 color;\n"

//这里用layout标识符把color属性设置为1
"out vec3 ourColor;\n"
"uniform float xOffset;\n"
"void main()\n"
"{\n"
"	gl_Position = vec4(position.x+xOffset, -position.y, position.z, 1.0);\n"
"ourColor = color;\n"
"}\0";


float offset = 0.5f;

		glUniform1f(glGetUniformLocation(shaderProgramOrange, "xOffset"), offset);


3.Output the vertex position to the fragment shader using the out keyword and set the fragment's color equal to this vertex position (see how even the vertex position values are interpolated across the triangle). Once you managed to do this; try to answer the following question: why is the bottom-left side of our triangle black?

const GLchar* vertexShaderSource = "#version 330 core\n"
"layout(location = 0) in vec3 position;\n"

//这里用layout标识符把color属性设置为1
"out vec3 outp;\n"
"void main()\n"
"{\n"
"	gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"outp = position;\n"
"}\0";
注意这里out的时候需要在mian里新建变量进行转接。

效果图:

左下角是黑色的原因也就是,把负的左边都变成了0.


如何封装目前所学的知识到一个抽象对象中。
写自己的着色器类。
预处理指令的作用:预处理指令会告知你的编译器只在它没被包含过的情况下才包含和编译这个头文件,
即使多个文件都包含了这个着色器头文件。
它是用来防止链接冲突的。

封装好的类直接用就可以了。

Shader.h:

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <GL/glew.h>; // 包含glew来获取所有的必须OpenGL头文件

class Shader
{
public:
	// 程序ID
	GLuint Program;
	// 构造器读取并构建着色器
	


	Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
	{
		//从文件路径获取顶点,片段着色器
		std::string vertexCode;
		std::string fragmentCode;
		std::ifstream vShaderFile;
		std::ifstream fShaderFile;
		// 保证ifstream对象可以抛出异常:
		vShaderFile.exceptions(std::ifstream::badbit);
		fShaderFile.exceptions(std::ifstream::badbit);
		try
		{
			// 打开文件
			vShaderFile.open(vertexPath);
			fShaderFile.open(fragmentPath);
			std::stringstream vShaderStream, fShaderStream;
			// 读取文件的缓冲内容到流中
			vShaderStream << vShaderFile.rdbuf();
			fShaderStream << fShaderFile.rdbuf();
			// 关闭文件
			vShaderFile.close();
			fShaderFile.close();
			// 转换流至GLchar数组
			vertexCode = vShaderStream.str();
			fragmentCode = fShaderStream.str();
		}
		catch (std::ifstream::failure e)
		{
			std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
		}
		const GLchar* vShaderCode = vertexCode.c_str();
		const GLchar* fShaderCode = fragmentCode.c_str();

		//编译和链接着色器。
		GLuint vertex, fragment;
		GLint success;
		GLchar infoLog[512];

		// 顶点着色器
		vertex = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex, 1, &vShaderCode, NULL);
		glCompileShader(vertex);
		// 打印编译错误(如果有的话)
		glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(vertex, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
		};

		fragment = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragment, 1, &fShaderCode, NULL);
		glCompileShader(fragment);
		// Print compile errors if any
		glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(fragment, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
		}
		this->Program = glCreateProgram();
		glAttachShader(this->Program, vertex);
		glAttachShader(this->Program, fragment);
		glLinkProgram(this->Program);
		// 打印连接错误(如果有的话)
		glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
		if (!success)
		{
			glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
		}

		// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了
		glDeleteShader(vertex);
		glDeleteShader(fragment);
	}
	void Use()
	{
		glUseProgram(this->Program);
	}
};

#endif

shader.vs和shader.frag直接写在资源里。

用的时候可以这样写:

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#include <iostream>
#include "Shader.h"

void key_callback(GLFWwindow* windows, int key, int scancode, int action, int mode);


//顶点着色器源码:




int main()
{

	std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;

	//这都是初始化GLFW,后面的要看文档
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);


	//创建窗口,
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);//通知GLFW将我们窗口的上下文设置为当前线程的主上下文


	//不知道回调函数为什么要加在这里??
	//glfwSetKeyCallback(window, key_callback2);回调函数只有最下面那个有作用
	glfwSetKeyCallback(window, key_callback);


	//初始化GLEW(管理OpenGL的函数指针)
	glewExperimental = GL_TRUE;
	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to initialize GLEW" << std::endl;
		return -1;
	}

	//视口,OpenGl知道相对于窗口大小显示数据和坐标
	int width, height;
	glfwGetFramebufferSize(window, &width, &height);
	glViewport(0, 0, width, height);//前两个控制左下角的位置,后面是窗口宽度高度(像素)

	Shader ourShader("shader.vs", "shader.frag");
 
	GLfloat vertices[] = {
		//位置                      //颜色
		0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // 右下
		-0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // 左下
		0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // 顶部
	};

	

	


	GLuint VBO, VAO;
	//使用glGenBuffers函数和一个缓冲ID生成一个VBO对象??
	glGenBuffers(1, &VBO);
	glGenVertexArrays(1, &VAO);
	

	//绑定VAO
	glBindVertexArray(VAO);
	//复制顶点数组到缓冲中,glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数
	glBindBuffer(GL_ARRAY_BUFFER, VBO);//glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


	

	//设置顶点属性指针,和颜色属性
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	
	//因为现在是两个属性,需要向右移动步长,6个

	glBindVertexArray(0);
	//安全?
	
	





	//防止退出的循环
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents();


		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		//glClearColor是一个状态设置函数,glClear是一个状态应用函数

		//绘图
		ourShader.Use();

		
		


		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);//绘制图形函数,0-3是数组索引
		glBindVertexArray(0);

		

		glfwSwapBuffers(window);
	}

	//回调函数
	
	//释放:
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);

	glfwTerminate(); //释放/删除之前的分配的所有资源
	return 0;
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{

	std::cout << key << std::endl;
	//用户按下ESC键,我们设置window窗口WindowShouldClose属性为true
	//关闭应用程序
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);
}


shader.vs

#version 330 core
layout(location = 0) in vec3 position;
out vec3 outp;
void main()
{
	gl_Position = vec4(position.x, position.y, position.z, 1.0);
outp = position;
}

shader.frag

#version 330 core
in vec3 outp;
out vec4  color;
void main()
{
color = vec4(outp,1.0);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值