CG 中点法画直线
1. \((x_i,y_i) \rightarrow (x_{i+1},y_{i+1})\)
根据可能所取点间的中点M与直线的位置
构造判别式:\(d = F(M) = F(x_{i+1}, y_{i,r}+0.5)\)
由d的正和负可判定下一个像素。 其中 \(p(x_i , y_{i,r})\)为当前点坐标
d < 0, 取NE;否则取E
2.如何再确定下一个像素\((x_{i+2},?)\)
1) 若\(d≥0\), 取正右方像素E, 则判定再下一个像素的d为\(d_1=F(x_i+2, y_{i,r}+0.5)=a(x_{i+2})+b(y_{i,r}+0.5)+c=d+a\),d的增量是a
2) 若d<0, 取右上方像素NE, 则判定再下一个像素的d为\(d2=F(x_i+2, y_{i,r}+1.5)=d+a+b\),d的增量为a+b
3.增量d的初始值
\(d_0=F(x_0+1, y_0+0.5)=F(x_0, y_0)+a+0.5b=a + 0.5b\)
4.增量d的递推公式
\[d_0=a+0.5b \\
d_i+1 = \left\{ \begin{array}{lr} d_i+a & d_i>0\\ d_i+a+b & d_i\leq0 \end{array} \right. \]
2d代替d
\[d_0=2a+b\\
d_i+1 = \left\{ \begin{array}{lr} d_i+2a & d_i>0\\ d_i+2a+2b & d_i\leq0 \end{array} \right. \]
5.其他几种情况
\[0 \leq m \leq 1\\ d_0=2a+b \\ d_{i+1} = \left\{ \begin{array}{lr} d_i+2a & d_i>0\\ d_i+2a+2b & d_i\leq0 \end{array} \right. \]
\[ m > 1 \\ d_0=a+2b \\ d_{i+1} = \left\{ \begin{array}{lr} d_i+2a+2b & d_i>0\\ d_i+2b & d_i\leq0 \end{array} \right. \]
\[-1 \leq m \leq 0 \\ d_0=2a-b \\ d_{i+1} = \left\{ \begin{array}{lr} d_i+2a-2b & d_i>0\\ d_i+2a & d_i\leq0 \end{array} \right. \]
\[m<- 1 \\ d_0=a-2b \\ d_{i+1} = \left\{ \begin{array}{lr} d_i-2b & d_i>0\\ d_i+2a-2b & d_i\leq0 \end{array} \right. \]
#include <iostream>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
using namespace std;
// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 800;
// Shaders
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(128.0/255.0f, 1.0f, 28*6.0/255.0f, 1.0f);\n"
"}\n\0";
GLint tot = 0;
GLfloat vertices[100000];
void MidpointLine(GLint x0, GLint y0, GLint x1, GLint y1);
// The MAIN function, from here we start the application and run the game loop
int main()
{
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create a GLFWwindow object that we can use for GLFW's functions
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
// Set the required callback functions
glfwSetKeyCallback(window, key_callback);
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
glewInit();
// Define the viewport dimensions
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Build and compile our shader program
// Vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// Check for compile time errors
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Check for compile time errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Link shaders
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// Check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// Set up vertex data (and buffer(s)) and attribute pointers
MidpointLine(0, 500, 0, -500);
MidpointLine(-500, -500, 500, 700);
MidpointLine(-500, 500, 500, -700);
MidpointLine(-500, 200, 500, -300);
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind
glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs)
// Game loop
while (!glfwWindowShouldClose(window))
{
// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents();
// Render
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Draw our first triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_POINTS, 0, tot);
glBindVertexArray(0);
// Swap the screen buffers
glfwSwapBuffers(window);
}
// Properly de-allocate all resources once they've outlived their purpose
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// Terminate GLFW, clearing any resources allocated by GLFW.
glfwTerminate();
return 0;
}
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
void addPoint(GLint x, GLint y, GLint z)
{
vertices[tot++] = 1.0 * x / WIDTH;
vertices[tot++] = 1.0 * y / HEIGHT;
vertices[tot++] = z;
}
void MidpointLine(GLint x0, GLint y0, GLint x1, GLint y1)
{
GLint a, b, d1, d2, d, x, y;
GLfloat m;
if (x1 < x0) { swap(x0, x1); swap(y0, y1);}
a = y0 - y1, b = x1 - x0;
if (b == 0) m = -1 * a * 100;
else m = (GLfloat)a / (x0 - x1);
x = x0, y = y0;
addPoint(x, y, 0);
if (m >= 0 && m <= 1)
{
d = 2 * a + b; d1 = 2 * a; d2 = 2 * (a + b);
while (x < x1)
{
if (d <= 0) { y++; d += d2; }
else d += d1;
x++;
addPoint(x, y, 0);
}
}
else if (m > 1)
{
d = a + 2 * b; d1 = 2 * (a + b); d2 = 2 * b;
while (y < y1)
{
if (d > 0) { x++; d += d1; }
else d += d2;
y++;
addPoint(x, y, 0);
}
}
else if (m >= -1 && m <= 0)
{
d = 2 * a - b; d1 = 2 * a - 2 * b; d2 = 2 * a;
while (x < x1)
{
if (d > 0) { y--; d += d1; }
else d += d2;
x++;
addPoint(x, y, 0);
}
}
else
{
d = a - 2 * b; d1 = -2 * b; d2 = 2 * (a - b);
while (y > y1)
{
if (d <= 0) { x++; d += d2; }
else d += d1;
y--;
addPoint(x, y, 0);
}
}
}