前言
图形学是计算机中很有意思的一块内容,在影视、游戏行业有着大量的应用,图形学的实验也十分有趣,建议仔细研究。
要学习图形学在我看来,一方面是图形学理论的学习,这个就不得不提到Games101 ,老师对此也是大加赞赏,也是少有的不用开倍速学习的网课。
其二是图形学API的学习,这门课使用的是OpenGL,大多同学使用的glut,确实glut比较简单,容易上手,不过glut也是十分古老了,建议使用最新的glfw和glad,可以在learnOpenGL 网站上进行学习,就目前而言,完成以下实验仅需看完入门部分即可。
实验过程中也参考了一位名叫龙征天学长的代码,并且对一些没有实现的功能进行了实现。
实验内容
实验题目 | 内容 |
---|---|
直线与画圆算法 | 实现DDA和Bresenham算法绘制直线和中点画圆法 |
裁剪算法 | 实现Liang-Barsky直线裁剪算法 |
光栅化 | 实现多边形填充、Z-buffering、反走样算法 |
关于代码框架(非最终版本)
使用OpenGL其实可以有一个大体的框架,实验过程中只需要在该框架上进行搭建即可,以下就是后面每个实验需要用到的公共代码(其实主要是着色器),如果现在不知道什么是着色器可以看看之前提到的learnOpenGL入门部分。
片段着色器
shader.fs
#version 330 core
out vec4 FragColor;
uniform vec4 ourColor;
void main()
{
FragColor = ourColor;
}
顶点着色器
shader.vs
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 outColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
}
着色器类
shader.h
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<fstream>
#include<sstream>
#include<cmath>
#include "glad/glad.h"
#include"GLFW/glfw3.h"
#ifndef SHADER_H
#define SHADER_H
using namespace std;
class Shader {
public:
//程序ID
unsigned int ID;
//构造器读取并构建着色器
Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
//使用/激活程序
void use() const;
//uniform工具函数
void setBool(const string & name, bool value) const;
void setInt(const string & name, int value) const;
void setFloat(const string & name, float value) const;
void setVec4(const string &name, float x, float y, float z, float w) const;
private:
char infoLog[512]{};
};
#endif //SHADER_H
shader.cpp
#include "shader.h"
Shader::Shader(const GLchar *vertexPath, const GLchar *fragmentPath) {
//从文件获取顶点/片段着色器
string vertexCode;
string fragmentCode;
ifstream vShaderFile;
ifstream fShaderFile;
//抛出异常
vShaderFile.exceptions (ifstream::failbit | ifstream::badbit);
fShaderFile.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();
//转换数据流到String
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch(ifstream::failure e){
cout<<"ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ"<<endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
//编译着色器
unsigned int vertex,fragment;
int success;
//顶点着色器
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, nullptr);
glCompileShader(vertex);
// 打印编译错误(如果有的话)
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertex, 512, nullptr, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
};
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment,1,&fShaderCode, nullptr);
glCompileShader(fragment);
glGetShaderiv(fragment,GL_COMPILE_STATUS,&success);
if(!success){
glGetShaderInfoLog(fragment,512, nullptr,infoLog);
cout<<"ERROR::SHADER::FRAGMENT::COMPILATION_FILED\n"<<infoLog<<endl;
}
//着色器程序
ID = glCreateProgram();
//链接着色器
glAttachShader(ID,vertex);
glAttachShader(ID,fragment);
glLinkProgram(ID);
//判断连接是否成功
glGetProgramiv(ID,GL_LINK_STATUS,&success);
if(!success){
glGetProgramInfoLog(ID,512, nullptr,infoLog);
cout<<"ERROR::SHADER::PROGRAM::COMPILATION_FILED\n"<<infoLog<<endl;
}
//连接完成后删除着色器对象
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void Shader::use() const {
glUseProgram(ID);
}
void Shader::setBool(const string &name, bool value) const {
glUniform1i(glGetUniformLocation(ID,name.c_str()),(int)value);
}
void Shader::setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setVec4(const string &name, float x, float y, float z, float w) const {
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}