说明
在阅读此博客前,请访问2018级山东大学计算机学院图形学实验汇总。
原笔记通过latex编写,csdn只支持latex部分功能,所以下面主要是将pdf截屏上传。部分内容参考中国农业大学计算机图形学mooc。
算法介绍
代码
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char* vertexShaderPath="/Users/longzhengtian/Desktop/代码/C++代码/ComputerGraphics/shader.vs";
const char* fragmentShaderPath="/Users/longzhengtian/Desktop/代码/C++代码/ComputerGraphics/shader.fs";
struct node{double x,y;}a[2],b[2];
struct Node{double xleft,xright,ytop,ybottom;}rec;
unsigned int VBO[3], VAO[3];
int clickwho=-1;
bool DrawLine=false,DrawRec=false,DrawLineEnd=false,DrawRecEnd=false;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void Liang_barsky();
bool distant(node p1,node p2){return (pow(fabs(p1.x-p2.x),2)+pow(fabs(p1.y-p2.y),2)<=25);}
float transX(double x){return (float)((float)(2*x)-SCR_WIDTH)/(SCR_WIDTH*1.0f);}
float transY(double y){return (float)(SCR_HEIGHT-2*(float)y)/(SCR_HEIGHT*1.0f);}
int main(){
//实例化glfw函数
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//创建glfw窗口
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LiangBarsky", nullptr, nullptr);
if (window == nullptr){
cout << "Failed to create GLFW window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//将window设置为接下来操作的主窗口
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetKeyCallback(window, key_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){//使用glad加载glfw的所有函数指针
cout << "Failed to initialize GLAD" << endl;
return -1;
}
Shader ourShader(vertexShaderPath,fragmentShaderPath);//创建着色器程序
float RecVertices[13] = {};//裁剪窗口
float Lin1Vertices[7] = {};//原始线
float Lin2Vertices[7] = {};//裁剪窗口里面的线
glGenVertexArrays(3, VAO);
glGenBuffers(3, VBO);
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(RecVertices), RecVertices, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Lin1Vertices), Lin1Vertices, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(VAO[2]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Lin2Vertices), Lin2Vertices, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window)){
//输入
processInput(window);
// float timeValue = glfwGetTime();
// float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
// float redValue = (cos(timeValue) / 2.0f) + 0.5f;
// float blueValue = (tan(timeValue) / 2.0f) + 0.5f;
// glClearColor(redValue, greenValue, blueValue, 1.0f);
//渲染命令
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//裁剪窗口
//ourShader.setVec4("ourColor",greenValue,blueValue,redValue,1.0f);
ourShader.setVec4("ourColor",1.0f,1.0f,1.0f,1.0f);
ourShader.use();
glBindVertexArray(VAO[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//主线条
ourShader.setVec4("ourColor",1.0f,0.0f,0.0f,1.0f);
ourShader.use();
glBindVertexArray(VAO[1]);
glDrawArrays(GL_LINES, 0, 2);
//窗口里面的线条
ourShader.setVec4("ourColor",0.0f,0.0f,0.0f,1.0f);
ourShader.use();
glBindVertexArray(VAO[2]);
glDrawArrays(GL_LINES, 0, 2);
//检查并调用事件,交换缓冲
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(3, VAO);
glDeleteBuffers(3, VBO);
glfwTerminate();
return 0;
}
void Liang_barsky(){
double p[5],q[5],umax=0,umin=1;
memset(p,0,sizeof(p)); memset(q,0,sizeof(q));
double xleft=min(rec.xleft,rec.xright),xright=max(rec.xleft,rec.xright);
double ytop=max(rec.ytop,rec.ybottom),ybottom=min(rec.ytop,rec.ybottom);
p[1]=a[0].x-a[1].x; q[1]=a[0].x-xleft;
p[2]=a[1].x-a[0].x; q[2]=xright-a[0].x;
p[3]=a[0].y-a[1].y; q[3]=a[0].y-ybottom;
p[4]=a[1].y-a[0].y; q[4]=ytop-a[0].y;
for (int i=1; i<=4; i++){
if(p[i]<0) umax=max(umax,q[i]/p[i]);
else if(p[i]>0) umin=min(umin,q[i]/p[i]);
else if(p[i]==0 && q[i]<0){ umax=-1; break; }
}
if(umax<=umin && umax>=0 && umax<=1 && umin>=0 && umin<=1){
b[0].x=a[0].x+umax*(a[1].x-a[0].x);
b[0].y=a[0].y+umax*(a[1].y-a[0].y);
b[1].x=a[0].x+umin*(a[1].x-a[0].x);
b[1].y=a[0].y+umin*(a[1].y-a[0].y);
float tempvec[]={transX(b[0].x),transY(b[0].y),1.0f,
transX(b[1].x),transY(b[1].y),1.0f
};
glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(tempvec), &tempvec);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else{
b[0].x=0; b[0].y=0; b[1].x=0; b[1].y=0;
float tempvec[]={0,0,1.0f,0,0,1.0f};
glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(tempvec), &tempvec);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
void processInput(GLFWwindow *window){
if(clickwho>=0 && clickwho<=3){//移动矩形
double xpos,ypos;
glfwGetCursorPos(window,&xpos,&ypos);
if(clickwho==0){rec.xleft=xpos; rec.ybottom=ypos;}//"左下"
else if(clickwho==1){rec.xright=xpos; rec.ytop=ypos;}//"右上"
else if(clickwho==2){rec.xleft=xpos; rec.ytop=ypos;}//"左上"
else if(clickwho==3){rec.xright=xpos; rec.ybottom=ypos;}//"右下"
float tempvec[]={transX(rec.xleft),transY(rec.ybottom),1.0f,
transX(rec.xleft),transY(rec.ytop),1.0f,
transX(rec.xright),transY(rec.ybottom),1.0f,
transX(rec.xright),transY(rec.ytop),1.0f
};
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(tempvec),&tempvec);
glBindBuffer(GL_ARRAY_BUFFER, 0);
if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
}
else if(clickwho>=4){//移动直线
double xpos,ypos;
glfwGetCursorPos(window,&xpos,&ypos);
a[clickwho-4].x=xpos; a[clickwho-4].y=ypos;
float tempvec[]={transX(a[0].x),transY(a[0].y),1.0f,
transX(a[1].x),transY(a[1].y),1.0f
};
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(tempvec), &tempvec);
glBindBuffer(GL_ARRAY_BUFFER, 0);
if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
}
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
glViewport(0, 0, width, height);
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
else if (key == GLFW_KEY_R && action == GLFW_PRESS) {//如果按下"R",画裁剪窗口
if(!DrawLine){//此时不是属于画直线时刻
if(!DrawRec){//开始画窗口
double xpos,ypos;
glfwGetCursorPos(window,&xpos,&ypos);
rec.xleft=xpos; rec.ybottom=ypos;
clickwho=1; DrawRec=true;//此时的状态和点击了"右上"是一样的,都是"右上"在移动
}
else {//结束画窗口
clickwho=-1; DrawRec=false; DrawRecEnd=true;
if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
}
}
}
else if (key == GLFW_KEY_L && action == GLFW_PRESS) {//如果按下"L",画直线
if(!DrawRec){//此时不是属于画裁剪窗口时刻
if(!DrawLine){//开始画直线
double xpos,ypos;
glfwGetCursorPos(window,&xpos,&ypos);
a[0].x=xpos; a[0].y=ypos;
clickwho=5; DrawLine=true;//此时状态和点击了第二个点是一样点,都是第二个点在移动
}
else {//结束画直线
clickwho=-1; DrawLine=false; DrawLineEnd=true;
if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
}
}
}
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods){
if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS && !DrawLine && !DrawRec){//此时没有画裁剪窗口和直线
double xpos,ypos;
glfwGetCursorPos(window,&xpos,&ypos);
if(clickwho!=-1) clickwho=-1;//移动中点击了鼠标,肯定是要结束了
else if(distant({rec.xleft,rec.ybottom},{xpos,ypos})) clickwho=0;//点击矩形"左下"
else if(distant({rec.xright,rec.ytop},{xpos,ypos})) clickwho=1;//点击矩形"右上"
else if(distant({rec.xleft,rec.ytop},{xpos,ypos})) clickwho=2;//点击矩形"左上"
else if(distant({rec.xright,rec.ybottom},{xpos,ypos})) clickwho=3;//点击矩形"右下"
else if(distant(a[0],{xpos,ypos})) clickwho=4;//点击直线的第一个点
else if(distant(a[1],{xpos,ypos})) clickwho=5;//点击直线的第二个点
}
}