OpenGL_Learn08(坐标系统与3D空间)

目录

1. 概述

2. 局部空间

3. 世界空间

4. 观察空间

5. 剪裁空间

6. 初入3D

7. 3D旋转

8. 多个正方体

9. 观察视角


1. 概述

OpenGL希望在每次顶点着色器运行后,我们可见的所有顶点都为标准化设备坐标(Normalized Device Coordinate, NDC)。也就是说,每个顶点的xyz坐标都应该在-1.01.0之间,超出这个坐标范围的顶点都将不可见。我们通常会自己设定一个坐标的范围,之后再在顶点着色器中将这些坐标变换为标准化设备坐标。然后将这些标准化设备坐标传入光栅器(Rasterizer),将它们变换为屏幕上的二维坐标或像素。 

  • 局部空间(Local Space,或者称为物体空间(Object Space))
  • 世界空间(World Space)
  • 观察空间(View Space,或者称为视觉空间(Eye Space))
  • 裁剪空间(Clip Space)
  • 屏幕空间(Screen Space)

 为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型(Model)、观察(View)、投影(Projection)三个矩阵。我们的顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。

  1. 局部坐标是对象相对于局部原点的坐标,也是物体起始的坐标。
  2. 下一步是将局部坐标变换为世界空间坐标(平移+旋转),世界空间坐标是处于一个更大的空间范围的。这些坐标相对于世界的全局原点,它们会和其它物体一起相对于世界的原点进行摆放。
  3. 接下来我们将世界坐标变换为观察空间坐标,使得每个坐标都是从摄像机或者说观察者的角度进行观察的。
  4. 坐标到达观察空间之后,我们需要将其投影到裁剪坐标。裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上。
  5. 最后,我们将裁剪坐标变换为屏幕坐标,我们将使用一个叫做视口变换(Viewport Transform)的过程。视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。

2. 局部空间

局部空间是指物体所在的坐标空间,即对象最开始所在的地方。想象你在一个建模软件(比如说Blender)中创建了一个立方体。你创建的立方体的原点有可能位于(0, 0, 0),即便它有可能最后在程序中处于完全不同的位置。甚至有可能你创建的所有模型都以(0, 0, 0)为初始位置。

我们一直使用的那个箱子的顶点是被设定在-0.5到0.5的坐标范围中,(0, 0)是它的原点。这些都是局部坐标。

3. 世界空间

是指顶点相对于世界的坐标,世界空间也有一个中心。

4.  观察空间

观察空间经常被人们称之OpenGL的摄像机(Camera)(所以有时也称为摄像机空间(Camera Space)或视觉空间(Eye Space))。

观察空间是将世界空间坐标转化为用户视野前方的坐标而产生的结果。因此观察空间就是从摄像机的视角所观察到的空间。而这通常是由一系列的位移和旋转的组合来完成,平移/旋转场景从而使得特定的对象被变换到摄像机的前方。这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里,它被用来将世界坐标变换到观察空间。

观察空间中,原点是摄像机位置,+x轴指向右方,+y轴指向上方,+z轴指向后方。需要注意的是摄像机的前方是-z轴,因为unity中观察空间使用的是右手坐标系,模型空间和世界空间使用的是左手坐标系,这个只需要记住就行了。

在观察变换的时候,是把世界空间作为观察空间的子空间来变换的,因此,我们可以把对摄像机的 变换想象为对世界空间的变换。根据上图,世界空间的原点从观察空间的原点出发进行了(-30, -180, 0)的旋转,然后又进行了(-0.5,-5,-8.5)的移动。由此我们可以构建变换矩阵以求出A点在观察空间中的坐标。

也就是比如观察原点是A(3,-1,9)(在世界中的坐标) ,世界空间原点是B(0,0,0) 。那么A=BM ,M为变换矩阵。此时模型都需要与M相乘,得到位于观察点A的所看的顶点坐标。

5. 剪裁空间

裁剪空间也称作齐次裁剪空间,把顶点从观察空间转换到裁剪空间中的矩阵叫做裁剪矩阵,也被称作投影矩阵。

我们最终在摄像机中可以看到的区域是由视锥体决定的,视锥体就是我们可以看到的部分在计算机中的几何抽象,视锥体的边界以外的部分不渲染。视锥体由六个平面包围而成,这些平面被称作裁剪平面。

视锥体有两种投影类型:一种是正交投影(平行投影),一种是透视投影。

视锥体的六个平面当中,上下左右四个平面相当于望远镜的镜筒,而近裁剪平面和远裁剪平面则决定了你可以看到的最近和最远的距离 。

为了将顶点坐标从观察变换到裁剪空间,我们需要定义一个投影矩阵(Projection Matrix),它指定了一个范围的坐标,比如在每个维度上的-1000到1000。投影矩阵接着会将在这个指定的范围内的坐标变换为标准化设备坐标的范围(-1.0, 1.0)。所有在范围外的坐标不会被映射到在-1.0到1.0的范围之间,所以会被裁剪掉。在上面这个投影矩阵所指定的范围内,坐标(1250, 500, 750)将是不可见的,这是由于它的x坐标超出了范围,它被转化为一个大于1.0的标准化设备坐标,所以被裁剪掉了。

一旦所有顶点被变换到裁剪空间,最终的操作——透视除法(Perspective Division)将会执行,在这个过程中我们将位置向量的x,y,z分量分别除以向量的齐次w分量;透视除法是将4D裁剪空间坐标变换为3D标准化设备坐标的过程。这一步会在每一个顶点着色器运行的最后被自动执行。

上图所示,它的第一个参数定义了fov的值,它表示的是视野(Field of View),并且设置了观察空间的大小。如果想要一个真实的观察效果,它的值通常设置为45.0f,但想要一个末日风格的结果你可以将其设置一个更大的值。第二个参数设置了宽高比,由视口的宽除以高所得。第三和第四个参数设置了平截头体的平面。我们通常设置近距离为0.1f,而远距离设为100.0f。所有在近平面和远平面内且处于平截头体内的顶点都会被渲染。


当你把透视矩阵的 near 值设置太大时(如10.0f),OpenGL会将靠近摄像机的坐标(在0.0f和10.0f之间)都裁剪掉,这会导致一个你在游戏中很熟悉的视觉效果:在太过靠近一个物体的时候你的视线会直接穿过去。

透视投影和正射投影的区别 

6. 初入3D

 在开始进行3D绘图时,我们首先创建一个模型矩阵。这个模型矩阵包含了位移、缩放与旋转操作,它们会被应用到所有物体的顶点上,以变换它们到全局的世界空间。让我们变换一下我们的平面,将其绕着x轴旋转,使它看起来像放在地上一样。这个模型矩阵看起来是这样的:

glm::mat4 model;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));

通过将顶点坐标乘以这个模型矩阵,我们将该顶点坐标变换到世界坐标。

texture.fs

#version 330 core
out vec4 FragColor;in vec3 ourColor;
in vec2 TexCoord;uniform float mixValue;//texture sampler
uniform sampler2D textureone;
uniform sampler2D texturetwo;void main()
{FragColor = mix(texture(textureone,TexCoord),texture(texturetwo,TexCoord),mixValue);
}

texture.vs

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCorrd;out vec2 TexCoord;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position=projection*view*model*vec4(aPos,1.0);TexCoord=vec2(aTexCorrd.x,aTexCorrd.y);
}

main.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>#include <iostream>
#include "stb_image.h"
#include <cmath>
#include "shader.h"#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;float mixValue = 0.2f;int main() {//1.初始化配置glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
#endif // __APPLE__//2.gltf 窗口创建GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LeranOpenGL", NULL, NULL);if (window == NULL) {std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//3. 加载所有GL函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}Shader ourShader("./texture.vs", "./texture.fs");//4. 设置顶点数据float vertices[] = {// positions          // colors           // texture coords0.5f,  0.5f, 0.0f, 1.0f, 1.0f, // top right0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left-0.5f,  0.5f, 0.0f, 0.0f, 1.0f  // top left };unsigned int indices[] = {0, 1, 3, // first triangle1, 2, 3  // second triangle};unsigned int VBO, VAO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1,&EBO);//元素缓冲对象:Element Buffer Object,EBO glBindVertexArray(VAO);//复制顶点数组到缓冲区中供opengl使用glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//设置纹理属性指针glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);//加载和创建纹理unsigned int textureone,texturetwo;glGenTextures(1, &textureone);glBindTexture(GL_TEXTURE_2D, textureone);//设置纹理环绕参数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);//加载图像和生成mipmapsint width, height, nrChannels;stbi_set_flip_vertically_on_load(true);std::string filePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\container.jpg)";unsigned char* data = stbi_load(filePath.c_str(), &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, &texturetwo);glBindTexture(GL_TEXTURE_2D, texturetwo);//设置纹理环绕参数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);//加载图像和生成mipmapsfilePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\awesomeface.png)";unsigned char* data2 = stbi_load(filePath.c_str(), &width, &height, &nrChannels, 0);if (data2) {glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);glGenerateMipmap(GL_TEXTURE_2D);}else {std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data2);ourShader.use();glUniform1i(glGetUniformLocation(ourShader.ID, "textureone"), 0);//二选一ourShader.setInt("texturetwo", 1);//二选一//5. 循环渲染while (!glfwWindowShouldClose(window)) {processInput(window);// renderglClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);//绑定纹理glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, textureone);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texturetwo);ourShader.setFloat("mixValue", mixValue);// create transformationsglm::mat4 model = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix firstglm::mat4 view = glm::mat4(1.0f);glm::mat4 projection = glm::mat4(1.0f);model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));//注意,我们将矩阵向我们要进行移动场景的反方向移动view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);// retrieve the matrix uniform locationsunsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view");// pass them to the shaders (2 different ways)glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "projection"), 1, GL_FALSE, &projection[0][0]);ourShader.use();glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glfwTerminate();return 0;}// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {std::cout << "up" << std::endl;mixValue += 0.001f;if (mixValue >= 1.0f) {mixValue = 1.0f;}}if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS){std::cout << "down" << std::endl;mixValue -= 0.001f; // change this value accordingly (might be too slow or too fast based on system hardware)if (mixValue <= 0.0f)mixValue = 0.0f;}std::cout << "mixValue:" << mixValue <<std::endl;
}// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}

我们的顶点坐标已经使用模型、观察和投影矩阵进行变换了,最终的物体应该会:

  • 稍微向后倾斜至地板方向。
  • 离我们有一些距离。
  • 有透视效果(顶点越远,变得越小)。

7. 3D旋转

 改一下模型随着时间旋转

model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));

一个正方体6个面,一个面2个三角形,每个三角形3个顶点

glDrawArrays(GL_TRIANGLES, 0, 36);

顶点数据 

	//4. 设置顶点数据float vertices[] = {-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};

 OpenGL存储它的所有深度信息于一个Z缓冲(Z-buffer)中,也被称为深度缓冲(Depth Buffer)。GLFW会自动为你生成这样一个缓冲(就像它也有一个颜色缓冲来存储输出图像的颜色)。深度值存储在每个片段里面(作为片段的z值),当片段想要输出它的颜色时,OpenGL会将它的深度值和z缓冲进行比较,如果当前的片段在其它片段之后,它将会被丢弃,否则将会覆盖。这个过程称为深度测试(Depth Testing),它是由OpenGL自动完成的。

需要增加glEnable(GL_DEPTH_TEST);因为默认是关闭状态。

因为我们使用了深度测试,我们也想要在每次渲染迭代之前清除深度缓冲(否则前一帧的深度信息仍然保存在缓冲中)。就像清除颜色缓冲一样,我们可以通过在glClear函数中指定DEPTH_BUFFER_BIT位来清除深度缓冲:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

8. 多个正方体

#include <glad/glad.h>
#include <GLFW/glfw3.h>#include <iostream>
#include "stb_image.h"
#include <cmath>
#include "shader.h"#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;float mixValue = 0.2f;int main() {//1.初始化配置glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
#endif // __APPLE__//2.gltf 窗口创建GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LeranOpenGL", NULL, NULL);if (window == NULL) {std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//3. 加载所有GL函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}Shader ourShader("./texture.vs", "./texture.fs");//4. 设置顶点数据float vertices[] = {-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};unsigned int indices[] = {0, 1, 3, // first triangle1, 2, 3  // second triangle};unsigned int VBO, VAO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1,&EBO);//元素缓冲对象:Element Buffer Object,EBO glBindVertexArray(VAO);//复制顶点数组到缓冲区中供opengl使用glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//设置纹理属性指针glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);//加载和创建纹理unsigned int textureone,texturetwo;glGenTextures(1, &textureone);glBindTexture(GL_TEXTURE_2D, textureone);//设置纹理环绕参数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);//加载图像和生成mipmapsint width, height, nrChannels;stbi_set_flip_vertically_on_load(true);std::string filePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\container.jpg)";unsigned char* data = stbi_load(filePath.c_str(), &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, &texturetwo);glBindTexture(GL_TEXTURE_2D, texturetwo);//设置纹理环绕参数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);//加载图像和生成mipmapsfilePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\awesomeface.png)";unsigned char* data2 = stbi_load(filePath.c_str(), &width, &height, &nrChannels, 0);if (data2) {glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);glGenerateMipmap(GL_TEXTURE_2D);}else {std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data2);ourShader.use();glUniform1i(glGetUniformLocation(ourShader.ID, "textureone"), 0);//二选一ourShader.setInt("texturetwo", 1);//二选一glm::vec3 cubePositions[] = {glm::vec3(0.0f,  0.0f,  0.0f),glm::vec3(2.0f,  5.0f, -15.0f),glm::vec3(-1.5f, -2.2f, -2.5f),glm::vec3(-3.8f, -2.0f, -12.3f),glm::vec3(2.4f, -0.4f, -3.5f),glm::vec3(-1.7f,  3.0f, -7.5f),glm::vec3(1.3f, -2.0f, -2.5f),glm::vec3(1.5f,  2.0f, -2.5f),glm::vec3(1.5f,  0.2f, -1.5f),glm::vec3(-1.3f,  1.0f, -1.5f)};//5. 循环渲染while (!glfwWindowShouldClose(window)) {processInput(window);glEnable(GL_DEPTH_TEST);// renderglClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//绑定纹理glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, textureone);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texturetwo);ourShader.setFloat("mixValue", mixValue);ourShader.use();// create transformationsglm::mat4 view = glm::mat4(1.0f);glm::mat4 projection = glm::mat4(1.0f);//注意,我们将矩阵向我们要进行移动场景的反方向移动view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);// retrieve the matrix uniform locationsunsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view");// pass them to the shaders (2 different ways)glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "projection"), 1, GL_FALSE, &projection[0][0]);glBindVertexArray(VAO);for (unsigned int i = 0; i < 10; i++) {glm::mat4 model=glm::mat4(1.0f);model = glm::translate(model, cubePositions[i]);float angle = 20.0f * i;model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glfwTerminate();return 0;}// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {std::cout << "up" << std::endl;mixValue += 0.001f;if (mixValue >= 1.0f) {mixValue = 1.0f;}}if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS){std::cout << "down" << std::endl;mixValue -= 0.001f; // change this value accordingly (might be too slow or too fast based on system hardware)if (mixValue <= 0.0f)mixValue = 0.0f;}std::cout << "mixValue:" << mixValue <<std::endl;
}// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}

9. 让可以被3整除的盒子是动的

1,3,6,9动,其他静止

#include <glad/glad.h>
#include <GLFW/glfw3.h>#include <iostream>
#include "stb_image.h"
#include <cmath>
#include "shader.h"#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;float mixValue = 0.2f;int main() {//1.初始化配置glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
#endif // __APPLE__//2.gltf 窗口创建GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LeranOpenGL", NULL, NULL);if (window == NULL) {std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//3. 加载所有GL函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}Shader ourShader("./texture.vs", "./texture.fs");//4. 设置顶点数据float vertices[] = {-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};unsigned int indices[] = {0, 1, 3, // first triangle1, 2, 3  // second triangle};unsigned int VBO, VAO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1,&EBO);//元素缓冲对象:Element Buffer Object,EBO glBindVertexArray(VAO);//复制顶点数组到缓冲区中供opengl使用glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//设置纹理属性指针glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);//加载和创建纹理unsigned int textureone,texturetwo;glGenTextures(1, &textureone);glBindTexture(GL_TEXTURE_2D, textureone);//设置纹理环绕参数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);//加载图像和生成mipmapsint width, height, nrChannels;stbi_set_flip_vertically_on_load(true);std::string filePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\container.jpg)";unsigned char* data = stbi_load(filePath.c_str(), &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, &texturetwo);glBindTexture(GL_TEXTURE_2D, texturetwo);//设置纹理环绕参数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);//加载图像和生成mipmapsfilePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\awesomeface.png)";unsigned char* data2 = stbi_load(filePath.c_str(), &width, &height, &nrChannels, 0);if (data2) {glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);glGenerateMipmap(GL_TEXTURE_2D);}else {std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data2);ourShader.use();glUniform1i(glGetUniformLocation(ourShader.ID, "textureone"), 0);//二选一ourShader.setInt("texturetwo", 1);//二选一glm::vec3 cubePositions[] = {glm::vec3(0.0f,  0.0f,  0.0f),glm::vec3(2.0f,  5.0f, -15.0f),glm::vec3(-1.5f, -2.2f, -2.5f),glm::vec3(-3.8f, -2.0f, -12.3f),glm::vec3(2.4f, -0.4f, -3.5f),glm::vec3(-1.7f,  3.0f, -7.5f),glm::vec3(1.3f, -2.0f, -2.5f),glm::vec3(1.5f,  2.0f, -2.5f),glm::vec3(1.5f,  0.2f, -1.5f),glm::vec3(-1.3f,  1.0f, -1.5f)};//5. 循环渲染while (!glfwWindowShouldClose(window)) {processInput(window);glEnable(GL_DEPTH_TEST);// renderglClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//绑定纹理glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, textureone);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texturetwo);ourShader.setFloat("mixValue", mixValue);ourShader.use();// create transformationsglm::mat4 view = glm::mat4(1.0f);glm::mat4 projection = glm::mat4(1.0f);//注意,我们将矩阵向我们要进行移动场景的反方向移动view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);// retrieve the matrix uniform locationsunsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view");// pass them to the shaders (2 different ways)glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "projection"), 1, GL_FALSE, &projection[0][0]);glBindVertexArray(VAO);for (unsigned int i = 0; i < 10; i++) {glm::mat4 model=glm::mat4(1.0f);model = glm::translate(model, cubePositions[i]);float angle = 20.0f * i;model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));if (i / 3 == 0) {model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));}unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glfwTerminate();return 0;}// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {std::cout << "up" << std::endl;mixValue += 0.001f;if (mixValue >= 1.0f) {mixValue = 1.0f;}}if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS){std::cout << "down" << std::endl;mixValue -= 0.001f; // change this value accordingly (might be too slow or too fast based on system hardware)if (mixValue <= 0.0f)mixValue = 0.0f;}std::cout << "mixValue:" << mixValue <<std::endl;
}// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}

 9. 观察视角

改变view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

		for (unsigned int i = 0; i < 1; i++) {glm::mat4 model=glm::mat4(1.0f);model = glm::translate(model, cubePositions[i]);float angle = 20.0f * i;model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));if (i / 3 == 0) {model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));}unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}

 

 效果(1)glm::vec3(0.0f, 0.0f, -3.0f)

 效果(2)glm::vec3(0.0f, 0.0f, -0.0f)

效果(3) glm::vec3(0.0f, 0.0f, 3.0f)

总结:在Z轴上,值越大离目标越近 

接下来我们需要创建一个观察矩阵。我们想要在场景里面稍微往后移动,以使得物体变成可见的(当在世界空间时,我们位于原点(0,0,0))。要想在场景里面移动,先仔细想一想下面这个句子:

  • 将摄像机向后移动,和将整个场景向前移动是一样的。

这正是观察矩阵所做的,我们以相反于摄像机移动的方向移动整个场景。因为我们想要往后移动,并且OpenGL是一个右手坐标系(Right-handed System),所以我们需要沿着z轴的正方向移动。我们会通过将场景沿着z轴负方向平移来实现。它会给我们一种我们在往后移动的感觉。(推导可知,z轴越小,越远离目标。z轴越大则靠近目标)

 效果(4)glm::vec3(1.0f, 0.0f, -3.0f)

x轴正方向

效果(5)glm::vec3(0.0f, 1.0f, -3.0f)

y轴正方向

坐标系统 - LearnOpenGL CN (learnopengl-cn.github.io)

Shader学习(8)各种坐标空间的定义和变换演示 - 知乎 (zhihu.com)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp使用vue

uniapp集成了Vuex&#xff0c;&#xff0c;并不需要安装vuex 定义自己的vuex vuex中独立命名空间&#xff1a; 可以在模块中使用 namespaced 属性&#xff0c;设置为 true&#xff0c;&#xff0c;这样做的好处是&#xff0c;&#xff0c;不同模块之间的state&#xff0c;mut…

istio 学习笔记

参考&#xff1a;istio简介和基础组件原理&#xff08;服务网格Service Mesh&#xff09;-CSDN博客 Istio 微服务框架 服务治理。 Istio的关键功能: HTTP/1.1&#xff0c;HTTP/2&#xff0c;gRPC和TCP流量的自动区域感知负载平衡和故障切换。 通过丰富的路由规则&#xf…

12 # 手写 findIndex 方法

findIndex 的使用 findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1。 <script>var arr [1, 3, 5, 7, 8];var result arr.findIndex(function (ele, index, array) {console.log("ele----->", ele);conso…

C#中.NET 7.0控制台应用使用LINQtoSQL、LINQtoXML

目录 一、新建控制台应用和数据库连接 二、手动添加System.Data.Linq程序包 三、手动添加System.Data.SqlClient程序包 四、再次操作DataClasses1.dbml 五、示例 1.源码 2.xml文件 默认安装的.NET 7.0控制台应用是不支持使用LINQtoSQL、LINQtoXML的。 默认安装的.NET F…

如何用Java高效地存入一万条数据?这可能是你面试成功的关键!

大家好&#xff0c;我是你们的小米&#xff0c;一个热爱技术、喜欢分享的29岁程序猿。今天我要和大家聊一聊一个常见的面试题&#xff1a;在Java中&#xff0c;当我们需要将一万条数据存储到数据库时&#xff0c;如何能够提高存储效率呢&#xff1f; 在面试过程中&#xff0c;…

设计模式(3)-结构型模式

结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低&#xff0c;满足“合成复用原则…

【机器学习】梯度下降预测波士顿房价

文章目录 前言一、数据集介绍二、预测房价代码1.引入库2.数据3.梯度下降 总结 前言 梯度下降算法学习。 一、数据集介绍 波士顿房价数据集&#xff1a;波士顿房价数据集&#xff0c;用于线性回归预测 二、预测房价代码 1.引入库 from sklearn.linear_model import Linear…

Python爬虫实战-批量爬取美女图片网下载图片

大家好&#xff0c;我是python222小锋老师。 近日锋哥又卷了一波Python实战课程-批量爬取美女图片网下载图片&#xff0c;主要是巩固下Python爬虫基础 视频版教程&#xff1a; Python爬虫实战-批量爬取美女图片网下载图片 视频教程_哔哩哔哩_bilibiliPython爬虫实战-批量爬取…

【Java】I/O流—缓冲流的基础入门和文件拷贝的实战应用

&#x1f33a;个人主页&#xff1a;Dawn黎明开始 &#x1f380;系列专栏&#xff1a;Java ⭐每日一句&#xff1a;你能坚持到什么程度&#xff0c;决定你能达到什么高度 &#x1f4e2;欢迎大家关注&#x1f50d;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 文章目录 一.&…

RapidSSL证书

RapidSSL是一家经验丰富的证书颁发机构&#xff0c;主要专注于提供标准和通配符SSL证书的域验证SSL证书。在2017年被DigicertCA收购后&#xff0c;RapidSSL改进了技术并开始使用现代基础设施。专注于为小型企业和网站提供基本安全解决方案的SSL加密。RapidSSL它具有强大的浏览器…

ZYNQ_project:key_led

条件里是十进制可以不加进制说明&#xff0c;编译器默认是10进制&#xff0c;其他进制要说明。 实验目标&#xff1a; 模块框图&#xff1a; 时序图&#xff1a; 代码&#xff1a; include "para.v"module key_filter (input wire …

python3.8.10虚拟环境安装talib总报平台不匹配

目录 环境&#xff1a; 需求&#xff1a; 问题&#xff1a; 概述 过程及解决 解决方案总结 环境&#xff1a; 操作系统&#xff1a;window10、64位 开发工具&#xff1a;pycharm python版本&#xff1a;python3.8.10 需求&#xff1a; 在python3.8.10的虚拟环境中安…

短短 45 分钟发布会,OpenAI 如何再次让 AI 圈一夜未眠

目录 前言 1. GPT-4 Turbo&#xff0c;更快&#xff0c;更省钱 2. GPT Store 来了&#xff01; 3. 零代码创建 AI Agent 前言 对于 AI 行业从业者来说&#xff0c;刚刚可能是一夜未眠。 北京时间 11 月 7 日凌晨&#xff0c;美国人工智能公司 OpenAI 的开发者大会正式开…

HTTParty库数据抓取代码示例

使用HTTParty库的网络爬虫程序&#xff0c; ruby require httparty # 设置服务器 proxy_host proxy_port # 使用HTTParty库发送HTTP请求获取网页内容 response HTTParty.get(/, :proxy > { :host > proxy_host, :port > proxy_port }) # 打印获取的网页内容 …

亚马逊云科技产品测评』活动征文|通过使用Amazon Neptune来预测电影类型初体验

文章目录 福利来袭Amazon Neptune什么是图数据库为什么要使用图数据库什么是Amazon NeptuneNeptune 的特点 快速入门环境搭建notebook 图神经网络快速构建加载数据配置端点Gremlin 查询清理 删除环境S3 存储桶删除 授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转…

Sketch是什么软件,如何收费和获得免费版

Sketch软件为设计师构建了一个优秀的本地Mac应用程序。Sketch是整个设计过程的平台&#xff0c;通过基于Web的工具共享工作&#xff0c;获取反馈&#xff0c;测试原型&#xff0c;并将其移交给任何浏览器。Sketch软件的定价根据不同的许可类型和订阅计划而变化。本文从Sketch软…

LeetCode算法题解(回溯、难点)|LeetCode332. 重新安排行程

LeetCode332. 重新安排行程 题目链接&#xff1a;332. 重新安排行程 题目描述&#xff1a; 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08…

密码学 - RSA签名算法

实验九 RSA签名算法- 一、实验目的 通过实验掌握GMP开源软件的用法&#xff0c;理解RSA数字签名算法&#xff0c;学会RSA数字签名算法程序设计&#xff0c;提高一般数字签名算法的设计能力。 二、实验要求 (1)基于GMP开源软件&#xff0c;实现RSA签名算法。 (2)要求有对应…

浅谈多回路电表在荷兰光伏系统配电项目中的应用

1.背景信息 Background&#xff1a; 随着全球化石能源&#xff08;石油&#xff0c;煤炭&#xff09;越来越接近枯竭&#xff0c;污染日趋严重&#xff0c;气候日益变暖等问题&#xff0c;全球多个国家和地区相继出台了法规政策&#xff0c;推动了光伏产业的发展。但是现有的光…

MySQL索引的数据结构

1. 索引及其优缺点 1.1 索引概述 MySQL官方对索引的定义为&#xff1a;索引&#xff08;Index&#xff09;是帮助MySQL高效获取数据的数据结构。 索引的本质&#xff1a;索引是数据结构。你可以简单理解为“排好序的快速查找数据结构”&#xff0c;满足特定查找算法。这些数据结…