谢岗镇网站建设公司宁波自适应网站建设

当前位置: 首页 > news >正文

谢岗镇网站建设公司,宁波自适应网站建设,mj wordpress,wordpress搭建下载站点OpenGL基础光照环境光照漫反射光照镜面光照基础光照 主要需要理解一个模型是冯氏光照模型#xff0c;主要结构由3个分量组成#xff1a;环境#xff0c;漫反射#xff0c;镜面光照。下面分别描述下这三个光照#xff1a; 环境光照(Ambient Lighting)#xff1a;即使在黑… OpenGL基础光照环境光照漫反射光照镜面光照基础光照 主要需要理解一个模型是冯氏光照模型主要结构由3个分量组成环境漫反射镜面光照。下面分别描述下这三个光照 环境光照(Ambient Lighting)即使在黑暗的情况下世界上通常也仍然有一些光亮月亮、远处的光所以物体几乎永远不会是完全黑暗的。为了模拟这个我们会使用一个环境光照常量它永远会给物体一些颜色。 漫反射光照(Diffuse Lighting)模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源它就会越亮。 镜面光照(Specular Lighting)模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。 环境光照 光是来自分散的很多光源其中的一个属性是可以向很多方向发散并反弹从而能够到达不是非常直接临近的点。所以光能够在它的表面上反射对一个物体产生间接的影响。考虑到这种情况的算法是全局照明算法算法开销高昂又极其复杂。 使用一个简化的全局照明模型也就是环境光照。用一个很小的常量光照颜色添加到物体片段的最终颜色中这样的话即使场景中没有直接的光源也能看到好像存在一些发散的光。 把环境光照添加到场景中用光的颜色乘以一个很小的常量环境因子再乘以物体的颜色最终的结果作为片段的颜色 void main() {float ambientStrength 0.1;vec3 ambient ambientStrength * lightColor;vec3 result ambient * objectColor;FragColor vec4(result, 1.0); }漫反射光照 漫反射光照使得物体上与光线方向越接近的片段能够从光源出获得更多的亮度。如果光线垂直于物体表面则这束光对物体的影响会最大化为了测量光线和片段的角度需要使用一个法向量是垂直于片段表面的一个向量。 注意两个单位向量的夹角越小它们点乘的结果越倾向于1当两个向量的夹角为90°则点乘会变成0。为了得到两个向量夹角的余弦值需要使用单位向量则需要保证所有的向量都是标准化的否则点乘返回的就不仅仅是余弦值了 首先需要先求得法向量 由于顶点本身没有表面需要利用它周围的顶点来计算出这个顶点的表面。可以使用叉乘对立方体所有的顶点计算法向量。由于3D立方体不是一个复杂的图形那么可以简单的把法线数据手工添加到顶点数据中。 由于向顶点数组添加了额外的数据所以需要更新光照的顶点着色器 #version 330 core layout (location 0) in vec3 aPos; layout (location 1) in vec3 aNormal; …现在向每个顶点都添加了一个法向量并且更新了顶点着色器还需要更新顶点属性指针。注意灯使用同样的顶点数组作为它的顶点数据然后灯的着色器并没有使用新添加的法向量。所以不需要更新灯的着色器或者是属性的配置但是必须修改顶点属性指针来适应新的顶点数组大小 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0);如果只想使用每个顶点的前三个float并且忽略后3个float则只需要把步长参数改成float大小的6倍即可。 所有的光照计算都是在片段着色器中进行的需要把法向量由顶点着色器传递到片段着色器 out vec3 Normal;void main() {gl_Position projection * view * model * vec4(aPos, 1.0);Normal aNormal; }接下来在片段着色器中定义相应的输入变量 in vec3 Normal;下面需要计算漫反射光照。当前知道了每个顶点的法向量但是还需要知道光源的位置向量和片段的位置向量由于光源的位置是一个静态变量那么可以简单的在片段着色器中把它声明成uniform uniform vec3 lightPos;然后再渲染循环中不断更新uniform使用上述声明的lightPos向量作为光源位置 lightingShader.setVec3(lightPos, lightPos);最后需要片段的位置。会再世界空间中进行所有光照计算所以需要一个再世界空间中的顶点位置。可以通过顶点位置属性乘以模型矩阵来变换到世界空间坐标。这个操作在顶点着色器中完成。下面实操声明一个输出变量并计算它的世界空间坐标 out vec3 FragPos;
out vec3 Normal;void main() {gl_Position projection * view * model * vec4(aPos, 1.0);FragPos vec3(model * vec4(aPos, 1.0));Normal aNormal; }最后在片段着色器中添加相应的输入变量 in vec3 FragPos;综上所有的变量都设置完成下来可以在片段着色器中添加光照计算。 首先需要计算光源和片段位置之间的方向向量。注光的方向向量是光源位置向量 和 片段位置向量 之间的向量差。需要确保所有相关向量最后都转换成单位向量需要把法线和最终的方向向量都进行标准化 vec3 norm normalize(Normal); vec3 lightDir normalize(lightPos - FragPos);下面需要对norm和lightDir向量进行点乘计算光源对当前片段实际的漫反射影响。结果值再乘以光的颜色得到漫反射分量。两个向量之间的角度越大漫反射分量就会越小 float diff max(dot(norm, lightDir), 0.0); vec3 diffuse diff * lightColor;如果两个向量之间的角度大于90度点乘的结果就会变成负数这样会导致漫反射分量变为负数。为此我们使用max函数返回两个参数之间较大的参数从而保证漫反射分量不会变成负数。负数颜色的光照是没有定义的所以最好避免它除非你是那种古怪的艺术家。 现在我们有了环境光分量和漫反射分量我们把它们相加然后把结果乘以物体的颜色来获得片段最后的输出颜色 vec3 result (ambient diffuse) * objectColor; FragColor vec4(result, 1.0);镜面光照 镜面光照也决定于光的方向向量和物体的法向量但是它也决定于观察方向例如玩家是从什么方向看向这个片段的。镜面光照决定于表面的反射特性。如果我们把物体表面设想为一面镜子那么镜面光照最强的地方就是我们看到表面上反射光的地方 可以根据法向量翻折入射光的方向来得到反射向量。计算反射向量和观察方向的角度差。夹角越小镜面光的作用越大。效果是如果看向入射光再表面的反射方向时会看到一点高光。 观察向量是计算镜面光照时需要的一个额外变量可以使用观察者的世界空间位置和片段的位置来计算它。再计算出镜面光照强度用其乘以光照颜色并将它和环境光照和漫反射光照部分加和。 要得到观察者的世界空间坐标可以直接使用摄像机的位置向量。把uniform添加到片段着色器中把摄像机位置传给着色器 uniform vec3 viewPos; lightingShader.setVec3(viewPos, camera.Position);下来可以计算高光强度。首先定义一个镜面强度变量给镜面高光一个中等亮度颜色 float specularStrength 0.5;下一步计算视线方向向量和对应的沿着法线轴的反射向量 vec3 viewDir normalize(viewPos - FragPos); vec3 reflectDir reflect(-lightDir, norm);需要注意的是我们对lightDir向量进行了取反。reflect函数要求第一个向量是从光源指向片段位置的向量但是lightDir当前正好相反是从片段指向光源由先前我们计算lightDir向量时减法的顺序决定。为了保证我们得到正确的reflect向量我们通过对lightDir向量取反来获得相反的方向。第二个参数要求是一个法向量所以我们提供的是已标准化的norm向量。 最后需要计算镜面分量 float spec pow(max(dot(viewDir, reflectDir), 0.0), 32); vec3 specular specularStrength * spec * lightColor;先计算视线方向与反射方向的点乘并确保它不是负值然后取它的32次幂。这个32是高光的反光度(Shininess)。一个物体的反光度越高反射光的能力越强散射得越少高光点就会越小2468163264128256 把镜面分量加到环境光分量和漫反射分量中再用结果乘以物体的颜色 vec3 result (ambient diffuse specular) * objectColor; FragColor vec4(result, 1.0);补充 在光照着色器的早期开发者曾经在顶点着色器中实现冯氏光照模型。在顶点着色器中做光照的优势是相比片段来说顶点要少得多因此会更高效所以开销大的光照计算频率会更低。然而顶点着色器中的最终颜色值是仅仅只是那个顶点的颜色值片段的颜色值是由插值光照颜色所得来的。结果就是这种光照看起来不会非常真实除非使用了大量顶点。 在顶点着色器中实现的冯氏光照模型叫做Gouraud着色(Gouraud Shading)而不是冯氏着色(Phong Shading)。记住由于插值这种光照看起来有点逊色。冯氏着色能产生更平滑的光照效果。 完整代码如下 #include glad/glad.h #include GLFW/glfw3.h#include glm/glm.hpp #include glm/gtc/matrix_transform.hpp #include glm/gtc/type_ptr.hpp#include learnopengl/shader_m.h #include learnopengl/camera.h#include iostreamvoid framebuffer_size_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void processInput(GLFWwindow window);// settings const unsigned int SCR_WIDTH 800; const unsigned int SCR_HEIGHT 600;// camera Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); float lastX SCR_WIDTH / 2.0f; float lastY SCR_HEIGHT / 2.0f; bool firstMouse true;// timing float deltaTime 0.0f; float lastFrame 0.0f;// lighting glm::vec3 lightPos(1.2f, 1.0f, 2.0f);int main() {// glfw: initialize and configure// ——————————glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef APPLEglfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif// glfw window creation// ——————–GLFWwindow window glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, LearnOpenGL, NULL, NULL);if (window NULL){std::cout Failed to create GLFW window std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);// tell GLFW to capture our mouseglfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);// glad: load all OpenGL function pointers// —————————————if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout Failed to initialize GLAD std::endl;return -1;}// configure global opengl state// —————————–glEnable(GL_DEPTH_TEST);// build and compile our shader zprogram// ————————————Shader lightingShader(2.2.basic_lighting.vs, 2.2.basic_lighting.fs);Shader lightCubeShader(2.2.light_cube.vs, 2.2.light_cube.fs);// set up vertex data (and buffer(s)) and configure vertex attributes// ——————————————————————float vertices[] {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f};// first, configure the cubes VAO (and VBO)unsigned int VBO, cubeVAO;glGenVertexArrays(1, cubeVAO);glGenBuffers(1, VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindVertexArray(cubeVAO);// position attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// normal attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);// second, configure the lights VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube)unsigned int lightCubeVAO;glGenVertexArrays(1, lightCubeVAO);glBindVertexArray(lightCubeVAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);// note that we update the lamps position attributes stride to reflect the updated buffer dataglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// render loop// ———–while (!glfwWindowShouldClose(window)){// per-frame time logic// ——————–float currentFrame static_castfloat(glfwGetTime());deltaTime currentFrame - lastFrame;lastFrame currentFrame;// input// —–processInput(window);// render// ——glClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// be sure to activate shader when setting uniforms/drawing objectslightingShader.use();lightingShader.setVec3(objectColor, 1.0f, 0.5f, 0.31f);lightingShader.setVec3(lightColor, 1.0f, 1.0f, 1.0f);lightingShader.setVec3(lightPos, lightPos);lightingShader.setVec3(viewPos, camera.Position);// view/projection transformationsglm::mat4 projection glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);glm::mat4 view camera.GetViewMatrix();lightingShader.setMat4(projection, projection);lightingShader.setMat4(view, view);// world transformationglm::mat4 model glm::mat4(1.0f);lightingShader.setMat4(model, model);// render the cubeglBindVertexArray(cubeVAO);glDrawArrays(GL_TRIANGLES, 0, 36);// also draw the lamp objectlightCubeShader.use();lightCubeShader.setMat4(projection, projection);lightCubeShader.setMat4(view, view);model glm::mat4(1.0f);model glm::translate(model, lightPos);model glm::scale(model, glm::vec3(0.2f)); // a smaller cubelightCubeShader.setMat4(model, model);glBindVertexArray(lightCubeVAO);glDrawArrays(GL_TRIANGLES, 0, 36);// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// ——————————————————————————-glfwSwapBuffers(window);glfwPollEvents();}// optional: de-allocate all resources once theyve outlived their purpose:// ————————————————————————glDeleteVertexArrays(1, cubeVAO);glDeleteVertexArrays(1, lightCubeVAO);glDeleteBuffers(1, VBO);// glfw: terminate, clearing all previously allocated GLFW resources.// ——————————————————————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_W) GLFW_PRESS)camera.ProcessKeyboard(FORWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_S) GLFW_PRESS)camera.ProcessKeyboard(BACKWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_A) GLFW_PRESS)camera.ProcessKeyboard(LEFT, deltaTime);if (glfwGetKey(window, GLFW_KEY_D) GLFW_PRESS)camera.ProcessKeyboard(RIGHT, deltaTime); }// 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); }// glfw: whenever the mouse moves, this callback is called // ——————————————————- void mouse_callback(GLFWwindow* window, double xposIn, double yposIn) {float xpos static_castfloat(xposIn);float ypos static_castfloat(yposIn);if (firstMouse){lastX xpos;lastY ypos;firstMouse false;}float xoffset xpos - lastX;float yoffset lastY - ypos; // reversed since y-coordinates go from bottom to toplastX xpos;lastY ypos;camera.ProcessMouseMovement(xoffset, yoffset); }// glfw: whenever the mouse scroll wheel scrolls, this callback is called // ———————————————————————- void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {camera.ProcessMouseScroll(static_castfloat(yoffset)); }