前言
本文为计算机图形学实验汇总,实验采用glad与glfw编写,代码还有很多不完善的地方。不要抄袭,代码仅供参考。
- 这些实验完成时间跨度较大,部分代码进行了二次重构,但是实验内可能仍然有不同的写法,希望参考代码后,自己编写的代码可以对其进行完善与统一。可以将画线、画多边形等操作合理封装,形成一个完善的图形学头文件甚至名称空间,这样对后续实验的进行有很大的帮助,同时代码也会显得更加美观。
- 由于我是第一次使用glfw,部分用法可能不太合理或有更好的解决方案。
glfw的学习网站是 LearnOpenGl , 很多人使用的是glut,虽然glfw的学习成本比glut要大一些(亿些),但是glut是已经停止维护20多年了,现在最新的用法是glfw+glad,既然要学OpenGL,那么为什么不学最新的?在实际写代码的过程中,你会发现图形学实验还是很有意思的,希望大家认真对待。
想要完成下面代码,基本上入门部分学一半就够了, 更高级的如果有兴趣可以学一下,学习网站最后的实验也可以做一下,成品看起来还是很好玩的。
笔记当时都是用latex写的,很多语句csdn不支持,因此大部分为截图(懒得整理了)。
注意:我是在mac上运行的代码,编译器采用的是clion,其他环境应该也没啥问题。
实验基本要求
作业题目 | 内容要求 |
---|---|
画线算法(判别式) | 支持用户交互输入/移动/修改两端点;算法遵循“判别式”的精神,没有取整操作,没有浮点数的乘法。 |
Liang-Barsky裁剪算法 | 支持用户交互输入/移动/修改两端点;算法遵循“直线段参数化”的精神,实时画出直线。请注意:画线的命令可以调用现成的API(而不是逐像素地画)。 |
多边形被矩阵窗口裁剪 | 窗口可固定;支持用户输入任意复杂多边形;输出的多边形边界必须完整(可不填充);不包括重复顶点和重复边。 |
扫描线填充多边形 | 支持用户输入任意复杂多边形 |
交互Bezier曲线 | 支持insert/delete/move控制点; 基于De Casteljau’s割角算法;同时画出控制顶点/控制多边形/样条曲线。 |
交互B样条 | 基于de boor割角算法;支持insert/delete/move控制点;支持修改阶数;同时画出控制顶点/控制多边形/样条曲线。 |
交互显示测地距离场 | 基于libigl显示一个三维模型,用鼠标选中一个顶点,使用纹理图片显示距离场效果。距离场算法代码请使用这个,如果你不懂,请阅读readme |
程序的演示方法在代码中很容易看出。
公共代码相关
CmakeList.txt
cmake_minimum_required(VERSION 3.14)
project(ComputerGraphics)
set(CMAKE_CXX_STANDARD 14)
# 添加头文件
set(GLFW_H /usr/local/Cellar/glfw/3.3.2/include/GLFW)
set(GLAD_H /usr/local/include/glad)
set(KH_H /usr/local/include/KHR)
include_directories(${GLFW_H} ${GLAD_H} ${KH_H})
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
find_package(GLUT REQUIRED)
include_directories(${GLUT_INCLUDE_DIR})
# 添加目标链接
#set(GLEW_LINK /usr/local/Cellar/glew/2.1.0_1/lib/libGLEW.2.1.0.dylib)
set(GLFW_LINK /usr/local/Cellar/glfw/3.3.2/lib/libglfw.3.dylib)
set(CMAKE_CXX_FLAGS "-g -Wall")
link_libraries(${OPENGL} ${GLFW_LINK})
# 执行编译命令
set(SOURCE_FILES0 "glad.c" LearnOpenGl.cpp)
set(SOURCE_FILES1 "glad.c" LearnOpenGL_template.cpp)
set(SOURCE_FILES2 "glad.c" LiangBarsky.cpp)
set(SOURCE_FILES3 "glad.c" Scan_Line.cpp)
set(SOURCE_FILES4 "glad.c" Bezier.cpp)
set(SOURCE_FILES5 "glad.c" Bresenham.cpp)
set(SOURCE_FILES6 "glad.c" B_spline.cpp)
set(SOURCE_FILES7 "glad.c" SutherlandHodgeman.cpp)
set(SOURCE_FILES8 "glad.c" DistanceField.cpp)
set(SOURCE_FILES9 "glad.c" test9.cpp)
add_executable(LearnOpenGl ${SOURCE_FILES0} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(LearnOpenGL_template ${SOURCE_FILES1} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(LiangBarsky ${SOURCE_FILES2} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(Scan_Line ${SOURCE_FILES3} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(Bezier ${SOURCE_FILES4} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(Bresenham ${SOURCE_FILES5} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(B_spline ${SOURCE_FILES6} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(SutherlandHodgeman ${SOURCE_FILES7} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(DistanceField ${SOURCE_FILES8} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
add_executable(test9 ${SOURCE_FILES9} ${GLUT_LIBRARY} ${OPENGL_LIBRARY})
if (APPLE)
target_link_libraries(LearnOpenGl "-framework OpenGL" "-framework GLUT")
target_link_libraries(LearnOpenGL_template "-framework OpenGL" "-framework GLUT")
target_link_libraries(LiangBarsky "-framework OpenGL" "-framework GLUT")
target_link_libraries(Scan_Line "-framework OpenGL" "-framework GLUT")
target_link_libraries(Bezier "-framework OpenGL" "-framework GLUT")
target_link_libraries(Bresenham "-framework OpenGL" "-framework GLUT")
target_link_libraries(B_spline "-framework OpenGL" "-framework GLUT")
target_link_libraries(SutherlandHodgeman "-framework OpenGL" "-framework GLUT")
target_link_libraries(DistanceField "-framework OpenGL" "-framework GLUT")
target_link_libraries(test9 "-framework OpenGL" "-framework GLUT")
endif()
顶点着色器代码:shader.vs
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 ourColor;
void main(){
gl_Position = vec4(aPos, 1.0);
}
片段着色器代码:shader.fs
#version 330 core
out vec4 FragColor;
uniform vec4 ourColor;
void main(){
FragColor = ourColor;
}
着色器类:shader.h
#ifndef COMPUTERGRAPHICS_SHADER_H
#define COMPUTERGRAPHICS_SHADER_H
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
class Shader{
public:
unsigned int ID;//程序ID
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr){//顶点着色器,片段着色器,几何着色器
string vertexCode;//存储着色器代码
string fragmentCode;
string geometryCode;
ifstream vShaderFile;
ifstream fShaderFile;
ifstream gShaderFile;
//保证如果打开失败可以抛出异常
vShaderFile.exceptions (ifstream::failbit | ifstream::badbit);
fShaderFile.exceptions (ifstream::failbit | ifstream::badbit);
gShaderFile.exceptions (ifstream::failbit | ifstream::badbit);
try{
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
vShaderFile.close();
fShaderFile.close();
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
if(geometryPath != nullptr){
gShaderFile.open(geometryPath);
stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
}
catch (ifstream::failure& e){
cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << endl;
}
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
//创建和编译顶点着色器
unsigned int vertex = glCreateShader(GL_VERTEX_SHADER);//创建一个顶点着色器
glShaderSource(vertex, 1, &vShaderCode, nullptr);//将顶点着色器源码附加到着色器对象上
glCompileShader(vertex);//编译这个着色器对象
checkCompileErrors(vertex, "VERTEX");//检查错误
unsigned int fragment = glCreateShader(GL_FRAGMENT_SHADER);//创建一个片段着色器
glShaderSource(fragment, 1, &fShaderCode, nullptr);//将片段着色器源码附加到着色器对象上
glCompileShader(fragment);//编译这个着色器对象
checkCompileErrors(fragment, "FRAGMENT");//检查错误
unsigned int geometry;
if(geometryPath != nullptr){//如果有几何着色器,则重复上述步骤
const char * gShaderCode = geometryCode.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, nullptr);
glCompileShader(geometry);
checkCompileErrors(geometry, "GEOMETRY");
}
ID = glCreateProgram();//创建一个着色器程序对象
glAttachShader(ID, vertex);//将顶点着色器对象附加到程序对象上
glAttachShader(ID, fragment);//将片段着色器对象附加到程序对象上
if(geometryPath != nullptr)
glAttachShader(ID, geometry);
glLinkProgram(ID);//链接着色器
checkCompileErrors(ID, "PROGRAM");//检查链接错误
glDeleteShader(vertex);//删除之前不需要的着色器对象
glDeleteShader(fragment);
if(geometryPath != nullptr)
glDeleteShader(geometry);
}
void use(){//激活着色器对象
glUseProgram(ID);
}
//uniform工具函数
void setBool(const string &name, bool value) const{//name是一个uniform的值
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void setInt(const string &name, int value) const{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void setFloat(const string &name, float value) const{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void setVec2(const string &name, const glm::vec2 &value) const{
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec2(const string &name, float x, float y) const{
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}
void setVec3(const string &name, const glm::vec3 &value) const{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec3(const string &name, float x, float y, float z) const{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
void setVec4(const string &name, const glm::vec4 &value) const{
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec4(const string &name, float x, float y, float z, float w){
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}
void setMat2(const string &name, const glm::mat2 &mat) const{
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
void setMat3(const string &name, const glm::mat3 &mat) const{
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
void setMat4(const string &name, const glm::mat4 &mat) const{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
private:
void checkCompileErrors(GLuint shader, string type){//错误检查
GLint success;
GLchar infoLog[1024];
if(type != "PROGRAM"){
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(shader, 1024, nullptr, infoLog);
cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << endl;
}
}
else{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if(!success){
glGetProgramInfoLog(shader, 1024, nullptr, infoLog);
cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << endl;
}
}
}
};
#endif //COMPUTERGRAPHICS_SHADER_H