OpenGL 笔记1

传输顶点数据:

VBO

float vertices[]...
...
//创建并绑定顶点缓冲对象VBO 即在GPU中储存一大堆顶点属性的地方,方便GPU读取
unsigned int VBO;
glGenBuffers(1, &VBO);
//GL_ARRAY_BUFFER表示顶点缓冲对象的类型
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//把之前定义的顶点数据复制到缓冲的内存中
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

 EBO

float indices[]...
...
//改为用索引查询顶点信息,重复利用顶点
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

VAO

//(阐明应当如何读取VBO的数据,并将获取的顶点数据正确链接到顶点着色器的顶点属性上)
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

//绑定VAO后再设置该VAO里想用的VBO和EBO
...VBO code
...EBO code

//设置并启用顶点属性,以便shader获取 |比如设置了两个顶点属性 vec3 pos; vec2 uv;
//layout=0 三个值 float类型 不标准化(normalize) 步长(每隔5个float长度读取) 偏移0
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//layout=1 2个值 float类型 不标准化(normalize) 步长(每隔5个float长度读取) 偏移3个float(跳过pos)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float));
glEnableVertexAttribArray(1);

glBindVertexArray(0);//解绑VAO以待后续使用

渲染

//可以把一个VAO看做一个等待渲染的物体
glUseProgram(shaderProgram);//使用什么着色器渲染
glBindVertexArray(VAO);//确定要渲染什么物体
//渲染物体:未开启EBO调用前者,开启调用后者|如长方形这里渲染六个顶点,(使用EBO为6个索引,实为4个顶点)
glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)

glBindVertexArray(0);//解绑物体

编写着色器 编译使用着色程序

着色器格式

//---------------顶点着色器-------------------
#version 330 core
layout (location = 0) in vec3 aPos; // 顶点属性 输入

out vec4 vertexColor; // 输出

uniform float somedata;//全局变量,相对每个着色程序

void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
}
//----------------片元着色器-------------------
#version 330 core

in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)

out vec4 FragColor;//输出

uniform vec3 somecolor;

void main()
{
    FragColor = vertexColor;
}

编译设置着色程序的shader类

#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h>

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

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>


class Shader
{
public:
	unsigned int ID;
	//构造器创建shader程序
	Shader(const GLchar* vertexPath, const GLchar* fragmentPath) {
		//1.从文件路径中读取顶点片元着色器源码
		std::string vertexCode;
		std::string fragmentCode;
		//创建输入i文件f流
		std::ifstream vShaderFile;
		std::ifstream fShaderFile;
		vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
		fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
		try
		{
			//打开文件
			vShaderFile.open(vertexPath);
			fShaderFile.open(fragmentPath);
			//读取至字符串流
			std::stringstream vShaderStream, fShaderStream;
			vShaderStream << vShaderFile.rdbuf();
			fShaderStream << fShaderFile.rdbuf();
			//关闭文件
			vShaderFile.close();
			fShaderFile.close();
			//转换数据流
			vertexCode = vShaderStream.str();
			fragmentCode = fShaderStream.str();
		}
		catch (std::ifstream::failure e)
		{
			std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
		}
		const char* vShaderCode = vertexCode.c_str();
		const char* fShaderCode = fragmentCode.c_str();
		//2.编译着色器
		int success;
		char infoLog[512];

#pragma region 创建并编译顶点着色器
		int vertexShader = glCreateShader(GL_VERTEX_SHADER);
		//将着色器源码与着色器对象绑定
		glShaderSource(vertexShader, 1, &vShaderCode, NULL);
		//编译并检查是否编译成功
		glCompileShader(vertexShader);
		glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
		}

#pragma endregion

#pragma region 创建并编译顶点着色器
		int fragShader = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragShader, 1, &fShaderCode, NULL);
		glCompileShader(fragShader);
		glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(fragShader, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
		}
#pragma endregion

#pragma region 创建着色程序并链接着色器

		ID = glCreateProgram();
		glAttachShader(ID, vertexShader);
		glAttachShader(ID, fragShader);
		glLinkProgram(ID);
		//检查是否链接成功
		glGetProgramiv(ID, GL_LINK_STATUS, &success);
		if (!success) {
			glGetProgramInfoLog(ID, 512, NULL, infoLog);
		}
		//链接成功后删除着色器
		glDeleteShader(vertexShader);
		glDeleteShader(fragShader);

#pragma endregion
	};
	//启用这个shader程序
	void Use() {
		glUseProgram(ID);
	}

	//设置uniform值
	void SetBool(const std::string &name, bool value) const {
		glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
	}
	void SetInt(const std::string &name, int value) const {
		glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
	}
	void SetFloat(const std::string &name, float value) const {
		glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
	}
	void SetMat4(const std::string &name, glm::mat4 value)const {
		glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()),1,GL_FALSE, glm::value_ptr(value));
	}
};
#endif 

纹理

读取图片数据

/*使用图像加载库 stb_image.h*/
stbi_set_flip_vertically_on_load(true);//转置图像y轴
//ps:可以用"\\"也可以用"/"
data = stbi_load("D:\\MyOpenGLLib\\Task\\chapter3\\awesomeface.png", &width, &height, &nrChannels, 0);
...
//使用后释放
stbi_image_free(data);

生成并设置纹理

unsigned int texture1, texture2;
	//生成并绑定纹理对象
	glGenTextures(1, &texture1);
	glBindTexture(GL_TEXTURE_2D, texture1);
	//配置纹理环绕模式模式 最终我们的纹理对象是绑定到GL_TEXTURE_2D的
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	//配置纹理过滤模式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	int width, height, nrChannels;

	//读取图片资源
	unsigned char *data = stbi_load("D:\\xax\\xaaax..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 << "Failed to load texture" << std::endl;
	}
	//释放图片资源
	stbi_image_free(data);

	glGenTextures(1, &texture2);
	glBindTexture(GL_TEXTURE_2D, texture2);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	stbi_set_flip_vertically_on_load(true);
	data = stbi_load("D:\\xx\\xxxx.png", &width, &height, &nrChannels, 0);
	if (data)
	{
		//第一个GL_RGB是GPU内部使用的格式,第二个GL_RGBA 是导入图使用的格式
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load texture2" << std::endl;
	}

传输和使用纹理

纹理-->纹理单元-->uniform sampler2D xxx;

纹理单元

//告知shader中的每个采样器选取哪个纹理单元
ourShader.SetInt("texture1", 0);
ourShader.SetInt("texture2", 1);


//每张纹理绑定至对应的纹理单元 (先激活指定纹理单元再绑定)GL_TEXTURE0~15
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);

着色器中使用纹理

...
//定义
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
    //采样 uv坐标应通过顶点属性获取
   FragColor = mix(texture(texture1, texCoord), texture(texture2, texCoord), 0.5);
   
}
...

空间坐标转换

传输矩阵至着色器

//使用数学库 glm.h
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
...

glm::mat4 transform;
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));
//着色器中的定义
uniform mat4 transform;

 

对象空间--[Model matrix] ->世界空间

...模型矩阵前三行为对象空间三条轴在世界空间的表示向量,第四列为世界中心和对象中心的距离  

0001

可以把旋转应用在这里

世界空间--[View matrix]->观察空间

即转换至摄像机的空间 

这里用的lookat,构成其实和模型矩阵方法一样,三个轴向量+原点偏移

#ifndef CAMERA_H
#define CAMERA_H

#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>


enum Camera_Movement {
	FORWARD,
	BACKWARD,
	RIGHT,
	LEFT
};

// 默认相机属性
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f;

class Camera
{
public:
	glm::vec3 worldUp;
	//位置属性
	glm::vec3 camPos;
	glm::vec3 camFront;
	glm::vec3 camUp;
	glm::vec3 camRight;
	//欧拉角
	float Yaw;
	float Pitch;

	//配置参数
	float MovementSpeed;
	float MouseSensitivity;
	float Zoom;

	Camera(glm::vec3 position = glm::vec3(0.f, 0.f, 0.f), glm::vec3 up = glm::vec3(0.f, 1.f, 0.f)) :camFront(glm::vec3(0.f, 0.f, -1.f)),MovementSpeed(SPEED),Yaw(YAW),Pitch(PITCH),MouseSensitivity(SENSITIVITY),Zoom(ZOOM) {
		camPos = position;
		worldUp = up;
		RecalculateCameraVector();
	}

	//获取view矩阵
	glm::mat4 GetViewMatrix() {
		return glm::lookAt(camPos, camPos + camFront, camUp);
	}
	//检测输入
	void ProcessKeyboard(Camera_Movement direction,float deltaTime) {

		float velocity = deltaTime*MovementSpeed;
		switch (direction)
		{
			case FORWARD: 
				camPos += camFront*velocity;
				break;
			case BACKWARD:
				camPos -= camFront*velocity;
				break;
			case LEFT:
				camPos -= camRight*velocity;
				break;
			case RIGHT:
				camPos += camRight*velocity;
				break;
		}
	}
	void ProcessMouseMovement(float xoffset, float yoffset) {
		Yaw += xoffset*MouseSensitivity;
		Pitch -= yoffset*MouseSensitivity;
		if (Pitch > 89.0f)
			Pitch = 89.0f;
		if (Pitch < -89.0f)
			Pitch = -89.0f;
		RecalculateCameraVector();
	}

private:
	//根据欧拉角计算前向,再推出右向和上向
	void RecalculateCameraVector() {
		glm::vec3 front;
		front.x = glm::cos(glm::radians(Yaw))*glm::cos(glm::radians(Pitch));
		front.y = glm::sin(glm::radians(Pitch));
		front.z= glm::cos(glm::radians(Pitch))*glm::sin(glm::radians(Yaw));
		camFront = glm::normalize(front);
		camRight = glm::normalize(glm::cross(camFront, worldUp));
		camUp = glm::normalize(glm::cross(camRight, camFront));

	}
};

#endif

观察空间--[Projection matrix]->裁减空间

//投射投影
projection = glm::perspective(glm::radians(fov), width / height, near, far);
//正交投影
projection=glm::ortho(left, right, top, near , bottom , far);

裁减空间-[齐次除法]-->标准化设备坐标(NDC)

这一步会在每一个顶点着色器运行的最后被自动执行。

NDC--[根据视口viewpoirt]->屏幕空间-->片段

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值