本小节实现Phong着色。Phong着色的核心是片元着色器的设置,如果将片元着色器的设置搬到顶点着色器中,则变成光滑着色。
TriMesh.cpp:
#include "TriMesh.h"
// 一些基础颜色
const vec3 basic_colors[8] = {
vec3(1.0, 1.0, 1.0), // White
vec3(1.0, 1.0, 0.0), // Yellow
vec3(0.0, 1.0, 0.0), // Green
vec3(0.0, 1.0, 1.0), // Cyan
vec3(1.0, 0.0, 1.0), // Magenta
vec3(1.0, 0.0, 0.0), // Red
vec3(0.0, 0.0, 0.0), // Black
vec3(0.0, 0.0, 1.0) // Blue
};
// 立方体的各个点
const vec3 cube_vertices[8] = {
vec3(-0.5, -0.5, -0.5),
vec3(0.5, -0.5, -0.5),
vec3(-0.5, 0.5, -0.5),
vec3(0.5, 0.5, -0.5),
vec3(-0.5, -0.5, 0.5),
vec3(0.5, -0.5, 0.5),
vec3(-0.5, 0.5, 0.5),
vec3(0.5, 0.5, 0.5)
};
// 三角形的点
const vec3 triangle_vertices[3] = {
vec3(-0.5, -0.5, 0.0),
vec3(0.5, -0.5, 0.0),
vec3(0.0, 0.5, 0.0)
};
// 正方形平面
const vec3 square_vertices[4] = {
vec3(-0.5, -0.5, 0.0),
vec3(0.5, -0.5, 0.0),
vec3(0.5, 0.5, 0.0),
vec3(-0.5, 0.5, 0.0),
};
TriMesh::TriMesh()
{
}
TriMesh::~TriMesh()
{
}
std::vector<vec3> TriMesh::getVertexPositions()
{
return vertex_positions;
}
std::vector<vec3> TriMesh::getVertexColors()
{
return vertex_colors;
}
std::vector<vec3> TriMesh::getVertexNormals()
{
return vertex_normals;
}
std::vector<vec3i> TriMesh::getFaces()
{
return faces;
}
std::vector<vec3> TriMesh::getPoints()
{
return points;
}
std::vector<vec3> TriMesh::getColors()
{
return colors;
}
std::vector<vec3> TriMesh::getNormals()
{
return normals;
}
void TriMesh::computeTriangleNormals()
{
// 这里的resize函数会给face_normals分配一个和faces一样大的空间
face_normals.resize(faces.size());
for (size_t i = 0; i < faces.size(); i++) {
auto& face = faces[i];
// 计算每个面片的法向量并归一化
vec3 norm;
face_normals[i] = cross((vertex_positions[face.y]- vertex_positions[face.x]), (vertex_positions[face.z] - vertex_positions[face.x]));
face_normals[i] = normalize(face_normals[i]);
// face_normals[i] = norm;
}
}
void TriMesh::computeVertexNormals()
{
// 计算面片的法向量
if (face_normals.size() == 0 && faces.size() > 0) {
computeTriangleNormals();
}
// 这里的resize函数会给vertex_normals分配一个和vertex_positions一样大的空间
// 并初始化法向量为0
vertex_normals.resize(vertex_positions.size(), vec3(0, 0, 0));
// 求法向量均值
for (size_t i = 0; i < faces.size(); i++) {
auto& face = faces[i];
vertex_normals[face.x] += face_normals[i];
vertex_normals[face.y] += face_normals[i];
vertex_normals[face.z] += face_normals[i];
}
// 对累加的法向量并归一化
for (size_t i = 0; i < vertex_normals.size(); i++) {
vertex_normals[i] = normalize(vertex_normals[i] / length(vertex_normals[i]));
}
}
vec3 TriMesh::getTranslation()
{
return translation;
}
vec3 TriMesh::getRotation()
{
return rotation;
}
vec3 TriMesh::getScale()
{
return scale;
}
mat4 TriMesh::getModelMatrix()
{
return Translate( getTranslation())*
RotateZ( getRotation()[2])*
RotateY( getRotation()[1])*
RotateX( getRotation()[0])*
Scale( getScale() );
}
void TriMesh::setTranslation(vec3 translation)
{
this->translation = translation;
}
void TriMesh::setRotation(vec3 rotation)
{
this->rotation= rotation;
}
void TriMesh::setScale(vec3 scale)
{
this->scale = scale;
}
vec4 TriMesh::getAmbient() { return ambient; };
vec4 TriMesh::getDiffuse() { return diffuse; };
vec4 TriMesh::getSpecular() { return specular; };
float TriMesh::getShininess() { return shininess; };
void TriMesh::setAmbient(vec4 _ambient) { ambient = _ambient; };
void TriMesh::setDiffuse(vec4 _diffuse) { diffuse = _diffuse; };
void TriMesh::setSpecular(vec4 _specular) { specular = _specular; };
void TriMesh::setShininess(float _shininess) { shininess = _shininess; };
void TriMesh::cleanData() {
vertex_positions.clear();
vertex_colors.clear();
vertex_normals.clear();
faces.clear();
face_normals.clear();
points.clear();
colors.clear();
normals.clear();
}
void TriMesh::storeFacesPoints() {
// 计算法向量
if (vertex_normals.size() == 0)
computeVertexNormals();
// 根据每个三角面片的顶点下标存储要传入GPU的数据
for (int i = 0; i < faces.size(); i++)
{
// 坐标
points.push_back(vertex_positions[faces[i].x]);
points.push_back(vertex_positions[faces[i].y]);
points.push_back(vertex_positions[faces[i].z]);
// 颜色
colors.push_back(vertex_colors[faces[i].x]);
colors.push_back(vertex_colors[faces[i].y]);
colors.push_back(vertex_colors[faces[i].z]);
// 法向量
if (vertex_normals.size() != 0) {
normals.push_back(vertex_normals[faces[i].x]);
normals.push_back(vertex_normals[faces[i].y]);
normals.push_back(vertex_normals[faces[i].z]);
}
}
}
// 立方体生成12个三角形的顶点索引
void TriMesh::generateCube() {
// 创建顶点前要先把那些vector清空
cleanData();
// 存储立方体的各个面信息
for (int i = 0; i < 8; i++)
{
vertex_positions.push_back(cube_vertices[i]);
vertex_colors.push_back(basic_colors[i]);
}
// 每个三角面片的顶点下标
faces.push_back(vec3i(0, 1, 3));
faces.push_back(vec3i(0, 3, 2));
faces.push_back(vec3i(1, 4, 5));
faces.push_back(vec3i(1, 0, 4));
faces.push_back(vec3i(4, 0, 2));
faces.push_back(vec3i(4, 2, 6));
faces.push_back(vec3i(5, 6, 4));
faces.push_back(vec3i(5, 7, 6));
faces.push_back(vec3i(2, 6, 7));
faces.push_back(vec3i(2, 7, 3));
faces.push_back(vec3i(1, 5, 7));
faces.push_back(vec3i(1, 7, 3));
storeFacesPoints();
}
void TriMesh::generateTriangle(vec3 color)
{
// 创建顶点前要先把那些vector清空
cleanData();
for (int i = 0; i < 3; i++)
{
vertex_positions.push_back(triangle_vertices[i]);
vertex_colors.push_back(color);
}
// 每个三角面片的顶点下标
faces.push_back(vec3i(0, 1, 2));
storeFacesPoints();
}
void TriMesh::generateSquare(vec3 color)
{
// 创建顶点前要先把那些vector清空
cleanData();
for (int i = 0; i < 4; i++)
{
vertex_positions.push_back(square_vertices[i]);
vertex_colors.push_back(color);
}
// 每个三角面片的顶点下标
faces.push_back(vec3i(0, 1, 2));
faces.push_back(vec3i(0, 2, 3));
storeFacesPoints();
}
void TriMesh::readOff(const std::string& filename)
{
// fin打开文件读取文件信息
if (filename.empty())
{
return;
}
std::ifstream fin;
fin.open(filename);
if (!fin)
{
printf("File on error\n");
return;
}
else
{
printf("File open success\n");
cleanData();
int nVertices, nFaces, nEdges;
// 读取OFF字符串
std::string str;
fin >> str;
// 读取文件中顶点数、面片数、边数
fin >> nVertices >> nFaces >> nEdges;
// 根据顶点数,循环读取每个顶点坐标
for (int i = 0; i < nVertices; i++)
{
vec3 tmp_node;
fin >> tmp_node.x >> tmp_node.y >> tmp_node.z;
vertex_positions.push_back(tmp_node);
vertex_colors.push_back(tmp_node);
}
// 根据面片数,循环读取每个面片信息,并用构建的vec3i结构体保存
for (int i = 0; i < nFaces; i++)
{
int num, a, b, c;
// num记录此面片由几个顶点构成,a、b、c为构成该面片顶点序号
fin >> num >> a >> b >> c;
faces.push_back(vec3i(a, b, c));
}
}
fin.close();
storeFacesPoints();
};
// Light
mat4 Light::getShadowProjectionMatrix() {
// 这里只实现了Y=0平面上的阴影投影矩阵
float lx, ly, lz;
mat4 modelMatrix = this->getModelMatrix();
vec4 light_position = modelMatrix * this->translation;
lx = light_position[0];
ly = light_position[1];
lz = light_position[2];
return mat4(
-ly, 0.0, 0.0, 0.0,
lx, 0.0, lz, 1.0,
0.0, 0.0, -ly, 0.0,
0.0, 0.0, 0.0, -ly
);
}
main.cpp
#include "Angel.h"
#include "mat.h"
#include "vec.h"
#include "TriMesh.h"
#include "Camera.h"
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int WIDTH = 600;
int HEIGHT = 600;
int mainWindow;
struct openGLObject
{
// 顶点数组对象
GLuint vao;
// 顶点缓存对象
GLuint vbo;
// 着色器程序
GLuint program;
// 着色器文件
std::string vshader;
std::string fshader;
// 着色器变量
GLuint pLocation;
GLuint cLocation;
GLuint nLocation;
// 投影变换变量
GLuint modelLocation;
GLuint viewLocation;
GLuint projectionLocation;
// 阴影变量
GLuint shadowLocation;
};
openGLObject mesh_object;
Light* light = new Light();
TriMesh* mesh = new TriMesh();
Camera* camera = new Camera();
void bindObjectAndData(TriMesh* mesh, openGLObject& object, const std::string &vshader, const std::string &fshader) {
// 创建顶点数组对象
#ifdef __APPLE__ // for MacOS
glGenVertexArraysAPPLE(1, &object.vao); // 分配1个顶点数组对象
glBindVertexArrayAPPLE(object.vao); // 绑定顶点数组对象
#else // for Windows
glGenVertexArrays(1, &object.vao); // 分配1个顶点数组对象
glBindVertexArray(object.vao); // 绑定顶点数组对象
#endif
// 创建并初始化顶点缓存对象
glGenBuffers(1, &object.vbo);
glBindBuffer(GL_ARRAY_BUFFER, object.vbo);
glBufferData(GL_ARRAY_BUFFER,
( mesh->getPoints().size() + mesh->getColors().size() + mesh->getNormals().size() ) * sizeof(vec3),
NULL,
GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh->getPoints().size() * sizeof(vec3), &mesh->getPoints()[0]);
glBufferSubData(GL_ARRAY_BUFFER, mesh->getPoints().size() * sizeof(vec3), mesh->getColors().size() * sizeof(vec3), &mesh->getColors()[0]);
glBufferSubData(GL_ARRAY_BUFFER, (mesh->getPoints().size() + mesh->getColors().size()) * sizeof(vec3), mesh->getNormals().size() * sizeof(vec3), &mesh->getNormals()[0]);
object.vshader = vshader;
object.fshader = fshader;
object.program = InitShader(object.vshader.c_str(), object.fshader.c_str());
// 从顶点着色器中初始化顶点的坐标
object.pLocation = glGetAttribLocation(object.program, "vPosition");
glEnableVertexAttribArray(object.pLocation);
glVertexAttribPointer(object.pLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
// 从顶点着色器中初始化顶点的颜色
object.cLocation = glGetAttribLocation(object.program, "vColor");
glEnableVertexAttribArray(object.cLocation);
glVertexAttribPointer(object.cLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(mesh->getPoints().size() * sizeof(vec3)));
// 从顶点着色器中初始化顶点的法向量
object.nLocation = glGetAttribLocation(object.program, "vNormal");
glEnableVertexAttribArray(object.nLocation);
glVertexAttribPointer(object.nLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET((mesh->getPoints().size() + mesh->getColors().size()) * sizeof(vec3)));
// 获得矩阵位置
object.modelLocation = glGetUniformLocation(object.program, "model");
object.viewLocation = glGetUniformLocation(object.program, "view");
object.projectionLocation = glGetUniformLocation(object.program, "projection");
object.shadowLocation = glGetUniformLocation(object.program, "isShadow");
}
void bindLightAndMaterial(TriMesh* mesh, openGLObject& object, Light* light, Camera* camera) {
// 传递相机的位置
glUniform3fv( glGetUniformLocation(object.program, "eye_position"), 1, vec3(camera->eye[0], camera->eye[1], camera->eye[2]) );
// 传递物体的材质
vec4 meshAmbient = mesh->getAmbient();
vec4 meshDiffuse = mesh->getDiffuse();
vec4 meshSpecular = mesh->getSpecular();
float meshShininess = mesh->getShininess();
glUniform4fv(glGetUniformLocation(object.program, "material.ambient"), 1, meshAmbient);
glUniform4fv(glGetUniformLocation(object.program, "material.diffuse"), 1, meshDiffuse);
glUniform4fv(glGetUniformLocation(object.program, "material.specular"), 1, meshSpecular);
glUniform1f(glGetUniformLocation(object.program, "material.shininess"), meshShininess);
// 传递光源信息
vec4 lightAmbient = light->getAmbient();
vec4 lightDiffuse = light->getDiffuse();
vec4 lightSpecular = light->getSpecular();
vec3 lightPosition = light->getTranslation();
glUniform4fv(glGetUniformLocation(object.program, "light.ambient"), 1, lightAmbient);
glUniform4fv(glGetUniformLocation(object.program, "light.diffuse"), 1, lightDiffuse);
glUniform4fv(glGetUniformLocation(object.program, "light.specular"), 1, lightSpecular);
glUniform3fv(glGetUniformLocation(object.program, "light.position"), 1, lightPosition);
}
void init()
{
std::string vshader, fshader;
// 读取着色器并使用
#ifdef __APPLE__ // for MacOS
vshader = "shaders/vshader_mac.glsl";
fshader = "shaders/fshader_mac.glsl";
#else // for Windows
vshader = "shaders/vshader_win.glsl";
fshader = "shaders/fshader_win.glsl";
#endif
// 设置光源位置
light->setTranslation(vec3(0.0, 0.0, 2.0));
light->setAmbient(vec4(1.0, 1.0, 1.0, 1.0)); // 环境光
light->setDiffuse(vec4(1.0, 1.0, 1.0, 1.0)); // 漫反射
light->setSpecular(vec4(1.0, 1.0, 1.0, 1.0)); // 镜面反射
// 设置物体的旋转位移
mesh->setTranslation(vec3(0.0, 0.0, 0.0));
mesh->setRotation(vec3(0.0, 0.0, 0.0));
mesh->setScale(vec3(1.0, 1.0, 1.0));
// 设置材质
mesh->setAmbient(vec4(0.2, 0.2, 0.2, 1.0)); // 环境光
mesh->setDiffuse(vec4(0.7, 0.7, 0.7, 1.0)); // 漫反射
mesh->setSpecular(vec4(0.2, 0.2, 0.2, 1.0)); // 镜面反射
mesh->setShininess(1.0); //高光系数
// 将物体的顶点数据传递
bindObjectAndData(mesh, mesh_object, vshader, fshader);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 相机矩阵计算
camera->updateCamera();
camera->viewMatrix = camera->getViewMatrix();
camera->projMatrix = camera->getProjectionMatrix(false);
#ifdef __APPLE__ // for MacOS
glBindVertexArrayAPPLE(mesh_object.vao);
#else
glBindVertexArray(mesh_object.vao);
#endif
glUseProgram(mesh_object.program);
// 物体的变换矩阵
mat4 modelMatrix = mesh->getModelMatrix();
// 传递矩阵
glUniformMatrix4fv(mesh_object.modelLocation, 1, GL_TRUE, &modelMatrix[0][0]);
glUniformMatrix4fv(mesh_object.viewLocation, 1, GL_TRUE, &camera->viewMatrix[0][0]);
glUniformMatrix4fv(mesh_object.projectionLocation, 1, GL_TRUE, &camera->projMatrix[0][0]);
// 将着色器变量 isShadow 设置为0,表示正常绘制的颜色,如果是1着表示阴影
glUniform1i(mesh_object.shadowLocation, 0);
// 将材质和光源数据传递给着色器
bindLightAndMaterial(mesh, mesh_object, light, camera);
// 绘制
glDrawArrays(GL_TRIANGLES, 0, mesh->getPoints().size());
glutSwapBuffers();
}
void printHelp()
{
std::cout << "================================================" << std::endl;
std::cout << "Use mouse to controll the light position (drag)." << std::endl;
std::cout << "================================================" << std::endl << std::endl;
std::cout << "Keyboard Usage" << std::endl;
std::cout <<
"[Window]" << std::endl <<
"ESC: Exit" << std::endl <<
"h: Print help message" << std::endl <<
std::endl <<
"[Model]" << std::endl <<
"-: Reset material parameters" << std::endl <<
"1/2/3/!/@/#: Change ambient parameters" << std::endl <<
"4/5/6/$/%/^: (TODO) Change diffuse parameters" << std::endl <<
"7/8/9/&/*/(: (TODO) Change specular parameters" << std::endl <<
"0/): (TODO) Change shininess parameters" << std::endl <<
std::endl <<
"q: Load sphere model" << std::endl <<
"a: Load Pikachu model" << std::endl <<
"w: Load Squirtle model" << std::endl <<
"s: Load sphere_coarse model" << std::endl <<
std::endl <<
"[Camera]" << std::endl <<
"SPACE: Reset camera parameters" << std::endl <<
"u/U: Increase/Decrease the rotate angle" << std::endl <<
"i/I: Increase/Decrease the up angle" << std::endl <<
"o/O: Increase/Decrease the camera radius" << std::endl << std::endl;
}
// 鼠标响应函数
void mouse(int x, int y)
{
// 用鼠标控制光源的位置lightPos,以实时更新光照效果
// 窗口坐标系与图像坐标系转换
float half_winx = WIDTH / 2.0;
float half_winy = HEIGHT / 2.0;
float lx = float(x - half_winx) / half_winx;
float ly = float(HEIGHT - y - half_winy) / half_winy;
vec3 pos = light->getTranslation();
pos.x = lx;
pos.y = ly;
light->setTranslation(pos);
}
void mouseWheel(int button, int dir, int x, int y)
{
vec3 pos = light->getTranslation();
if (dir > 0)
{
pos.z += 0.1;
// std::cout << "far from to light\n";
}
else
{
pos.z -= 0.1;
// std::cout << "close to light\n";
}
light->setTranslation(pos);
}
// 键盘响应函数
void keyboard(unsigned char key, int x, int y)
{
float tmp;
vec4 ambient;
switch (key)
{
// ESC键退出游戏
case 033: exit(EXIT_SUCCESS); break;
case 'h': printHelp(); break;
case 'q':
std::cout << "read sphere.off" << std::endl;
mesh = new TriMesh();
mesh->readOff("./assert/sphere.off");
init();
break;
case 'a':
std::cout << "read Pikachu.off" << std::endl;
mesh = new TriMesh();
mesh->readOff("./assert/Pikachu.off");
init();
break;
case 'w':
std::cout << "read Squirtle.off" << std::endl;
mesh = new TriMesh();
mesh->readOff("./assert/Squirtle.off");
init();
break;
case 's':
std::cout << "read sphere_coarse.off" << std::endl;
mesh = new TriMesh();
mesh->readOff("./assert/sphere_coarse.off");
init();
break;
case '1':
ambient = mesh->getAmbient();
tmp = ambient.x;
ambient.x = std::min(tmp + 0.1, 1.0);
mesh->setAmbient(ambient);
break;
case '2':
ambient = mesh->getAmbient();
tmp = ambient.y;
ambient.y = std::min(tmp + 0.1, 1.0);
mesh->setAmbient(ambient);
break;
case '3':
ambient = mesh->getAmbient();
tmp = ambient.z;
ambient.z = std::min(tmp + 0.1, 1.0);
mesh->setAmbient(ambient);
break;
case '!':
ambient = mesh->getAmbient();
tmp = ambient.x;
ambient.x = std::max(tmp - 0.1, 0.0);
mesh->setAmbient(ambient);
break;
case '@':
ambient = mesh->getAmbient();
tmp = ambient.y;
ambient.y = std::max(tmp - 0.1, 0.0);
mesh->setAmbient(ambient);
break;
case '#':
ambient = mesh->getAmbient();
tmp = ambient.z;
ambient.z = std::max(tmp - 0.1, 0.0);
mesh->setAmbient(ambient);
break;
// 控制调整材质,以实时更新光照效果
case '-':
mesh->setAmbient(vec4(0.2, 0.2, 0.2, 1.0));
mesh->setDiffuse(vec4(0.7, 0.7, 0.7, 1.0));
mesh->setSpecular(vec4(0.2, 0.2, 0.2, 1.0));
mesh->setShininess(1.0);
break;
case '=':
std::cout << "ambient: " << mesh->getAmbient() << std::endl;
std::cout << "diffuse: " << mesh->getDiffuse() << std::endl;
std::cout << "specular: " << mesh->getSpecular() << std::endl;
std::cout << "shininess: " << mesh->getShininess() << std::endl;
break;
case ' ':
cin >> a >> b >> c;
break;
// 通过按键改变相机和投影的参数
default:
camera->keyboard(key, x, y);
break;
}
glutPostRedisplay();
}
void idle(void)
{
glutPostRedisplay();
}
// 重新设置窗口
void reshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
}
void cleanData() {
mesh->cleanData();
delete camera;
camera = NULL;
// 释放内存
delete mesh;
mesh = NULL;
// 删除绑定的对象
#ifdef __APPLE__
glDeleteVertexArraysAPPLE(1, &mesh_object.vao);
#else
glDeleteVertexArrays(1, &mesh_object.vao);
#endif
glDeleteBuffers(1, &mesh_object.vbo);
glDeleteProgram(mesh_object.program);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
// 窗口支持双重缓冲、深度测试、超采样
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(WIDTH, HEIGHT);
mainWindow = glutCreateWindow("Phong-Vertex");
#ifdef __APPLE__
#else
glewExperimental = GL_TRUE;
glewInit();
#endif
mesh->readOff("./assert/sphere.off");
// Init mesh, shaders, buffer
init();
// bind callbacks
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMotionFunc(mouse);
// glutMouseWheelFunc(mouseWheel);
glutIdleFunc(idle);
// 输出帮助信息
printHelp();
// 启用深度测试
glEnable(GL_DEPTH_TEST);
glutMainLoop();
cleanData();
return 0;
}
顶点着色器:
#version 330 core
in vec3 vPosition;
in vec3 vColor;
in vec3 vNormal;
// 模型变换矩阵、相机观察矩阵、投影矩阵
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 position;
out vec3 normal;
void main()
{
vec4 v1 = model * vec4(vPosition, 1.0);
// 由于model矩阵有可能为阴影矩阵,为了得到正确位置,我们需要做一次透视除法
vec4 v2 = vec4(v1.xyz / v1.w, 1.0);
// 考虑相机和投影
vec4 v3 = projection* view * v2;
gl_Position = v3;
position = vec3(v2.xyz);
normal = vec3( model * vec4(vNormal, 0.0) );
}
片元着色器:
#version 330 core
// 给光源数据一个结构体
struct Light{
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec3 position;
};
// 给物体材质数据一个结构体
struct Material{
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
in vec3 position;
in vec3 normal;
// 相机坐标
uniform vec3 eye_position;
// 光源
uniform Light light;
// 物体材质
uniform Material material;
uniform int isShadow;
out vec4 fColor;
void main()
{
if (isShadow == 1) {
fColor = vec4(0.0, 0.0, 0.0, 1.0);
}
else {
// 计算四个归一化的向量 N,V,L,R(或半角向量H)
vec3 N=normalize(normal);
vec3 V=normalize(eye_position-position);
vec3 L=normalize(light.position-position);
vec3 R=reflect(-L,N);
// 环境光分量I_a
vec4 I_a = light.ambient * material.ambient;
// 计算系数和漫反射分量I_d
float diffuse_dot = max(dot(L, N), 0);
vec4 I_d = diffuse_dot * light.diffuse * material.diffuse;
// 计算系数和镜面反射分量I_s
float specular_dot_pow = pow(max(dot(R, V), 0), material.shininess);
vec4 I_s = specular_dot_pow * light.specular * material.specular;
// 注意如果光源在背面则去除高光
if( dot(L, N) < 0.0 ) {
I_s = vec4(0.0, 0.0, 0.0, 1.0);
}
fColor = I_a + I_d + I_s;
fColor.a = 1.0;
}
}