买了人民邮电苏小红教授主编的计算机图形学实用教程,但是一直懒得看,现在决定利用CSDN博客平台来督促自己。
上网搜了下,大多数人都是用老式的固定管线,没看到有谁用现代OpenGL,看了算法实现,尝试改成着色器的,自己看教材,教材上的算法写得很清楚了,一步一步实现即可。
SetPixel函数是windows下的函数,看了其他人博客里面用固定管线实现其实很简单,就是调用glBegin(GL_POINTS); glVertex2i(x,y)。
改成着色器很简单,代码是我学习learnopengl的时候拿自己建的工程改的。DDA法和中点画线法,Bresenham畫線法
教材里面的算法x的增量是1,但是OpenGL里面标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间,所以我把增量改成0.1,还可以更小。
运行结果:第一張圖是pointsize 15.0 ,第二張圖是5.0
分別是中點畫線和Bresenham,中點畫線波浪紋比較明顯。
glPointSize(15.0);
glPointSize(5.0);
void bges::CGfxRenderDDADrawLine::startUp()
{
vertexArrayID = 0;
glGenVertexArrays(1, &vertexArrayID);
glBindVertexArray(vertexArrayID);
// Create and compile our GLSL program from the shaders
Shader shader;
Shader shader2;
programID = shader.LoadShaders("/home/study/OpenGL/learnopengl/MyProject/shaderFile/SimpleVertexShader.vertexshader","/home/study/OpenGL/learnopengl/MyProject/shaderFile/SimpleFragmentShader.fragmentshader" );
static GLfloat lineVertex_Buffer_Data[902] = {0.0};
//{0.00000,1.000000,0.250000,0.500000};
//this->length = GetLineDDAData(0.0,0.0,0.45,0.41,lineVertex_Buffer_Data);
static GLfloat lineVertexX[451] = {0.0};
static GLfloat lineVertexY[451] = {0.0};
GetLineMLDAData(0.0,0.0,0.45,0.41,lineVertexX,lineVertexY);
for(int i = 0;i < 451;i++){
lineVertex_Buffer_Data[ i ] = lineVertexX[ i ];
}
for(int i = 451;i < 902;i++){
lineVertex_Buffer_Data[ i ] = lineVertexY[ i - 451 ];
}
vertexbuffer = 0;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(lineVertex_Buffer_Data),
lineVertex_Buffer_Data, GL_STATIC_DRAW);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
vertexArrayIDBresenham = 0;
glGenVertexArrays(1, &vertexArrayIDBresenham);
glBindVertexArray(vertexArrayIDBresenham);
programIDBresenham = shader2.LoadShaders( "/home/tankweight/study/OpenGL/learnopengl/MyProject/shaderFile/SimpleVertexShader.vertexshader", "/home/tankweight/study/OpenGL/learnopengl/MyProject/shaderFile/SimpleFragmentShader.fragmentshader" );
static GLfloat lineVertex_Buffer_DataBresenham[1224] = {0.0};
static GLfloat lineVertexXBresenham[612] = {0.0};
static GLfloat lineVertexYBresenham[612] = {0.0};
GetLineBresenhamData(-0.46,-0.2,0.15,0.11,lineVertexXBresenham,lineVertexYBresenham);
for(int i = 0;i < 612;i++){
lineVertex_Buffer_DataBresenham[ i ] = lineVertexXBresenham[ i ];
}
for(int i = 612;i < 1004;i++){
lineVertex_Buffer_DataBresenham[ i ] = lineVertexYBresenham[ i - 612 ];
}
vertexbufferBresenham = 0;
glGenBuffers(1, &vertexbufferBresenham);
glBindBuffer(GL_ARRAY_BUFFER, vertexbufferBresenham);
glBufferData(GL_ARRAY_BUFFER, sizeof(lineVertex_Buffer_DataBresenham),
lineVertex_Buffer_DataBresenham, GL_STATIC_DRAW);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glPointSize(5.0);
}
DDA数值微分画线算法:
int bges::CGfxRenderDDADrawLine::GetLineDDAData(float x1,float y1,float x2,float y2, GLfloat vertex_buffer_data[])
{
float length = 0.0;
int k = 0;
float x = x1;
float y = y1;
float dx = abs(x2 - x1);
float dy = abs(y2 - y1);
float m = (float)(dy / dx);
length = dx - dy >= 0.0000001f ? dx : dy;
int yinit = length / 0.001;
printf("yinit = %d,length = %f\n",yinit,length);
vertex_buffer_data[ k ] = x;
vertex_buffer_data[ k + yinit ] = y;
//printf("%f,%f,%f\n",m,x,y);
//vertex_buffer_data[ k + 2 ] = 0.0f;
k = 1;
for(int i = 1;i < yinit;i++){
if(dx - dy > 0.0 && x1 - x2 < 0.0){
x += 0.001;
y += m;
vertex_buffer_data[ k ] = x;
vertex_buffer_data[ k + yinit ] = y;
//vertex_buffer_data[ k + 2 ] = 0.0f;
printf("%f,%f\n",x,y);
k++;
}
}
return length / 0.01;
}
渲染
void bges::CGfxRenderDDADrawLine::Render(double currentTime)
{
glClear( GL_COLOR_BUFFER_BIT );
// Use our shader
glUseProgram(programID);
glBindVertexArray(vertexArrayID);
glDrawArrays(GL_POINTS, 0, 451);
//glDisableVertexAttribArray(0);
glUseProgram(programIDBresenham);
glBindVertexArray(vertexArrayIDBresenham);
glDrawArrays(GL_POINTS, 0, 200);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
顶点着色器
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}
片元着色器
#version 330 core
// Ouput data
out vec3 color;
void main()
{
// Output color = red
color = vec3(1,0,0);
}
中点画线法:
void bges::CGfxRenderDDADrawLine::GetLineMLDAData(float x1,float y1,float x2,float y2, GLfloat lineVertexX[],GLfloat lineVertexY[])
{
float a = y1 - y2;
float b = x2 - x1;
float d = 2 * a + b;
float deta1 = 2 * a;
float deta2 = 2 * (a + b);
float x = x1,y = y1;
lineVertexX[ 0 ] = x;
lineVertexY[ 0 ] = y;
int i = 1;
for(;;)
{
if(x - x2 < 0.000001){
if(d - 0.0000001 < 0){
x = x + 0.001;
y = y + 0.001;
d = d + deta2;
}
else {
x = x + 0.001;
d = d + deta1;
}
lineVertexX[ i ] = x;
lineVertexY[ i ] = y;
//printf("%f,%f\n",x,y);
i++;
}
else{
return;
}
}
}
Bresenham畫線算法
void bges::CGfxRenderDDADrawLine::GetLineBresenhamData(float x1,float y1,float x2,float y2, GLfloat lineVertexX[],GLfloat lineVertexY[])
{
float dx = x2 - x1;
float dy = y2 - y1;
float x = x1;
float y = y1;
lineVertexX[ 0 ] = x;
lineVertexY[ 0 ] = y;
float m = abs(float(dy / dx));
bool xx_yy = m - 1.0 < 0.0000001 ? true : false;
float S1 = dx - 0.0000001 > 0.0 ? 0.001 : -0.001;
float S2 = dy - 0.0000001 > 0.0 ? 0.001 : -0.001;
float e_InitValue = m - 1.0 > 0.0000001 ? 2 * abs(dx) - 2 * (dy) : 2 * abs(dy) - 2 * (dx);
float e_current = e_InitValue;
int i = 1;
for(;;)
{
if((x2 - x) > 0.0000001){
if(e_current - 0.0000001 < 0.0){
if(false == xx_yy){
y += S2;
e_current += 2 * abs(dx);
}
else{
x += S1;
e_current += 2 * abs(dy);
}
}
else{
if(false == xx_yy){
x += S1;
y += S2;
e_current += (2 * abs(dx) - 2 * abs(dy));
}
else{
y += S2;
x += S1;
e_current += (2 * abs(dy) - 2 * abs(dx));
}
}
lineVertexX[ i ] = x;
lineVertexY[ i ] = y;
i++;
//printf("1 i = %d\n",i);
}
else{
//printf("2 i = %d\n",i);
return;
}
}
}