【计算机图形学-11】OpenGL程序实例分析4——Phong着色

本小节实现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;
	}
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值