Basic Lighting_练习一

在观察空间(而不是世界空间)中计算冯氏光照:

 1 // Vertex shader:
 2 // ================
 3 #version 330 core
 4 layout (location = 0) in vec3 aPos;
 5 layout (location = 1) in vec3 aNormal;
 6 
 7 out vec3 FragPos;
 8 out vec3 Normal;
 9 out vec3 LightPos;
10 
11 uniform vec3 lightPos; // we now define the uniform in the vertex shader and pass the 'view space' lightpos to the fragment shader. lightPos is currently in world space.
12 
13 uniform mat4 model;
14 uniform mat4 view;
15 uniform mat4 projection;
16 
17 void main()
18 {
19     gl_Position = projection * view * model * vec4(aPos, 1.0);
20     FragPos = vec3(view * model * vec4(aPos, 1.0));
21     Normal = mat3(transpose(inverse(view * model))) * aNormal;
22     LightPos = vec3(view * vec4(lightPos, 1.0)); // Transform world-space light position to view-space light position
23 }
24 
25 
26 // Fragment shader:
27 // ================
28 #version 330 core
29 out vec4 FragColor;
30 
31 in vec3 FragPos;
32 in vec3 Normal;
33 in vec3 LightPos;   // extra in variable, since we need the light position in view space we calculate this in the vertex shader
34 
35 uniform vec3 lightColor;
36 uniform vec3 objectColor;
37 
38 void main()
39 {
40     // ambient
41     float ambientStrength = 0.1;
42     vec3 ambient = ambientStrength * lightColor;    
43     
44      // diffuse 
45     vec3 norm = normalize(Normal);
46     vec3 lightDir = normalize(LightPos - FragPos);
47     float diff = max(dot(norm, lightDir), 0.0);
48     vec3 diffuse = diff * lightColor;
49     
50     // specular
51     float specularStrength = 0.5;
52     vec3 viewDir = normalize(-FragPos); // the viewer is always at (0,0,0) in view-space, so viewDir is (0,0,0) - Position => -Position
53     vec3 reflectDir = reflect(-lightDir, norm);  
54     float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
55     vec3 specular = specularStrength * spec * lightColor; 
56     
57     vec3 result = (ambient + diffuse + specular) * objectColor;
58     FragColor = vec4(result, 1.0);
59 }
View Code

注意:

  1. 在观察空间计算的好处是,观察者的位置总是(0, 0, 0),所以这样你直接就获得了观察者位置。可是我发现在学习的时候在世界空间中计算光照更符合直觉。如果你仍然希望在观察空间计算光照的话,你需要将所有相关的向量都用观察矩阵进行变换(记得也要改变法线矩阵)。
  2. 当我们讨论摄像机/观察空间(Camera/View Space)的时候,是在讨论以摄像机的视角作为场景原点时场景中所有的顶点坐标:观察矩阵(LookAt)把所有的世界坐标变换为相对于摄像机位置与方向的观察坐标。
  3. LookAt矩阵就像它的名字表达的那样:它会创建一个看着(Look at)给定目标的观察矩阵。
  1 #include <glad/glad.h>
  2 #include <GLFW/glfw3.h>
  3 #define STB_IMAGE_IMPLEMENTATION
  4 #include <stb/stb_image.h>
  5 
  6 #include <glm/glm.hpp>
  7 #include <glm/gtc/matrix_transform.hpp>
  8 #include <glm/gtc/type_ptr.hpp>
  9 
 10 #include <Shader/shader.h>
 11 #include <Camera/camera.h>
 12 
 13 #include <iostream>
 14 
 15 void framebuffer_size_callback(GLFWwindow* window, int width, int height);
 16 void mouse_callback(GLFWwindow* window, double xpos, double ypos);
 17 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
 18 void processInput(GLFWwindow *window);
 19 
 20 // settings
 21 const unsigned int SCR_WIDTH = 800;
 22 const unsigned int SCR_HEIGHT = 600;
 23 
 24 // camera
 25 Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
 26 float lastX = SCR_WIDTH / 2.0f;
 27 float lastY = SCR_HEIGHT / 2.0f;
 28 bool firstMouse = true;
 29 
 30 //timeing
 31 float deltaTime = 0.0f; // 当前帧与上一帧的时间差
 32 float lastFrame = 0.0f; // 上一帧的时间
 33 
 34 // lighting
 35 glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
 36 
 37 int main()
 38 {
 39     // glfw: initialize and configure
 40     // ------------------------------
 41     glfwInit();
 42     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
 43     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
 44     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 45 
 46 #ifdef __APPLE__
 47     glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
 48 #endif
 49 
 50     // glfw window creation
 51     // --------------------
 52     GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
 53     if (window == NULL)
 54     {
 55         std::cout << "Failed to create GLFW window" << std::endl;
 56         glfwTerminate();
 57         return -1;
 58     }
 59     glfwMakeContextCurrent(window);
 60     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
 61     glfwSetCursorPosCallback(window, mouse_callback);
 62     glfwSetScrollCallback(window, scroll_callback);
 63 
 64     // tell GLFW to capture our mouse
 65     glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
 66 
 67     // glad: load all OpenGL function pointers
 68     // ---------------------------------------
 69     if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
 70     {
 71         std::cout << "Failed to initialize GLAD" << std::endl;
 72         return -1;
 73     }
 74 
 75     // configure global opengl state
 76     // -----------------------------
 77     glEnable(GL_DEPTH_TEST);
 78 
 79     // build and compile our shader zprogram
 80     // ------------------------------------
 81     Shader lightingShader("colors.vs", "colors.fs");
 82     Shader lampShader("lamp.vs", "lamp.fs");
 83 
 84     // set up vertex data (and buffer(s)) and configure vertex attributes
 85     // ------------------------------------------------------------------
 86     float vertices[] = {
 87         -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
 88         0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
 89         0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
 90         0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
 91         -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
 92         -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
 93 
 94         -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
 95         0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
 96         0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
 97         0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
 98         -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
 99         -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
100 
101         -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
102         -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
103         -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
104         -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
105         -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
106         -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
107 
108         0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
109         0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
110         0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
111         0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
112         0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
113         0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
114 
115         -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
116         0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
117         0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
118         0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
119         -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
120         -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
121 
122         -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
123         0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
124         0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
125         0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
126         -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
127         -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
128     };
129 
130     unsigned int VBO, cubeVAO;
131     glGenVertexArrays(1, &cubeVAO);
132     glGenBuffers(1, &VBO);
133 
134     glBindVertexArray(cubeVAO);
135 
136     glBindBuffer(GL_ARRAY_BUFFER, VBO);
137     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
138 
139     // position attribute
140     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
141     glEnableVertexAttribArray(0);
142     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
143     glEnableVertexAttribArray(1);
144 
145     unsigned int lightVAO;
146     glGenVertexArrays(1, &lightVAO);
147     glBindVertexArray(lightVAO);
148     // 只需要绑定VBO不用再次设置VBO的数据,因为箱子的VBO数据中已经包含了正确的立方体顶点数据
149     glBindBuffer(GL_ARRAY_BUFFER, VBO);
150     // 设置灯立方体的顶点属性(对我们的灯来说仅仅只有位置数据)
151     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
152     glEnableVertexAttribArray(0);
153 
154     // pass projection matrix to shader (as projection matrix rarely changes there's no need to do this per frame)
155     // -----------------------------------------------------------------------------------------------------------
156     //glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
157     //ourShader.setMat4("projection", projection);
158 
159 
160     // render loop
161     // -----------
162     while (!glfwWindowShouldClose(window))
163     {
164         float currentFrame = glfwGetTime();
165         deltaTime = currentFrame - lastFrame;
166         lastFrame = currentFrame;
167 
168         // input
169         // -----
170         processInput(window);
171 
172         // render
173         // ------
174         glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
175         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
176 
177         // activate shader
178         lightingShader.use();
179         lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
180         lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
181         lightingShader.setVec3("lightPos", lightPos);
182         lightingShader.setVec3("viewPos", camera.Position);
183 
184         // pass projection matrix to shader (note that in this case it could change every frame)
185         glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
186         lightingShader.setMat4("projection", projection);
187 
188         // camera/view transformation
189         glm::mat4 view = camera.GetViewMatrix();
190         lightingShader.setMat4("view", view);
191 
192         glm::mat4 model = glm::mat4(1.0);
193         lightingShader.setMat4("model", model);
194         // render boxes
195         glBindVertexArray(cubeVAO);
196         glDrawArrays(GL_TRIANGLES, 0, 36);
197 
198         lampShader.use();
199         lampShader.setMat4("projection", projection);
200         lampShader.setMat4("view", view);
201         model = glm::mat4(1.0f);
202         float r = 5.0f;
203         float x = sin(glfwGetTime())*r;
204         float z = cos(glfwGetTime())*r;
205         lightPos.x = x; lightPos.z = z;
206         model = glm::translate(model, lightPos);
207         model = glm::scale(model, glm::vec3(0.2f));
208         lampShader.setMat4("model", model);
209 
210         glBindVertexArray(lightVAO);
211         glDrawArrays(GL_TRIANGLES, 0, 36);
212 
213         // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
214         // -------------------------------------------------------------------------------
215         glfwSwapBuffers(window);
216         glfwPollEvents();
217     }
218 
219     // optional: de-allocate all resources once they've outlived their purpose:
220     // ------------------------------------------------------------------------
221     glDeleteVertexArrays(1, &cubeVAO);
222     glDeleteVertexArrays(1, &lightVAO);
223     glDeleteBuffers(1, &VBO);
224 
225     // glfw: terminate, clearing all previously allocated GLFW resources.
226     // ------------------------------------------------------------------
227     glfwTerminate();
228     return 0;
229 }
230 
231 // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
232 // ---------------------------------------------------------------------------------------------------------
233 void processInput(GLFWwindow *window)
234 {
235     if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
236         glfwSetWindowShouldClose(window, true);
237 
238     if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
239         camera.ProcessKeyboard(FORWARD, deltaTime);
240     if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
241         camera.ProcessKeyboard(BACKWARD, deltaTime);
242     if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
243         camera.ProcessKeyboard(LEFT, deltaTime);
244     if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
245         camera.ProcessKeyboard(RIGHT, deltaTime);
246 }
247 
248 // glfw: whenever the window size changed (by OS or user resize) this callback function executes
249 // ---------------------------------------------------------------------------------------------
250 void framebuffer_size_callback(GLFWwindow* window, int width, int height)
251 {
252     // make sure the viewport matches the new window dimensions; note that width and 
253     // height will be significantly larger than specified on retina displays.
254     glViewport(0, 0, width, height);
255 }
256 
257 void mouse_callback(GLFWwindow* window, double xpos, double ypos){
258     if (firstMouse)
259     {
260         lastX = xpos;
261         lastY = ypos;
262         firstMouse = false;
263     }
264 
265     float xoffset = xpos - lastX;
266     float yoffset = lastY - ypos;
267     //std::cout << ypos << std::endl;
268     lastX = xpos;
269     lastY = ypos;
270 
271     camera.ProcessMouseMovement(xoffset, yoffset);
272 }
273 
274 // glfw: whenever the mouse scroll wheel scrolls, this callback is called
275 // ----------------------------------------------------------------------
276 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
277 {
278     camera.ProcessMouseScroll(yoffset);
279 }
View Code

2019/11/29

原文地址:https://www.cnblogs.com/ljy08163268/p/11961008.html