github仓库:livingsu/OpenGL-simulate-turning
之前用的一直是旧OpenGL的固定管线(glut库),但是当接触了新OpenGL以后,感觉着色器、VAO、VBO实在是太强大了,不仅更加灵活,而且利用缓存可以极大提升渲染性能。
主要参考**Learn-OpenGL-CN官网**,项目中加载模型用到的Assimp库,加载图片用的stb_image库,另外还用到了learn-OpenGL作者写的一些类:camera.h,shader.h,model.h都是及其方便的类。
实现的主要功能:
- 显示背景图片,圆柱形原料、车刀模型的绘制
- 通过鼠标移动车刀,完成切削
- 切削时有粒子系统模拟飞溅效果
- 可以选择圆柱体材质(金属或者木质),使用的是pbr光照模型
- 切削后圆柱体光照材质发生变化
- 可以创建三次贝塞尔曲线作为切削的约束线
效果预览:
1.背景图片
画两个三角形,设置纹理图片即可,注意将z值设置和w一样,那么其深度就是最大的z/w=1.0,就会显示在所有物体的后面。
// background.vs
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main(){
TexCoords = aTexCoords;
gl_Position = vec4(aPos.xy,1.0,1.0); //设置深度为最大
}
要注意画背景之前打开glDepthFunc(GL_LEQUAL)并在之后恢复默认值。
// 画背景图片
// -------------
glDepthFunc(GL_LEQUAL); //设置背景在所有物体的最后面(最大深度)绘制
bgShader.use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bgTexture);
glBindVertexArray(bgVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glDepthFunc(GL_LESS);
2.圆柱体原料
圆柱体拥有很多信息
//圆柱体信息,注意应该用double而不是float,避免精度不够导致除法出错
const double cylinderRadius = 0.4;
const double cylinderLength = 1.6;
const int angleStep = 2; //切分角度增量
const double lengthStep = 0.001; //切分长度增量
const double radiusStep = 0.001; //半径增量
vector<int> radiusArray; //半径数组,均为radiusStep的整数倍
vector<int> radiusMinArray; //半径最小值数组,规定半径的最小值,用于贝塞尔曲线的限制
vector<glm::vec3> allPoints; //所有点数组,包括顶点、法向量和纹理坐标
vector<unsigned int> indices; //索引数据
unsigned int cylinderVAO;
unsigned int cylinderVBO;
unsigned int vertexNum; //顶点数量
绘制的主要思想:
只需要绘制圆柱体侧面,将侧面展开得到一个矩形,将矩形沿底边分成slices(=360/angleStep)份,沿z轴分成stacks(=cylinderLength/lengthStep)份,得到的小矩形用两个三角形绘制即可。由于相同的点在不同的小矩形中重复利用,故用EBO进行索引缓存即可。
void initCylinder() {
int slices = 360 / angleStep; //围绕z轴的细分
int stacks = cylinderLength / lengthStep; //沿z轴的细分
//初始化半径数组和半径限制数组
unsigned int initRadius = cylinderRadius / radiusStep;
for (int i = 0; i <= stacks; ++i) {
radiusArray.push_back(initRadius);
}
for (int i = 0; i <= stacks; ++i) {
radiusMinArray.push_back(0); //开始时,半径最小均可以取0
}
float R, alpha, x