CHEN Yihui 5 years ago
parent
commit
b8e0fb8e95
6 changed files with 158 additions and 25 deletions
  1. 2 0
      .gitignore
  2. 2 1
      build_run.sh
  3. 85 6
      fshader71.glsl
  4. 32 2
      main.cc
  5. 11 7
      readme.txt
  6. 26 9
      vshader71.glsl

+ 2 - 0
.gitignore

@@ -1,3 +1,5 @@
 # obj, bin files
 *.obj
 *.out
+# build dir
+build/

+ 2 - 1
build.sh → build_run.sh

@@ -3,4 +3,5 @@ mkdir -p build
 cd build
 cmake ..
 make -j
-cd ..
+cd ..
+build/flying

+ 85 - 6
fshader71.glsl

@@ -1,22 +1,101 @@
 
 #version 150
 
-in  vec4 color;
-in  vec2 texCoord;
-in  float fog_factor;
+in vec2 texCoord;
+in float fog_factor;
+
+// per-fragment interpolated values from the vertex shader
+in vec3 fN0;
+in vec3 fL0;
+in vec3 fE0;
+in vec3 fN1;
+in vec3 fL1;
+in vec3 fE1;
+
 out vec4 fColor;
 
 uniform sampler2D tex;
 
+uniform float plane_light_on;
+
 void main() {
+  vec4 material_ambient;
+  vec4 material_diffuse;
+  vec4 material_specular;
+  float material_shininess;
   if (texCoord.x > 10) { // cow
     fColor = vec4(0.1, 0.1, 0.1, 1);
+    material_ambient = fColor;
+    material_diffuse = vec4(1.0, 0.8, 0.0, 1.0);
+    material_specular = vec4(1.0, 0.0, 1.0, 1.0);
+    material_shininess = 50.0;
+  } else { // tex
+    fColor = texture(tex, texCoord);
+    material_ambient = fColor;
+    material_diffuse = fColor;
+    material_specular = vec4(0.0, 0.0, 0.0, 0.0);
+    material_shininess = 0.0;
+  }
+
+  // Normalize the input lighting vectors
+
+  vec4 light0_ambient = vec4(0.2, 0.2, 0.2, 1.0);
+  vec4 light0_diffuse = vec4(1.0, 1.0, 1.0, 1.0);
+  vec4 light0_specular = vec4(1.0, 1.0, 1.0, 1.0);
+
+  vec4 ambient_product0 = light0_ambient * material_ambient;
+  vec4 diffuse_product0 = light0_diffuse * material_diffuse;
+  vec4 specular_product0 = light0_specular * material_specular;
+
+  vec3 N0 = normalize(fN0);
+  vec3 E0 = normalize(fE0);
+  vec3 L0 = normalize(fL0);
+  vec3 H0 = normalize(L0 + E0);
+
+  vec4 ambient0 = ambient_product0;
+
+  float Kd0 = max(dot(L0, N0), 0.0);
+  vec4 diffuse0 = Kd0 * diffuse_product0;
+
+  float Ks0 = pow(max(dot(N0, H0), 0.0), material_shininess);
+  vec4 specular0 = Ks0 * specular_product0;
+
+  // discard the specular highlight if the light's behind the vertex
+  if (dot(L0, N0) < 0.0) {
+    specular0 = vec4(0.0, 0.0, 0.0, 1.0);
   }
-  else { // tex
-    fColor = color * texture(tex, texCoord);
+
+  vec4 light1_ambient = vec4(0.2, 0.2, 0.2, 1.0);
+  vec4 light1_diffuse = vec4(1.0, 1.0, 1.0, 1.0);
+  vec4 light1_specular = vec4(1.0, 1.0, 1.0, 1.0);
+
+  vec4 ambient_product1 = light1_ambient * material_ambient;
+  vec4 diffuse_product1 = light1_diffuse * material_diffuse;
+  vec4 specular_product1 = light1_specular * material_specular;
+
+  vec3 N1 = normalize(fN1);
+  vec3 E1 = normalize(fE1);
+  vec3 L1 = normalize(fL1);
+  vec3 H1 = normalize(L1 + E1);
+
+  vec4 ambient1 = ambient_product0;
+
+  float Kd1 = max(dot(L1, N1), 0.0);
+  vec4 diffuse1 = Kd1 * diffuse_product1;
+
+  float Ks1 = pow(max(dot(N1, H1), 0.0), material_shininess);
+  vec4 specular1 = Ks1 * specular_product0;
+
+  // discard the specular highlight if the light's behind the vertex
+  if (dot(L1, N1) < 0.0) {
+    specular1 = vec4(0.0, 0.0, 0.0, 1.0);
   }
 
+  fColor = 0.5 * (plane_light_on * (ambient0 + diffuse0 + specular0) +
+                  (ambient1 + diffuse1 + specular1));
+  fColor.a = 1.0;
+
   // fog
   vec4 fogColor = vec4(0.5, 0.5, 0.5, 1);
   fColor = fColor * fog_factor + fogColor * (1 - fog_factor);
-} 
+}

+ 32 - 2
main.cc

@@ -27,6 +27,11 @@ GLubyte image[TextureWidth][TextureHeight][3];
 // Vertex data arrays
 point4 points[NumVertices];
 vec2 tex_coords[NumVertices];
+vec3 normals[NumVertices];
+
+// plane light params
+GLuint plane_light;
+GLfloat light_on = 1.0f;
 
 // fog params
 GLuint fog; // is_foggy uniform
@@ -102,7 +107,7 @@ void load_model(const std::string &file_name, bool not_tex = false,
         vertices.emplace_back(x / 50.0f + x_offset, z / 50.0f + z_offset,
                               y / 50.0f + y_offset, 1.0);
         if (!not_tex) {
-          *(reinterpret_cast<float*>(ter_alt) + idx) = y / 50.0f;
+          *(reinterpret_cast<float *>(ter_alt) + idx) = y / 50.0f;
           idx++;
         }
       } else if (t == "vt") {
@@ -113,7 +118,10 @@ void load_model(const std::string &file_name, bool not_tex = false,
         a--;
         b--;
         c--;
+        vec3 normal = normalize(
+            cross(vertices[b] - vertices[a], vertices[c] - vertices[b]));
         points[index] = vertices[a];
+        normals[index] = normal;
         if (not_tex) {
           tex_coords[index] = {20.0, 0.0};
         } else {
@@ -121,6 +129,7 @@ void load_model(const std::string &file_name, bool not_tex = false,
         }
         index++;
         points[index] = vertices[b];
+        normals[index] = normal;
         if (not_tex) {
           tex_coords[index] = {20.0, 0.0};
         } else {
@@ -128,6 +137,7 @@ void load_model(const std::string &file_name, bool not_tex = false,
         }
         index++;
         points[index] = vertices[c];
+        normals[index] = normal;
         if (not_tex) {
           tex_coords[index] = {20.0, 0.0};
         } else {
@@ -187,7 +197,8 @@ void init() {
   GLuint buffer;
   glGenBuffers(1, &buffer);
   glBindBuffer(GL_ARRAY_BUFFER, buffer);
-  glBufferData(GL_ARRAY_BUFFER, sizeof(points) + sizeof(tex_coords), NULL,
+  glBufferData(GL_ARRAY_BUFFER,
+               sizeof(points) + sizeof(tex_coords) + sizeof(normals), NULL,
                GL_STATIC_DRAW);
 
   // Specify an offset to keep track of where we're placing data in our
@@ -198,6 +209,9 @@ void init() {
   offset += sizeof(points);
 
   glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(tex_coords), tex_coords);
+  offset += sizeof(tex_coords);
+
+  glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(normals), normals);
 
   // Load shaders and use the resulting shader program
   GLuint program = InitShader("vshader71.glsl", "fshader71.glsl");
@@ -215,6 +229,12 @@ void init() {
   glEnableVertexAttribArray(vTexCoord);
   glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0,
                         BUFFER_OFFSET(offset));
+  offset += sizeof(tex_coords);
+
+  GLuint vNormal = glGetAttribLocation(program, "vNormal");
+  glEnableVertexAttribArray(vNormal);
+  glVertexAttribPointer(vNormal, 3, GL_FLOAT, GL_FALSE, 0,
+                        BUFFER_OFFSET(offset));
 
   // Set the value of the fragment shader texture sampler variable
   //   ("texture") to the the appropriate texture unit. In this case,
@@ -225,6 +245,7 @@ void init() {
   projection = glGetUniformLocation(program, "projection");
   fog = glGetUniformLocation(program, "foggy");
   eye_pos = glGetUniformLocation(program, "eye_pos");
+  plane_light = glGetUniformLocation(program, "plane_light_on");
   glEnable(GL_DEPTH_TEST);
 
   glClearColor(1, 1, 1, 1);
@@ -250,6 +271,8 @@ void display(void) {
 
   glUniform1i(fog, foggy);
 
+  glUniform1f(plane_light, light_on);
+
   glDrawArrays(GL_TRIANGLES, 0, NumVertices);
 
   glutSwapBuffers();
@@ -270,6 +293,13 @@ void keyboard(unsigned char key, int mousex, int mousey) {
   case 033: // Escape Key
     exit(0);
     break;
+  case 'l':
+    if (light_on > 0.0) {
+      light_on = 0.0;
+    } else {
+      light_on = 1.0;
+    }
+    break;
   case 'f':
     if (foggy > 0) {
       foggy = 0;

+ 11 - 7
readme.txt

@@ -10,10 +10,12 @@
     gc_tex.obj
     gc_tex.ppm
     cow.obj
-  编译
-    ./build.sh
-  运行
-    ./main.out
+  编译运行
+    直接编译运行
+      g++ main.cc InitShader.cpp -I. -lGL -lGLEW -lglut -o main.out
+      ./main.out
+    使用cmake
+      ./build_run.sh
   操作
     w,a,s,d:控制观察者x,y位置(和看的方向等没关系)
     9,6:控制观察者z位置(升降)
@@ -33,10 +35,12 @@
     物体的纹理坐标都设成一个特殊坐标,
     在片段着色器中增加判断(区分地形和物体),如果纹理坐标是特殊坐标,则涂特殊的颜色
   光照
+    光照1:随飞机移动,点光源
+    光照2:在地图中心上方,平行光源
     顶点法向用cpu预先计算,存在glBuffer里,
-    顶点光照在顶点着色器里计算,
-    面的法向在顶点着色器里计算
-    面的光照在片段着色器里计算
+    (在每个三角形的顶点法相是相同的,但计算镜面光时的向量对于每个顶点是不同的)
+    光的参数,材料参数写在片段着色器里
+    假设材料参数对两种光相同,其中地形没有镜光,牛有较高镜面
     使用uniform变量,传输是否有雾(int),及眼睛位置(vec3)到顶点着色器,
     在顶点着色器里根据距离(的平方)计算雾化参数(使用指数),若没雾直接输出雾化参数1

+ 26 - 9
vshader71.glsl

@@ -1,11 +1,18 @@
 #version 150
 
-in  vec4 vPosition;
-in  vec2 vTexCoord;
+in vec4 vPosition;
+in vec2 vTexCoord;
+in vec3 vNormal;
 
-out vec4 color;
 out vec2 texCoord;
 out float fog_factor;
+// output values that will be interpretated per-fragment
+out vec3 fN0;
+out vec3 fE0;
+out vec3 fL0;
+out vec3 fN1;
+out vec3 fE1;
+out vec3 fL1;
 
 uniform int foggy;
 uniform vec3 eye_pos;
@@ -13,16 +20,26 @@ uniform mat4 model_view;
 uniform mat4 projection;
 
 void main() {
-  color       = vec4(1.0, 1.0, 1.0, 1.0);
-  texCoord    = vTexCoord;
-  gl_Position = projection * model_view *  vPosition / vPosition.w;
+  texCoord = vTexCoord;
+  gl_Position = projection * model_view * vPosition / vPosition.w;
 
+  // light0
+  vec4 LightPosition0 = vec4(eye_pos.x, eye_pos.y, eye_pos.z, 1.0);
+  fN0 = vNormal;
+  fE0 = -(model_view * vPosition).xyz;
+  fL0 = LightPosition0.xyz - (model_view * vPosition).xyz;
+
+  // light1
+  vec4 LightPosition1 = vec4(0.5, 0.25, 10, 0.0);
+  fN1 = vNormal;
+  fE1 = -(model_view * vPosition).xyz;
+  fL1 = LightPosition1.xyz;
   // fog
   if (foggy > 0) {
     // distance
-    float dis = (vPosition.x - eye_pos.x) * (vPosition.x - eye_pos.x)
-              + (vPosition.y - eye_pos.y) * (vPosition.y - eye_pos.y)
-              + (vPosition.z - eye_pos.z) * (vPosition.z - eye_pos.z);
+    float dis = (vPosition.x - eye_pos.x) * (vPosition.x - eye_pos.x) +
+                (vPosition.y - eye_pos.y) * (vPosition.y - eye_pos.y) +
+                (vPosition.z - eye_pos.z) * (vPosition.z - eye_pos.z);
     fog_factor = exp(-dis);
   } else { // not foggy
     fog_factor = 1.0;