OpenGL材质系统和贴图纹理

news2025/1/8 2:28:19

        上一篇文章当中笔者为大家介绍了风氏光照模型,相信大家也发现了光照着色器当中有设置有很多控制光照强度的参数,而所谓的材质系统就是我们可以人为的去调节这些参数,让一个物体的反光效果能够更加接近我们现实生活当中的一些物体。

材质系统

        当描述一个表面时,我们可以分别为三个光照分量定义一个材质颜色(Material Color):环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting)。通过为每个分量指定一个颜色,我们就能够对表面的颜色输出有细粒度的控制了。现在,我们再添加一个反光度(Shininess)分量,结合上述的三个颜色,我们就有了全部所需的材质属性了

#version 450 core
struct Material {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
}; 

uniform Material material;

        如你所见,我们为风氏光照模型的每个分量都定义一个颜色向量。ambient材质向量定义了在环境光照下这个表面反射的是什么颜色,通常与表面的颜色相同。diffuse材质向量定义了在漫反射光照下表面的颜色。漫反射颜色(和环境光照一样)也被设置为我们期望的物体颜色。specular材质向量设置的是表面上镜面高光的颜色(或者甚至可能反映一个特定表面的颜色)。最后,shininess影响镜面高光的散射/半径。

        使用材质

         我们在片段着色器中创建了一个材质结构体的uniform,所以下面我们希望修改一下光照的计算来遵从新的材质属性。由于所有材质变量都储存在一个结构体中,我们可以从uniform变量material中访问它们:

void main()
{    
    // 环境光
    vec3 ambient = lightColor * material.ambient;

    // 漫反射 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = lightColor * (diff * material.diffuse);

    // 镜面光
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = lightColor * (spec * material.specular);  

    vec3 result = ambient + diffuse + specular;
    FragColor = vec4(result, 1.0);
}

        我们可以看到,和之前光照模型几乎没有什么不同的,我们只是通过结构体的方式来访问这些向量,这样做的好处是我们可以人为的控制这些材质的向量了。

lightingShader.setVec3("material.ambient",  1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.diffuse",  1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
lightingShader.setFloat("material.shininess", 32.0f);

不过到现在还是有一个问题,那就是整个光照模型看上去会特别的亮,这是因为我们还没有设置照射光的属性,我们需要调整光的亮度。

struct Light {
    vec3 position;

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

uniform Light light;

片段着色器修改成如下的代码

void main()
{    
    // 环境光
    vec3 ambient = light.ambient * material.ambient;

    // 漫反射 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * (diff * material.diffuse);

    // 镜面光
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = light.specular * (spec * material.specular);  

    vec3 result = ambient + diffuse + specular;
    FragColor = vec4(result, 1.0);
}

设置光照的属性

lightingShader.setVec3("light.ambient",  0.2f, 0.2f, 0.2f);
lightingShader.setVec3("light.diffuse",  0.5f, 0.5f, 0.5f); // 将光照调暗了一些以搭配场景
lightingShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f); 

好的到了这里,我们材质系统就为大家介绍到这里了,不过通过上面的代码我们知道,这个材质系统影响的是整个立方体的材质状况,但我们也知道现实生活当中这种单一材质物体是很少见的,一般我们看到的物体都是好几种材质组合而来的。要想表现出这种复杂的纹理,我们组好要能控制每个像素颜色,那怎样才能做到这种事了?可能有的朋友已经想到了,那就是使用之前的纹理,就可以控制片段着色器当中的像素颜色了!

纹理贴图

        我们使用下面两个纹理图片来制作一个带有贴边的木箱子。

可能有的朋友想问,为什么铁框的贴图的中间的部分是黑色的,其实这个目的就在于减小木制材料部分中间的反光程度。整个光照着色器代码如下:

#type vertex
#version 450 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
layout(location = 2) in vec3 normal;
layout(location = 3) in vec2 texCoord;

layout(location = 0) out vec4 v_Position;
layout(location = 1) out vec3 v_Color;
layout(location = 2) out vec3 v_Normal;
layout(location = 3) out vec2 v_texCoord;

uniform mat4 u_ViewProject;

void main(){
    gl_Position = u_ViewProject * position;
    v_Position = position;
    v_Color = color;
    v_Normal = normal;
    v_texCoord = texCoord;
}


#type fragment
#version 450 core

layout(location = 0) out vec4 o_Color;

layout(location = 0) in vec4 v_Position;
layout(location = 1) in vec3 v_Color;
layout(location = 2) in vec3 v_Normal;
layout(location = 3) in vec2 v_texCoord;

struct Material {
    int diffuse;
    int specular;
    int shininess;
};

struct Light{
    vec3 position;

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

uniform sampler2D u_Textures[2];

uniform vec3 u_ViewPos;
uniform Material material;
uniform Light light;

void main(){
    vec3 v_position3 = vec3(v_Position.x,v_Position.y,v_Position.z);
    //环境亮度
    vec3 ambient = light.ambient * texture(u_Textures[material.diffuse],v_texCoord).rgb;
    //漫反射亮度
    vec3 vertex2light = normalize(light.position - v_position3);
    float diff = max(dot(vertex2light,normalize(v_Normal)),0.0f);
    vec3 diffuse = light.diffuse * diff * texture(u_Textures[material.diffuse],v_texCoord).rgb;

    //镜面反射
    vec3 viewDir = normalize(u_ViewPos - v_position3);
    vec3 reflectDir = reflect(-vertex2light,normalize(v_Normal));
    float spec = pow(max(dot(viewDir,reflectDir),0.0f),material.shininess);
    vec3 specular = light.specular * spec * texture(u_Textures[material.specular],v_texCoord).rgb;

    vec3 result = ambient + diffuse + specular;
    o_Color = vec4(result,1.0f);
}

这样我们就可得到一个边框反光的木箱子了,这一章总体是比较简单的,主函数代码贴在下面,如果对主函数当中的一些变量不清楚的话可以到这个网站获取此案例的所有的代码,包括纹理贴图:https://gitee.com/HonyOrange_227/opengl-light-lab

我们来看一下最后的效果

此文章到这里就结束了,希望能帮助到大家

#include<glad/glad.h>
#include<GLFW/glfw3.h>

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

#include"Shader.h"
#include"Texture.h"
#include"Camera.h"

static Camera camera(glm::vec3(0.0f, 0.0f, 5.0f));
static bool run = true;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);

int main() {
	glfwInit();

	GLFWwindow* window = glfwCreateWindow(640, 480, "Triangles", NULL, NULL);

	
	glfwMakeContextCurrent(window);
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);

	glfwSetKeyCallback(window, key_callback);
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
	//需要初始化GLAD
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	float lightVertexes[] = {
		//front surface
		-0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//0
		0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//1
		0.5f,	0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//2
		-0.5f,	0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//3

		//back surface
		-0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,	//4
		0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,	//5
		0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,	//6
		-0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,	//7

		//up surface
		-0.5f,	0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,		//8
		0.5f,	0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,		//9
		0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,		//10
		-0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,		//11

		//down surface
		-0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,		//12
		0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,		//13
		0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,		//14
		-0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,		//15

		//left surface
		-0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,	//16
		-0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//17
		-0.5f,	0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//18
		-0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,	//19

		//right surface
		0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f,	//20
		0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//21
		0.5f,	0.5f,	0.5f,	1.0f,	1.0f,1.0f,1.0f,	//22
		0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,1.0f,1.0f	//23
	};					

	float vertexes[] = {
		//front surface
		-0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,1.0f,		0.0f,0.0f,//0
		0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,1.0f,		1.0f,0.0f,//1
		0.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,1.0f,		1.0f,1.0f,//2
		-0.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,1.0f,		0.0f,1.0f,//3

		//back surface
		-0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,-1.0f,	0.0f,0.0f,//4
		0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,-1.0f,	1.0f,0.0f,//5
		0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,-1.0f,	1.0f,1.0f,//6
		-0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,0.0f,-1.0f,	0.0f,1.0f,//7

		//up surface
		-0.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,1.0f,0.0f,		0.0f,0.0f,//8
		0.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,1.0f,0.0f,		1.0f,0.0f,//9
		0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,1.0f,0.0f,		1.0f,1.0f,//10
		-0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,1.0f,0.0f,		0.0f,1.0f,//11

		//down surface
		-0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,-1.0f,0.0f,	0.0f,0.0f,//12
		0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,-1.0f,0.0f,	1.0f,0.0f,//13
		0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,-1.0f,0.0f,	1.0f,1.0f,//14
		-0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		0.0f,-1.0f,0.0f,	0.0f,1.0f,//15

		//left surface
		-0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		-1.0f,0.0f,0.0f,	0.0f,0.0f,//16
		-0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		-1.0f,0.0f,0.0f,	1.0f,0.0f,//17
		-0.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		-1.0f,0.0f,0.0f,	1.0f,1.0f,//18
		-0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		-1.0f,0.0f,0.0f,	0.0f,1.0f,//19

		//right surface
		0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		1.0f,0.0f,0.0f,		0.0f,0.0f,//20
		0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		1.0f,0.0f,0.0f,		1.0f,0.0f,//21
		0.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.5f,0.2f,		1.0f,0.0f,0.0f,		1.0f,1.0f,//22
		0.5f,	0.5f,	-0.5f,	1.0f,	1.0f,0.5f,0.2f,		1.0f,0.0f,0.0f,		0.0f,1.0f,//23
	};

	glm::vec4 originVertexes[24] = {
		{-0.5f,	-0.5f,	0.5f,	1.0f},
		{0.5f,	-0.5f,	0.5f,	1.0f},
		{0.5f,	0.5f,	0.5f,	1.0f},
		{-0.5f,	0.5f,	0.5f,	1.0f},

		//back surface
		{-0.5f,	-0.5f,	-0.5f,	1.0f},
		{0.5f,	-0.5f,	-0.5f,	1.0f},
		{0.5f,	0.5f,	-0.5f,	1.0f},
		{-0.5f,	0.5f,	-0.5f,	1.0f},

		//up surface
		{-0.5f,	0.5f,	0.5f,	1.0f},
		{0.5f,	0.5f,	0.5f,	1.0f},
		{0.5f,	0.5f,	-0.5f,	1.0f},
		{-0.5f,	0.5f,	-0.5f,	1.0f},

		//down surface
		{-0.5f,	-0.5f,	0.5f,	1.0f},
		{0.5f,	-0.5f,	0.5f,	1.0f},
		{0.5f,	-0.5f,	-0.5f,	1.0f},
		{-0.5f,	-0.5f,	-0.5f,	1.0f},

		//left surface
		{-0.5f,	-0.5f,	-0.5f,	1.0f},
		{-0.5f,	-0.5f,	0.5f,	1.0f},
		{-0.5f,	0.5f,	0.5f,	1.0f} ,
		{-0.5f,	0.5f,	-0.5f,	1.0f},

		//right surface
		{0.5f,	-0.5f,	-0.5f,	1.0f},
		{0.5f,	-0.5f,	0.5f,	1.0f},
		{0.5f,	0.5f,	0.5f,	1.0f},
		{0.5f,	0.5f,	-0.5f,	1.0f}
	};

	unsigned int indexes[] = {
		//front surface
		0,1,2,
		2,3,0,

		//back surface
		4,5,6,
		6,7,4,

		//up surface
		8,9,10,
		10,11,8,

		//down surface
		12,13,14,
		14,15,12,

		//left surface
		16,17,18,
		18,19,16,

		//right surface
		20,21,22,
		22,23,20
	};

	glEnable(GL_DEPTH_TEST);
	unsigned int buffer = 0, lightbuffer = 0,vertexArray = 0, lightVertexArray = 0,indexBuffer = 0;

	glCreateVertexArrays(1, &vertexArray);
	glBindVertexArray(vertexArray);

	glCreateBuffers(1, &buffer);
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 12 * sizeof(float), NULL);

	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 12 * sizeof(float), (const void*)(4 * sizeof(float)));

	glEnableVertexAttribArray(2);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 12 * sizeof(float), (const void*)(7 * sizeof(float)));

	glEnableVertexAttribArray(3);
	glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 12 * sizeof(float), (const void*)(10 * sizeof(float)));

	glCreateVertexArrays(1, &lightVertexArray);
	glBindVertexArray(lightVertexArray);

	glCreateBuffers(1, &lightbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, lightbuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(lightVertexes), lightVertexes, GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), NULL);

	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void*)(4 * sizeof(float)));
	
	glCreateBuffers(1, &indexBuffer);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);

	Shader* pShader = new Shader("assets/shaders/TextureShader.glsl");
	Shader* pLightShader = new Shader("assets/shaders/LightShader.glsl");
	Texture* pTextureWood = new Texture("assets/Textures/container2.png");
	Texture* pTextureSteel = new Texture("assets/Textures/container2_specular.png");

	glm::mat4 transform = glm::translate(glm::mat4(1.0), glm::vec3(0.3f, 1.5f, 1.5f));
	glm::vec4 orginCenter(0.0f, 0.0f, 0.0f, 1.0f);

	int textureIndexes[2] = { 0,1 };
	while (!glfwWindowShouldClose(window) && run) {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		glm::mat4 project = glm::perspective(glm::radians(camera.GetCameraZoom()), 640.0f / 480.0f, 0.1f, 100.0f);
		glm::mat4 view = camera.GetViewMatrix();
		glm::mat4 ViewProject = project * view;
		
		for (int i = 0; i < 24; i++) {
			glm::vec4 originPoint = originVertexes[i];
			originPoint = transform * glm::scale(glm::mat4(1.0f), glm::vec3(0.5f, 0.5f, 0.5f)) * originPoint;
			lightVertexes[i * 7] = originPoint.x;
			lightVertexes[i * 7 + 1] = originPoint.y;
			lightVertexes[i * 7 + 2] = originPoint.z;
			lightVertexes[i * 7 + 3] = originPoint.w;
		}

		glBindBuffer(GL_ARRAY_BUFFER, lightbuffer);
		glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(lightVertexes), lightVertexes);

		pShader->Bind();
		pShader->UploadUniformat4("u_ViewProject", ViewProject);

		glBindVertexArray(lightVertexArray);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

		glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL);

		glm::vec4 centerMove = transform * orginCenter;

		for (int i = 0; i < 24; i++) {
			glm::vec4 originPoint = originVertexes[i];
			originPoint = glm::scale(glm::mat4(1.0f), glm::vec3(1.5f, 1.5f, 1.5f)) * originPoint;
			vertexes[i * 12] = originPoint.x;
			vertexes[i * 12 + 1] = originPoint.y;
			vertexes[i * 12 + 2] = originPoint.z;
			vertexes[i * 12 + 3] = originPoint.w;
		}

		glBindBuffer(GL_ARRAY_BUFFER, buffer);
		glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexes), vertexes);

		pTextureWood->Bind(0);
		pTextureSteel->Bind(1);
		pLightShader->Bind();
		pLightShader->UploadUniformat4("u_ViewProject", ViewProject);
		pLightShader->UploadUnifromFloat3("u_ViewPos",camera.GetPosition());

		pLightShader->UploadUnifromFloat3("light.position", { centerMove.x, centerMove.y, centerMove.z });
		pLightShader->UploadUnifromFloat3("light.ambient", { 0.2f,0.2f,0.2f });
		pLightShader->UploadUnifromFloat3("light.diffuse", { 0.5f,0.5f,0.5f });
		pLightShader->UploadUnifromFloat3("light.specular", { 1.0f,1.0f,1.0f });

		pLightShader->UploadUniform1i("material.diffuse", 0);
		pLightShader->UploadUniform1i("material.specular", 1);
		pLightShader->UploadUniform1i("material.shininess", 64);

		pLightShader->UplaodUniform1iv("u_Textures", 2, textureIndexes);

		glBindVertexArray(vertexArray);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

		glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL);

		glfwSwapBuffers(window);

		glfwPollEvents();
	}

	delete pShader;
	delete pLightShader;

	glfwDestroyWindow(window);

	glfwTerminate();
}

void mouse_callback(GLFWwindow* window, double xposIn, double yposIn) {
	static float lastX = 320.0f, lastY = 240.0f;
	static bool firstMouse = true;

	float xpos = static_cast<float>(xposIn);
	float ypos = static_cast<float>(yposIn);

	if (firstMouse) {
		lastX = xpos;
		lastY = ypos;
		firstMouse = false;
	}

	float xoffset = xpos - lastX;
	float yoffset = lastY - ypos;

	lastX = xpos, lastY = ypos;

	camera.ProcessMouseMovement(xoffset, yoffset);
}

void scroll_callback(GLFWwindow* window, double xoffsetIn, double yoffsetIn) {
	camera.ProcessMouseScroll(static_cast<float>(yoffsetIn));
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		run = false;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2272363.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【mybatis】Mybatis整体架构解析

从本篇开始我们开始学习mybatis的系列源码&#xff0c;主要的主题可能就是四个方面 从整体把握mybatis系统架构通过一个查询SQL 源码解析核心流程mybatis的缓存机制-源码级别mybatis的插件机制-源码级别spring是如何整合的mybatis框架的 1.整体架构 上述是mybatis的源码&…

stm32 智能语音电梯系统

做了个stm32智能语音控制的电梯模型&#xff0c;总结一下功能&#xff0c;源码用ST的HAL库写的&#xff0c;整体流程分明。 实物图 这个是整个板子的图片&#xff0c;逻辑其实并不复杂&#xff0c;只是功能比较多&#xff0c;在我看来都是一些冗余的功能&#xff0c;但也可能是…

Git 部署

参考&#xff1a;手把手教你入门Git — Git使用指南&#xff08;Linux&#xff09; 需要说明的是&#xff1a; 1、服务器linux系统中一般使用master分支&#xff0c;但github现在流行的是main分支&#xff1b; 解决方案是修改master分支位main分支 git branch -m master mai…

【业务场景】sql server从Windows迁移到Linux

目录 1.背景 2.Linux安装sql server 3.服务器不开端口的问题 4.数据库导入导出问题 1.背景 博主在24年年底接手运维了一个政府的老系统&#xff0c;整个应用和数据库单点部署在一台Windows Server服务器上&#xff0c;数据库选型是经典的老项目标配——sql server。随着近…

《Vue3实战教程》35:Vue3测试

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 测试​ 为什么需要测试​ 自动化测试能够预防无意引入的 bug&#xff0c;并鼓励开发者将应用分解为可测试、可维护的函数、模块、类和组件。这能够帮助你和你的团队更快速、自信地构建复杂的 Vue 应用。与任何应用一…

字玩FontPlayer开发笔记6 Tauri2设置菜单

字玩FontPlayer开发笔记6 Tauri2设置菜单 字玩FontPlayer是笔者开源的一款字体设计工具&#xff0c;使用Vue3 ElementUI开发&#xff0c;源代码&#xff1a; github: https://github.com/HiToysMaker/fontplayer gitee: https://gitee.com/toysmaker/fontplayer 笔记 字玩目…

我用AI学Android Jetpack Compose之开篇

最近突发奇想&#xff0c;想学一下Jetpack Compose&#xff0c;打算用Ai学&#xff0c;学最新的技术应该要到官网学&#xff0c;不过Compose已经出来一段时间了&#xff0c;Ai肯定学过了&#xff0c;用Ai来学&#xff0c;应该问题不大&#xff0c;学习过程记录下来&#xff0c;…

Zookeeper是如何保证事务的顺序一致性的?

大家好&#xff0c;我是锋哥。今天分享关于【Zookeeper是如何保证事务的顺序一致性的?】面试题。希望对大家有帮助&#xff1b; Zookeeper是如何保证事务的顺序一致性的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper 通过多个机制来保证事务的顺序一…

机器人手眼标定

机器人手眼标定 一、机器人手眼标定1. 眼在手上标定基本原理2. 眼在手外标定基本原理 二、眼在手外标定实验三、标定精度分析 一、机器人手眼标定 要实现由图像目标点到实际物体上抓取点之间的坐标转换&#xff0c;就必须拥有准确的相机内外参信息。其中内参是相机内部的基本参…

数据挖掘——聚类

数据挖掘——聚类 聚类K-meansKNN VS K-meansK-Nearest Neighbors (KNN)K-means K中心算法PAM算法 K-modes算法——解决数据敏感的问题KMeans算法 ——解决初始点选择问题K-中心点层次方法AGNES算法——最小距离单链接全链接平均链接 聚类评估K均值和K中心点的优缺点层次化聚类…

web实操9——session

概念 数据保存在服务器HttpSession对象里。 session也是域对象&#xff0c;有setAttribute和getAttribute方法 快速入门 代码 获取session和塞入数据&#xff1a; 获取session获取数据&#xff1a; 请求存储&#xff1a; 请求获取&#xff1a; 数据正常打印&#xff1a…

GPT系统重大升级,开创国内先河:o1支持图片识别功能正式上线

文章目录 零、前言一、授权码登录体验优化&#xff1a;一步直达聊天界面二、全新“项目”功能&#xff1a;让工作更有条理三、语音功能升级&#xff1a;全新交互体验四、o1支持图片识别五、总结 零、前言 我是虚竹哥&#xff0c;目标是带十万人玩转ChatGPT。 亲爱的用户&…

unity 播放 序列帧图片 动画

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、方法一&#xff1a;代码控制播放序列帧1、设置图片属性2、创建Image组件3、简单的代码控制4、挂载代码并赋值 二、方法二&#xff1a;直接使用1.Image上添加…

VisionPro软件Image Stitch拼接算法

2D图像拼接的3种情景 1.一只相机取像位置固定&#xff0c;或者多只相机固定位置拍图&#xff0c;硬拷贝拼图&#xff0c;采用CopyRegion工具实现 2.一只或多只相机在多个位置拍照&#xff0c;相机视野互相重叠&#xff0c;基于Patmax特征定位后&#xff0c;无缝 拼图&#xff…

【大模型】7 天 AI 大模型学习

今天终于来到大模型学习的实战课了&#xff08;虽然前面跳了2天的课&#xff09;&#xff0c;今天我们会一起学习 Llama 模型的运行、部署、微调 ~ 一、Llama 介绍 Llama 模型官网&#xff1a;官网 Llama 论文&#xff1a;论文 Llama 代码&#xff1a;代码 理念&#xff1a;Th…

小程序学习08—— 系统参数获取和navBar组件样式动态设置

一 系统信息的概念 uni-app提供了异步(uni.getSystemInfo)和同步(uni.getSystemInfoSync)的2个API获取系统信息。 success 返回参数说明&#xff1a; 参数分类说明statusBarHeight手机状态栏的高度system操作系统名称及版本。。。 二 自定义navbar 2.1 获取系统参数 代码展示…

STM32的LED点亮教程:使用HAL库与Proteus仿真

学习目标&#xff1a;掌握使用STM32 HAL库点亮LED灯&#xff0c;并通过Proteus进行仿真验证&#xff01; 建立HAL库标准工程 1.新建工程文件夹 新建工程文件夹建议路径尽量为中文。建立文件夹的目的为了更好分类去管理项目工程中需要的各类工程文件。 首先需要在某个位置建立工…

密码学原理技术-第十一章-Hash Functions

文章目录 总结Why we need hash functionsDigital Signature with a Hash FunctionBasic Protocol for Digital Signatures with a Hash FunctionPrincipal input–output behavior of hash functions Security propertiesThe three security requirements of hash functionsWh…

【AI大模型系列】AI Agent与LangChain框架介绍(七)

目录 一、什么是AI Agent 二、什么是LangChain 三、LangChain的重要模块 3.1 Model I/O&#xff08;模块输入输出&#xff09; 3.2 Retrieval&#xff08;检索&#xff09; 3.3 Chains&#xff08;链式调用&#xff09; 3.4 Agents 3.5 Memory&#xff08;记忆&#xff…

RabbitMQ 架构介绍:深入理解与应用

RabbitMQ 是一个开源的消息代理&#xff08;Message Broker&#xff09;软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;&#xff0c;并提供了可靠的消息传递机制。RabbitMQ 广泛应用于分布式系统中&#xff0c;用于解耦系统组件、异步处理任务和实现消…