{"id":448,"date":"2022-01-21T22:45:13","date_gmt":"2022-01-21T14:45:13","guid":{"rendered":"http:\/\/liyanliang.net\/?p=448"},"modified":"2022-03-02T08:09:10","modified_gmt":"2022-03-02T00:09:10","slug":"openglshaderfog","status":"publish","type":"post","link":"http:\/\/liyanliang.net\/index.php\/2022\/01\/21\/openglshaderfog\/","title":{"rendered":"OpenGL\u96fe\u5316\u6548\u679c\u5b9e\u73b0-\u6bcf\u50cf\u7d20\u96fe\u5316"},"content":{"rendered":"\n<div id=\"toc_container\" class=\"no_bullets\"><p class=\"toc_title\">Contents<\/p><ul class=\"toc_list\"><li><a href=\"#i\"><span class=\"toc_number toc_depth_1\">1<\/span> \u96fe\u5316\u5b9e\u73b0\u539f\u7406<\/a><\/li><li><a href=\"#shader\"><span class=\"toc_number toc_depth_1\">2<\/span> shader\u4ee3\u7801\u5b9e\u73b0\uff1a<\/a><\/li><li><a href=\"#i-2\"><span class=\"toc_number toc_depth_1\">3<\/span> \u5b8c\u6574\u9879\u76ee\u4ee3\u7801\uff1a<\/a><\/li><\/ul><\/div>\n<h3 class=\"has-cyan-bluish-gray-background-color has-background wp-block-heading\"><span id=\"i\">\u96fe\u5316\u5b9e\u73b0\u539f\u7406<\/span><\/h3>\n\n\n\n<p>    \u96fe\u80cc\u540e\u7684\u57fa\u672c\u601d\u60f3\u662f\uff0c\u7269\u4f53\u79bb\u76f8\u673a\u8d8a\u8fdc\uff0c\u5b83\u5e94\u8be5\u88ab\u96fe\u8986\u76d6\u5f97\u8d8a\u591a\uff0c\u56e0\u6b64\u5c31\u8d8a\u4e0d\u53ef\u89c1\u3002 \u56e0\u4e3a\u6211\u4eec\u73b0\u5728\u62e5\u6709\u73b0\u4ee3 GPU\uff0c\u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u68c0\u67e5\u573a\u666f\u7684\u6bcf\u4e2a\u7247\u6bb5\u6709\u591a\u8fdc\u5e76\u8ba1\u7b97\u96fe\u3002 \u6211\u4eec\u9700\u8981\u5f97\u5230\u4e00\u4e2a\u53eb\u505a\u96fe\u56e0\u5b50\u7684\u4e1c\u897f\uff0c\u5b83\u662f\u4e00\u4e2a\u4ece 0.0 \u5230 1.0 \u7684\u6570\u5b57\uff0c\u7b80\u5355\u5730\u8bf4\uff0c\u5e94\u8be5\u5bf9\u90a3\u4e2a\u7247\u6bb5\u5e94\u7528\u591a\u5c11\u96fe\u3002 \u5982\u679c\u4e3a\u96f6\uff0c\u5219\u6ca1\u6709\u96fe\uff0c\u5982\u679c\u4e3a 1.0\uff0c\u5219\u5bf9\u8c61\u5b8c\u5168\u88ab\u96fe\u8986\u76d6\u3002 \u4ecb\u4e8e\u4e24\u8005\u4e4b\u95f4\u7684\u4efb\u4f55\u4e1c\u897f\u90fd\u4f1a\u4f7f\u7269\u4f53\u51fa\u73b0\/\u8ff7\u5931\u5728\u8ff7\u96fe\u4e2d\u3002<\/p>\n\n\n\n<p><strong>\u96fe\u9700\u8981\u4e09\u4e2a\u63a7\u5236\u53d8\u91cf\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  struct Fog {\n      vec4  color;  \/\/ \u989c\u8272\n      float range;  \/\/ \u8303\u56f4\n      float density; \/\/ \u5f3a\u5ea6\n  };<\/pre>\n\n\n\n<p><strong>\u96fe\u5f3a\u5ea6\u56e0\u5b50\u7684\u8ba1\u7b97\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">      vec3    viewPos =   vec3(view * vec4(outPosition,1));\n      float   eyeDist =   length(viewPos);\n      float   fogIntensity   =   (fog.range - eyeDist) * fog.density;\n      fogIntensity   =   clamp(fogIntensity, 0.0, 1.0);<\/pre>\n\n\n\n<figure class=\"wp-block-image is-style-default\"><img decoding=\"async\" src=\"https:\/\/liyanliangpublic.oss-cn-hongkong.aliyuncs.com\/img\/20220121223210.png\" alt=\"\"\/><\/figure>\n\n\n\n<p><strong>\u5173\u4e8eclamp\u51fd\u6570\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  genType clamp (genType x, float minVal, float maxVal)<\/pre>\n\n\n\n<p>clamp\u7ffb\u8bd1\u4e3a\u5939\u5177\uff0c\u5c31\u53eb\u5939\u5177\u51fd\u6570\u5427\uff0c\u8fd9\u4e2a\u51fd\u6570\u662f\u4ec0\u4e48\u610f\u601d\u5462\uff1f\u770b\u770b\u89e3\u91ca\u7684\u610f\u601d\u662f\uff1a\u83b7\u53d6x\u548cminVal\u4e4b\u95f4\u8f83\u5927\u7684\u90a3\u4e2a\u503c\uff0c\u7136\u540e\u518d\u62ff\u8f83\u5927\u7684\u90a3\u4e2a\u503c\u548c\u6700\u540e\u90a3\u4e2a\u6700\u5927\u7684\u503c\u8fdb\u884c\u6bd4\u8f83\u7136\u540e\u83b7\u53d6\u8f83\u5c0f\u7684\u90a3\u4e2a\uff0c\u610f\u601d\u5c31\u660e\u767d\u4e86\uff0cclamp\u5b9e\u9645\u4e0a\u662f\u83b7\u5f97\u4e09\u4e2a\u53c2\u6570\u4e2d\u5927\u5c0f\u5904\u5728\u4e2d\u95f4\u7684\u90a3\u4e2a\u503c\u3002\u51fd\u6570\u6709\u4e2a\u8bf4\u660e\uff1a\u5982\u679cminVal &gt; minMax\u7684\u8bdd\uff0c\u51fd\u6570\u8fd4\u56de\u7684\u7ed3\u679c\u662f\u672a\u5b9a\u7684\u3002\u4e5f\u5c31\u662f\u8bf4x\u7684\u503c\u5927\u5c0f\u6ca1\u6709\u9650\u5236\uff0c\u4f46\u662fminval\u7684\u503c\u5fc5\u987b\u6bd4maxVal\u5c0f\u3002<\/p>\n\n\n\n<p><strong>\u50cf\u7d20\u989c\u8272\u8ba1\u7b97\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  FragColor = mix(objectColor, fog.color, 1-fogIntensity);<\/pre>\n\n\n\n<p><strong>\u5173\u4e8emix()\u51fd\u6570:<\/strong><\/p>\n\n\n\n<p>mix(x,y,a) a\u63a7\u5236\u6df7\u5408\u7ed3\u679c return x(1-a) +y*a \u8fd4\u56de \u7ebf\u6027\u6df7\u5408\u7684\u503c\u3002<\/p>\n\n\n\n<h3 class=\"has-cyan-bluish-gray-background-color has-background wp-block-heading\"><span id=\"shader\">shader\u4ee3\u7801\u5b9e\u73b0\uff1a<\/span><\/h3>\n\n\n\n<p>shaderFog_fragment.vs<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  #version 330 core\n  layout (location = 0) in vec3 aPos;\n  layout (location = 1) in vec3 aNormal;\n  layout (location = 2) in vec2 aTexCoords;\n  \u200b\n  out vec3 FragPos;\n  out vec3 Normal;\n  out vec2 TexCoords;\n  \u200b\n  uniform mat4 model;\n  uniform mat4 view;\n  uniform mat4 projection;\n  \u200b\n  out vec3 outPosition;\n  \u200b\n  void main()\n  {\n      outPosition = aPos;\n      FragPos = vec3(model * vec4(aPos, 1.0));\n      Normal = mat3(transpose(inverse(model))) * aNormal;  \n      TexCoords = aTexCoords;\n      \n      gl_Position = projection * view * vec4(FragPos, 1.0);\n  }<\/pre>\n\n\n\n<p>shaderFog_fragment.fs<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#version 330 core\nout vec4 FragColor;\n\nstruct Material {\n    sampler2D diffuse;\n    sampler2D specular;    \n    float shininess;\n}; \n\nstruct Light {\n    \/\/vec3 position;\n    vec3 direction;\n\n    vec3 ambient;\n    vec3 diffuse;\n    vec3 specular;\n};\n\nstruct Fog {\n    vec4  color;\n    float range;\n    float density;\n};\n\nin vec3 FragPos;  \nin vec3 Normal;  \nin vec2 TexCoords;\n\nin vec3 outPosition;\nuniform mat4 view; \n\nuniform vec3 viewPos;\nuniform Material material;\nuniform Light light;\nuniform Fog fog;\n\nvoid main()\n{\n    \/\/ fog\n\tvec3    viewPos =   vec3(view * vec4(outPosition,1));\n    float   eyeDist =   length(viewPos);\n    float   fogIntensity   =   (fog.range - eyeDist) * fog.density;\n    fogIntensity   =   clamp(fogIntensity, 0.0, 1.0);\n\t\t\t\t\t\t\t\t\t\t\n    \/\/ ambient\n    vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;\n  \t\n    \/\/ diffuse \n    vec3 norm = normalize(Normal);\n    \/\/ vec3 lightDir = normalize(light.position - FragPos);\n    vec3 lightDir = normalize(-light.direction);  \n    float diff = max(dot(norm, lightDir), 0.0);\n    vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;  \n    \n    \/\/ specular\n    vec3 viewDir = normalize(viewPos - FragPos);\n    vec3 reflectDir = reflect(-lightDir, norm);  \n    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);\n    vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;  \n        \n    vec3 result = ambient + diffuse + specular;\n    \/\/FragColor = vec4(result, 1.0);\n\tvec4 OutColor = vec4(result, 1.0);\n\tFragColor = mix(OutColor, fog.color, 1-fogIntensity);\n} <\/pre>\n\n\n\n<p>main.cpp<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  #include &lt;glad\/glad.h>\n  #include &lt;GLFW\/glfw3.h>\n  #include &lt;stb_image.h>\n  \u200b\n  #include &lt;glm\/glm.hpp>\n  #include &lt;glm\/gtc\/matrix_transform.hpp>\n  #include &lt;glm\/gtc\/type_ptr.hpp>\n  \u200b\n  #include &lt;learnopengl\/shader_m.h>\n  #include &lt;learnopengl\/camera.h>\n  \u200b\n  #include &lt;iostream>\n  \u200b\n  void framebuffer_size_callback(GLFWwindow* window, int width, int height);\n  void mouse_callback(GLFWwindow* window, double xpos, double ypos);\n  void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);\n  void processInput(GLFWwindow *window);\n  unsigned int loadTexture(const char *path);\n  \u200b\n  \/\/ settings\n  const unsigned int SCR_WIDTH = 800;\n  const unsigned int SCR_HEIGHT = 600;\n  \u200b\n  \/\/ camera\n  Camera camera(glm::vec3(0.0f, 1.0f, 10.0f));\n  float lastX = SCR_WIDTH \/ 2.0f;\n  float lastY = SCR_HEIGHT \/ 2.0f;\n  bool firstMouse = true;\n  \u200b\n  \/\/ timing\n  float deltaTime = 0.0f;\n  float lastFrame = 0.0f;\n  \u200b\n  int main()\n  {\n      \/\/ glfw: initialize and configure\n      \/\/ ------------------------------\n      glfwInit();\n      glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n      glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\n      glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n  \u200b\n  #ifdef __APPLE__\n      glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);\n  #endif\n  \u200b\n      \/\/ glfw window creation\n      \/\/ --------------------\n      GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, \"ShaderFog\", NULL, NULL);\n      if (window == NULL)\n      {\n          std::cout &lt;&lt; \"Failed to create GLFW window\" &lt;&lt; std::endl;\n          glfwTerminate();\n          return -1;\n      }\n      glfwMakeContextCurrent(window);\n      glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);\n      glfwSetCursorPosCallback(window, mouse_callback);\n      glfwSetScrollCallback(window, scroll_callback);\n  \u200b\n      \/\/ tell GLFW to capture our mouse\n      \/\/glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);\n  \u200b\n      \/\/ glad: load all OpenGL function pointers\n      \/\/ ---------------------------------------\n      if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))\n      {\n          std::cout &lt;&lt; \"Failed to initialize GLAD\" &lt;&lt; std::endl;\n          return -1;\n      }\n  \u200b\n      \/\/ configure global opengl state\n      \/\/ -----------------------------\n      glEnable(GL_DEPTH_TEST);\n  \u200b\n      \/\/ build and compile shaders\n      \/\/ -------------------------\n      Shader lightingShader(\"shaderFog_fragment.vs\", \"shaderFog_fragment.fs\");\n  \u200b\n      \/\/ set up vertex data (and buffer(s)) and configure vertex attributes\n      \/\/ ------------------------------------------------------------------\n      float vertices[] = {\n          \/\/ positions          \/\/ normals           \/\/ texture coords\n          -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f,\n          0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  0.0f,\n          0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f,\n          0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f,\n          -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f,\n          -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f,\n  \u200b\n          -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f,\n          0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f,\n          0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,\n          0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,\n          -0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f,\n          -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f,\n  \u200b\n          -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f,\n          -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f,\n          -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f,\n          -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f,\n          -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f,\n          -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f,\n  \u200b\n          0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,\n          0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f,\n          0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f,\n          0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f,\n          0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  0.0f,\n          0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,\n  \u200b\n          -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,\n          0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  1.0f,\n          0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,\n          0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,\n          -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  0.0f,\n          -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,\n  \u200b\n          -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f,\n          0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,\n          0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f,\n          0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f,\n          -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  0.0f,\n          -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f\n      };\n  \u200b\n      float planeSize = 50.0f; \/\/ 5.0f\n      float textureSize = 20.0f; \/\/ 2.0f\n      float planeVertices[] = {\n          \/\/ positions                    \/\/ normals           \/\/ texture Coords \n           planeSize, -0.5f,  planeSize,   0.0f,  0.0f,  1.0f, textureSize, 0.0f,\n          -planeSize, -0.5f,  planeSize,   0.0f,  0.0f,  1.0f, 0.0f, 0.0f,\n          -planeSize, -0.5f, -planeSize,   0.0f,  0.0f,  1.0f, 0.0f, textureSize,\n  \u200b\n           planeSize, -0.5f,  planeSize,  0.0f,  0.0f,  1.0f,  textureSize, 0.0f,\n          -planeSize, -0.5f, -planeSize,  0.0f,  0.0f,  1.0f,  0.0f, textureSize,\n           planeSize, -0.5f, -planeSize,  0.0f,  0.0f,  1.0f,  textureSize, textureSize\n      };\n  \u200b\n      \/\/ positions all containers\n      glm::vec3 cubePositions[] = {\n          glm::vec3( 0.0f,  0.0f,  0.0f),\n          glm::vec3( 2.0f,  0.0f, -15.0f),\n          glm::vec3(-1.5f,  0.0f, -2.5f),\n          glm::vec3(-3.8f,  0.0f, -12.3f),\n          glm::vec3( 2.4f,  0.0f, -3.5f),\n          glm::vec3(-1.7f,  0.0f, -7.5f),\n          glm::vec3( 1.3f,  0.0f, -2.5f),\n          glm::vec3( 1.5f,  0.0f, -2.5f),\n          glm::vec3( 1.5f,  0.0f, -1.5f),\n          glm::vec3(-1.3f,  0.0f, -1.5f)\n      };\n  \u200b\n      \/\/ first, configure the cube's VAO (and VBO)\n      unsigned int VBO, cubeVAO;\n      glGenVertexArrays(1, &amp;cubeVAO);\n      glGenBuffers(1, &amp;VBO);\n  \u200b\n      glBindBuffer(GL_ARRAY_BUFFER, VBO);\n      glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);\n  \u200b\n      glBindVertexArray(cubeVAO);\n      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);\n      glEnableVertexAttribArray(0);\n      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));\n      glEnableVertexAttribArray(1);\n      glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));\n      glEnableVertexAttribArray(2);\n  \u200b\n      \/\/ plane VAO\n      unsigned int planeVAO, planeVBO;\n      glGenVertexArrays(1, &amp;planeVAO);\n      glGenBuffers(1, &amp;planeVBO);\n      glBindVertexArray(planeVAO);\n      glBindBuffer(GL_ARRAY_BUFFER, planeVBO);\n      glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &amp;planeVertices, GL_STATIC_DRAW);\n      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);\n      glEnableVertexAttribArray(0);\n      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));\n      glEnableVertexAttribArray(1);\n      glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));\n      glEnableVertexAttribArray(2);\n  \u200b\n      \/\/ load textures (we now use a utility function to keep the code more organized)\n      \/\/ -----------------------------------------------------------------------------\n      unsigned int diffuseMap = loadTexture(\"resources\/textures\/container2.png\");\n      unsigned int specularMap = loadTexture(\"resources\/textures\/container2_specular.png\");\n      unsigned int floorTexture = loadTexture(\"resources\/textures\/metal.png\");\n  \u200b\n      \/\/ shader configuration\n      \/\/ --------------------\n      lightingShader.use();\n      lightingShader.setInt(\"material.diffuse\", 0);\n      lightingShader.setInt(\"material.specular\", 1);\n  \u200b\n      \/\/ render loop\n      \/\/ -----------\n      while (!glfwWindowShouldClose(window))\n      {\n          \/\/ per-frame time logic\n          \/\/ --------------------\n          float currentFrame = static_cast&lt;float>(glfwGetTime());\n          deltaTime = currentFrame - lastFrame;\n          lastFrame = currentFrame;\n  \u200b\n          \/\/ input\n          \/\/ -----\n          processInput(window);\n  \u200b\n          \/\/ render\n          \/\/ ------\n          glClearColor(0.1f, 0.1f, 0.1f, 1.0f);\n          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n  \u200b\n          \/\/ be sure to activate shader when setting uniforms\/drawing objects\n          lightingShader.use();\n          lightingShader.setVec3(\"light.direction\", -0.2f, -1.0f, -0.3f);\n          lightingShader.setVec3(\"viewPos\", camera.Position);\n  \u200b\n          \/\/ light properties\n          lightingShader.setVec3(\"light.ambient\", 1.0f, 1.0f, 1.0f);\n          lightingShader.setVec3(\"light.diffuse\", 1.0f, 1.0f, 1.0f);\n          lightingShader.setVec3(\"light.specular\", 1.0f, 1.0f, 1.0f);\n  \u200b\n          \/\/ material properties\n          lightingShader.setFloat(\"material.shininess\", 32.0f);\n  \u200b\n          \/\/ fog\n          lightingShader.setVec4(\"fog.color\", 1.0f, 1.0f, 1.0f, 1.0f);\n          lightingShader.setFloat(\"fog.density\", 0.1f); \/\/ 0.01\n          lightingShader.setFloat(\"fog.range\", 15.0f);\n  \u200b\n          \/\/ view\/projection transformations\n          glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH \/ (float)SCR_HEIGHT, 0.1f, 100.0f);\n          glm::mat4 view = camera.GetViewMatrix();\n          lightingShader.setMat4(\"projection\", projection);\n          lightingShader.setMat4(\"view\", view);\n  \u200b\n          \/\/ world transformation\n          glm::mat4 model = glm::mat4(1.0f);\n          lightingShader.setMat4(\"model\", model);\n  \u200b\n          \/\/ floor\n          glActiveTexture(GL_TEXTURE0);\n          glBindVertexArray(planeVAO);\n          glBindTexture(GL_TEXTURE_2D, floorTexture);\n          model = glm::mat4(1.0f);\n          lightingShader.setMat4(\"model\", model);\n          glDrawArrays(GL_TRIANGLES, 0, 6);\n  \u200b\n          \/\/ cube\n          \/\/ bind diffuse map\n          glActiveTexture(GL_TEXTURE0);\n          glBindTexture(GL_TEXTURE_2D, diffuseMap);\n          \/\/ bind specular map\n          glActiveTexture(GL_TEXTURE1);\n          glBindTexture(GL_TEXTURE_2D, specularMap);\n  \u200b\n          \/\/ render containers\n          glBindVertexArray(cubeVAO);\n          for (unsigned int i = 0; i &lt; 10; i++)\n          {\n              \/\/ calculate the model matrix for each object and pass it to shader before drawing\n              glm::mat4 model = glm::mat4(1.0f);\n              model = glm::translate(model, cubePositions[i]);\n              \/\/float angle = 20.0f * i;\n              \/\/model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));\n              lightingShader.setMat4(\"model\", model);\n  \u200b\n              glDrawArrays(GL_TRIANGLES, 0, 36);\n          }\n  \u200b\n          \/\/ glfw: swap buffers and poll IO events (keys pressed\/released, mouse moved etc.)\n          \/\/ -------------------------------------------------------------------------------\n          glfwSwapBuffers(window);\n          glfwPollEvents();\n      }\n  \u200b\n      \/\/ optional: de-allocate all resources once they've outlived their purpose:\n      \/\/ ------------------------------------------------------------------------\n      glDeleteVertexArrays(1, &amp;cubeVAO);\n      glDeleteVertexArrays(1, &amp;planeVAO);\n      glDeleteBuffers(1, &amp;VBO);\n  \u200b\n      \/\/ glfw: terminate, clearing all previously allocated GLFW resources.\n      \/\/ ------------------------------------------------------------------\n      glfwTerminate();\n      return 0;\n  }\n  \u200b\n  \/\/ process all input: query GLFW whether relevant keys are pressed\/released this frame and react accordingly\n  \/\/ ---------------------------------------------------------------------------------------------------------\n  void processInput(GLFWwindow *window)\n  {\n      if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)\n          glfwSetWindowShouldClose(window, true);\n  \u200b\n      if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)\n          camera.ProcessKeyboard(FORWARD, deltaTime);\n      if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)\n          camera.ProcessKeyboard(BACKWARD, deltaTime);\n      if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)\n          camera.ProcessKeyboard(LEFT, deltaTime);\n      if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)\n          camera.ProcessKeyboard(RIGHT, deltaTime);\n  }\n  \u200b\n  \/\/ glfw: whenever the window size changed (by OS or user resize) this callback function executes\n  \/\/ ---------------------------------------------------------------------------------------------\n  void framebuffer_size_callback(GLFWwindow* window, int width, int height)\n  {\n      \/\/ make sure the viewport matches the new window dimensions; note that width and \n      \/\/ height will be significantly larger than specified on retina displays.\n      glViewport(0, 0, width, height);\n  }\n  \u200b\n  \u200b\n  \/\/ glfw: whenever the mouse moves, this callback is called\n  \/\/ -------------------------------------------------------\n  void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)\n  {\n      float xpos = static_cast&lt;float>(xposIn);\n      float ypos = static_cast&lt;float>(yposIn);\n      if (firstMouse)\n      {\n          lastX = xpos;\n          lastY = ypos;\n          firstMouse = false;\n      }\n  \u200b\n      float xoffset = xpos - lastX;\n      float yoffset = lastY - ypos; \/\/ reversed since y-coordinates go from bottom to top\n  \u200b\n      lastX = xpos;\n      lastY = ypos;\n  \u200b\n      camera.ProcessMouseMovement(xoffset, yoffset);\n  }\n  \u200b\n  \/\/ glfw: whenever the mouse scroll wheel scrolls, this callback is called\n  \/\/ ----------------------------------------------------------------------\n  void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)\n  {\n      camera.ProcessMouseScroll(static_cast&lt;float>(yoffset));\n  }\n  \u200b\n  \/\/ utility function for loading a 2D texture from file\n  \/\/ ---------------------------------------------------\n  unsigned int loadTexture(char const * path)\n  {\n      unsigned int textureID;\n      glGenTextures(1, &amp;textureID);\n  \u200b\n      int width, height, nrComponents;\n      unsigned char *data = stbi_load(path, &amp;width, &amp;height, &amp;nrComponents, 0);\n      if (data)\n      {\n          GLenum format;\n          if (nrComponents == 1)\n              format = GL_RED;\n          else if (nrComponents == 3)\n              format = GL_RGB;\n          else if (nrComponents == 4)\n              format = GL_RGBA;\n  \u200b\n          glBindTexture(GL_TEXTURE_2D, textureID);\n          glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);\n          glGenerateMipmap(GL_TEXTURE_2D);\n  \u200b\n          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);\n          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n  \u200b\n          stbi_image_free(data);\n      }\n      else\n      {\n          std::cout &lt;&lt; \"Texture failed to load at path: \" &lt;&lt; path &lt;&lt; std::endl;\n          stbi_image_free(data);\n      }\n  \u200b\n      return textureID;\n  }\n  \u200b<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span id=\"i-2\">\u5b8c\u6574\u9879\u76ee\u4ee3\u7801\uff1a<\/span><\/h3>\n\n\n\n<p><a href=\"https:\/\/github.com\/mc-liyanliang\/OpenGL-Shader\/tree\/master\">https:\/\/github.com\/mc-liyanliang\/OpenGL-Shader\/tree\/master<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Contents1 \u96fe\u5316\u5b9e\u73b0\u539f\u74062 shader\u4ee3\u7801\u5b9e\u73b0\uff1a3 \u5b8c\u6574\u9879\u76ee\u4ee3\u7801\uff1a \u96fe\u5316\u5b9e\u73b0\u539f\u7406 \u96fe\u80cc\u540e\u7684\u57fa\u672c\u601d\u60f3\u662f\uff0c\u7269\u4f53\u79bb\u76f8\u673a\u8d8a\u8fdc\uff0c\u5b83\u5e94\u8be5\u88ab\u96fe\u8986\u76d6\u5f97\u8d8a\u591a\uff0c\u56e0\u6b64\u5c31\u8d8a\u4e0d\u53ef\u89c1\u3002 \u56e0\u4e3a\u6211\u4eec\u73b0\u5728\u62e5\u6709\u73b0\u4ee3 GPU\uff0c\u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u68c0\u67e5\u573a\u666f\u7684\u6bcf\u4e2a\u7247\u6bb5\u6709\u591a\u8fdc\u5e76\u8ba1\u7b97\u96fe\u3002 \u6211\u4eec\u9700\u8981\u5f97\u5230\u4e00\u4e2a\u53eb\u505a\u96fe\u56e0\u5b50\u7684\u4e1c\u897f\uff0c\u5b83\u662f\u4e00\u4e2a\u4ece 0.0 \u5230 1.0 \u7684\u6570\u5b57\uff0c\u7b80\u5355\u5730\u8bf4\uff0c\u5e94\u8be5\u5bf9\u90a3\u4e2a\u7247\u6bb5\u5e94\u7528\u591a\u5c11\u96fe\u3002 \u5982\u679c\u4e3a\u96f6\uff0c\u5219\u6ca1\u6709\u96fe\uff0c\u5982\u679c\u4e3a 1.0\uff0c\u5219\u5bf9\u8c61\u5b8c\u5168\u88ab\u96fe\u8986\u76d6\u3002 \u4ecb\u4e8e\u4e24\u8005\u4e4b\u95f4\u7684\u4efb\u4f55\u4e1c\u897f\u90fd\u4f1a\u4f7f\u7269\u4f53\u51fa\u73b0\/\u8ff7\u5931\u5728\u8ff7\u96fe\u4e2d\u3002 \u96fe\u9700\u8981\u4e09\u4e2a\u63a7\u5236\u53d8\u91cf\uff1a \u96fe\u5f3a\u5ea6\u56e0\u5b50\u7684\u8ba1\u7b97\uff1a \u5173\u4e8eclamp\u51fd\u6570\uff1a clamp\u7ffb\u8bd1\u4e3a\u5939\u5177\uff0c\u5c31\u53eb\u5939\u5177\u51fd\u6570\u5427\uff0c\u8fd9\u4e2a\u51fd\u6570\u662f\u4ec0\u4e48\u610f\u601d\u5462\uff1f\u770b\u770b\u89e3\u91ca\u7684\u610f\u601d\u662f\uff1a\u83b7\u53d6x\u548cminVal\u4e4b\u95f4\u8f83\u5927\u7684\u90a3\u4e2a\u503c\uff0c\u7136\u540e\u518d\u62ff\u8f83\u5927\u7684\u90a3\u4e2a\u503c\u548c\u6700\u540e\u90a3\u4e2a\u6700\u5927\u7684\u503c\u8fdb\u884c\u6bd4\u8f83\u7136\u540e\u83b7\u53d6\u8f83\u5c0f\u7684\u90a3\u4e2a\uff0c\u610f\u601d\u5c31\u660e\u767d\u4e86\uff0cclamp\u5b9e\u9645\u4e0a\u662f\u83b7\u5f97\u4e09\u4e2a\u53c2\u6570\u4e2d\u5927\u5c0f\u5904\u5728\u4e2d\u95f4\u7684\u90a3\u4e2a\u503c\u3002\u51fd\u6570\u6709\u4e2a\u8bf4\u660e\uff1a\u5982\u679cminVal &gt; minMax\u7684\u8bdd\uff0c\u51fd\u6570\u8fd4\u56de\u7684\u7ed3\u679c\u662f\u672a\u5b9a\u7684\u3002\u4e5f\u5c31\u662f\u8bf4x\u7684\u503c\u5927\u5c0f\u6ca1\u6709\u9650\u5236\uff0c\u4f46\u662fminval\u7684\u503c\u5fc5\u987b\u6bd4maxVal\u5c0f\u3002 \u50cf\u7d20\u989c\u8272\u8ba1\u7b97\uff1a \u5173\u4e8emix()\u51fd\u6570: mix(x,y,a) &#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"http:\/\/liyanliang.net\/index.php\/2022\/01\/21\/openglshaderfog\/\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":449,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[47],"class_list":["post-448","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-opengl","tag-fog"],"_links":{"self":[{"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/posts\/448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/comments?post=448"}],"version-history":[{"count":2,"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/posts\/448\/revisions"}],"predecessor-version":[{"id":476,"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/posts\/448\/revisions\/476"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/media\/449"}],"wp:attachment":[{"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/media?parent=448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/categories?post=448"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/liyanliang.net\/index.php\/wp-json\/wp\/v2\/tags?post=448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}