Aquacolor

Aquacolor



LearningOpenGL【6】

Gumdrop · 2025-08-30 · 28浏览 · 未分类



直接上代码然后作检讨。

#define _CRT_SECURE_NO_WARNINGS

#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include<iostream>
#include<sstream>
#include<fstream>

#define STB_IMAGE_IMPLEMENTATION
#include<stb_image.h>

void processInput(GLFWwindow*);
void sourceInput(unsigned int& vertexShader, unsigned int& fragmentShader, unsigned int& shaderProgram, const char* vertexShaderPath, const char* fragmentShaderPath);

int main() {
	stbi_set_flip_vertically_on_load(true);

	/// <summary>
	/// Part 1: Initialize and configure GLFW
	/// </summary>
	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, 800, "Learn", NULL, NULL);
	if (window == NULL) {
		std::cerr << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cerr << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	/// <summary>
	/// Part 2: Set up vertex data (and buffer(s)) and configure vertex attributes
	/// </summary>
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	float vertices[] = {
		-0.5f, -0.5f, 0.0f, 1.0f,0.0f,0.0f, 0.0f, 0.0f,
		0.5f, -0.5f, 0.0f, 1.0f,1.0f,0.0f, 1.0f, 0.0f,
		0.5f, 0.5f, 0.0f, 0.0f,0.0f,1.0f, 1.0f, 1.0f,
		-0.5f, 0.5f, 0.0f, 0.0f,0.5f,0.0f, 0.0f, 1.0f
	};
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);

	unsigned int indices[] = {
		0,1,2,
		2,3,0
	};
	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	glBindVertexArray(0);

	/// <summary>
	/// Part 3: Build and compile our shader program
	/// </summary>

	unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	unsigned int shaderProgram = glCreateProgram();
	sourceInput(vertexShader, fragmentShader, shaderProgram, "VertexShader.glsl", "FragmentShader.glsl");

	unsigned int texture0;
	unsigned int texture1;
	glGenTextures(1, &texture0);
	glGenTextures(1, &texture1);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, texture0);
	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_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	{
		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::cerr << "Failed to load texture" << std::endl;
		}
	}
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, texture1);
	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_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	{
		int width, height, nrChannels;
		unsigned char* data = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
		if (data) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		else {
			std::cerr << "Failed to load texture" << std::endl;
		}
	}

	/// <summary>
	/// Part 4: Render loop 
	/// </summary>
	glfwSetFramebufferSizeCallback(window,
		[](GLFWwindow* window, int width, int height) {glViewport(0, 0, width, height); });
	while (!glfwWindowShouldClose(window))
	{
		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glUseProgram(shaderProgram);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture0);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture1);

		glUniform1i(glGetUniformLocation(shaderProgram, "texture0"), 0);
		glUniform1i(glGetUniformLocation(shaderProgram, "texture1"), 1);
		glBindVertexArray(VAO);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}
}

void processInput(GLFWwindow* window) {
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, true);
	}
}

void sourceInput(unsigned int& vertexShader, unsigned int& fragmentShader, unsigned int& shaderProgram, const char* vertexShaderPath, const char* fragmentShaderPath)
{
	std::ifstream vertexShaderFile;
	std::ifstream fragmentShaderFile;
	std::string vertexShaderStr;
	std::string fragmentShaderStr;
	vertexShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	fragmentShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	try
	{
		std::stringstream vertexShaderStringStream;
		std::stringstream fragmentShaderStringStream;
		vertexShaderFile.open(vertexShaderPath);
		fragmentShaderFile.open(fragmentShaderPath);
		vertexShaderStringStream << vertexShaderFile.rdbuf();
		fragmentShaderStringStream << fragmentShaderFile.rdbuf();
		vertexShaderFile.close();
		fragmentShaderFile.close();
		vertexShaderStr = vertexShaderStringStream.str();
		fragmentShaderStr = fragmentShaderStringStream.str();
	}
	catch (const std::exception&)
	{
		std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
	}
	const char* vertexShaderSource = vertexShaderStr.c_str();
	const char* fragmentShaderSource = fragmentShaderStr.c_str();
	std::cout << vertexShaderSource << std::endl << std::endl;
	std::cout << fragmentShaderSource << std::endl << std::endl;
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(vertexShader);
	{
		int  success;
		char infoLog[512];
		glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
		}
	}
	glCompileShader(fragmentShader);
	{
		int  success;
		char infoLog[512];
		glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
		}
	}
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	{
		int success;
		char infoLog[512];
		glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
		if (!success) {
			glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
			std::cerr << "ERROR::PROGRAM::LINK_FAILED\n" << infoLog << std::endl;
		}
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

}
//vertexshader.glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
  
out vec4 vertexColor;
out vec2 texCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = vec4(aColor, 1.0);
    texCoord = aTexCoord;
}

//fragmentshader.glsl
#version 330 core  
in vec4 vertexColor;
in vec2 texCoord;

out vec4 FragColor;

uniform sampler2D texture0;
uniform sampler2D texture1;

void main()
{
    FragColor = mix(texture(texture0, texCoord),texture(texture1,texCoord),0.2)*vertexColor;
}

minifying, magnifying, downscaled, supersampling, texels, sampler

纹理的使用方式和其他对象有所区别:

unsigned int texture;
glGenTexture(1,&texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texture);
glTexParameteri(...);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_RGB,GL_UNSIGNED_BYTE,data);
glGenerateMipmap(GL_TEXTURE_2D);

此前已经学过的用一个宏管理的:VBO、EBO、shader。

不用宏管理的:VAO、program。

纹理使用两个宏管理,一个是GL_TEXTURE_xD,另一个是GL_TEXTUREx,当glActiveTexture()将一个宏设为活动时,所有使用GL_TEXTURE_2D修改的属性都属于那个被绑定的宏。这相当于每个纹理都与一个宏GL_TEXTUREx关联。这个宏称作texture units

生成、active、绑定、配置

纹理坐标

值取从0到1,有1、2、3D纹理,分别具有坐标轴s、t、r,在设置参数时使用GL_TEXTURE_WRAP_S+GL_REPEAT设置超出0到1的纹理坐标的处理方式。

降采样和过采样

采样是在纹理上给fragment片段采集颜色数据。

当多个片段采集一个纹理像素点texel的情况下,称为降采样,t/f<1(或者在原本完美贴合的情况下放大纹理,magnifying)

当一个片段需要采集多个texel的情况下,称为过采样,t/f>1(缩小纹理,downscaling,minifying,supersampling)

降采样其实并不需要特殊处理,可以选择GL_NEARESTGL_LINEAR规则采样插值。

过采样情况可能会出现的较多并且会使用mipmap技术、之上的各项异性过滤技术等。

过采样容易出现的原因是远处三角形在rasterization阶段形成的片段数会很少,于是相比纹理大小形成明显区别。

(低频采样方式(少片段)采集高频信号(多texel)会导致严重走样)

如果使用mipmap进行插值将会能够选择远近两个mipmap的选择规则,但是两mipmap之间默认线性插值。

使用GL_TEXTURE_MIN_FILTERGL_TEXTURE_MAG_FILTER宏指定修改的参数。

stb头文件

这是个C风格的all in one header工具库。使用细节很多所以不考虑。

GLSL使用纹理

//vertexshader.glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
  
out vec4 vertexColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = vec4(aColor, 1.0);
    TexCoord = aTexCoord;
}

//fragmentshader.glsl
#version 330 core  
in vec4 vertexColor;
in vec2 TexCoord;

out vec4 FragColor;

uniform sampler2D Texture1;

void main()
{
    FragColor = texture(Texture1, TexCoord);
}

多了一个VAA自然要在vertexshader中体现。(layout in、out)

在fragmentshader中使用纹理需要一个uniform的sampler2D对象和texture()函数。

该sampler2D对象不一定需要手动管理,在只有一个纹理时默认为GL_TEXTURE0

当需要修改它对应的纹理时,直接将数字赋给它,比如要设置为纹理1就赋值1。

//render loop中
glUniformi(glGetUniformLocation(shaderProgram,"Texture1"),1);

颜色计算和纹理叠加

RGB颜色的叠加,其计算方式基本是用乘号,后面的各种颜色叠加都是用该法。但是为了特殊效果可以用其他方式。

纹理叠加用mix,看着像计算了透明但事实上没有计算!alpha测试在下一个环节的shader里。

检讨

用接近4h的时间,但事实上在学的时间应该就一个多小时,其他时间都在处理两个纹理报错的情况,即使用copilot也没能排除。

然后发现第一个问题是由于在VBO中添加了纹理坐标但是没有enable纹理坐标的VAA;第二个是把材质名称后缀打错了。

首先是两个重要事实:opengl的debug真的很困难,纯靠程序员经验;ai在低级错误上往往比较难排查,使用ai的方法还是需要学习的。

其次是自我批评:感觉找不到错就及时止损过一段时间再回来找,以及写代码要动脑子。

(可能要想点办法能主动动脑) 2025-08-29T17:59:45.png



©

comment 评论区

添加新评论

face表情



  • ©2026 bilibili.com

textsms
内容不能为空
昵称不能为空
email
邮件地址格式错误
web
beach_access
验证码不能为空
keyboard发表评论


star_outline 咱快来抢个沙发吧!




©2026 Aquacolor

Theme Romanticism2.2 by Akashi
Powered by Typecho