OpenGL进阶示例1——动态画线(虚线、实线、颜色、速度等)

用OpenGL动态绘制线段,其实很简单,但到现在为止,网上可参考资料并不多。于是亲自动手写一个函数,方便动态绘制线段。代码如下:

#include<GL/glut.h>						//OpenGL实用工具包
#include <Windows.h>

/*所遇问题:
1、系统API函数Sleep()不听话,睡眠时快时慢(可能跟我计算机当前运行程序有关吧)
解决方案:重写Sleep()函数,实质为空循环。仅用于Debug下,Release会将其优化

2、动态画直线,朝某些方向画线时出现块状
解决方案:认认真真把直线方程推导一遍,斜率存在或不存在分别讨论,将数学思想转换为编程思想
*/

void init(void)
{
	glClearColor(0.0,0.0,0.0,0.0);		//指定清除颜色(黑色),即背景颜色
	glShadeModel(GL_FLAT);				//设置着色模式,采用恒定着色
}

void Sleep(int ms)			//覆盖系统API函数
{
	for(int i=0;i<ms*ms*ms*10;i++)		//数值大小根据实际情况调试
	{
		;
	}
}

//特别注意:1、斜率不存在。2、直线斜率一定要保持一致,将直线两点式方程转化为斜率式方程y=kx+c
//k=(y2-y1)/(x2-x1);
//c=(x2*y1-x1*y2)/(x2-x1);
void DrawDynamicLine(GLfloat x1, GLfloat y1,		//起点坐标
	GLfloat x2, GLfloat y2,							//终点坐标
	GLfloat red,GLfloat green,GLfloat blue,			//线段颜色
	int speed,										//绘制速度,0-100,值越大速度越大
	int type										//虚线类型,16位2进制表示,1为实点,0为虚点,0xFFFF为实线
	)
{
	glEnable(GL_LINE_STIPPLE);						//点画线模式
	glColor3f(red,green,blue);						//设置线段绘制颜色
	glLineStipple(1,type);							//dashed(虚线),type为16位2进制数,0表示实点,1表示虚点

	if (x1!=x2)										//如果斜率存在
	{
		GLfloat k=(y2-y1)/(x2-x1);					//直线斜率 y=kx+c
		GLfloat c=(x2*y1-x1*y2)/(x2-x1);			//直线常数
		//假定以A为原点建立二维坐标系,则下边4个if分别对应于:第一象限,第二象限,第三象限,第四象限
		if (x1<x2&&y1<=y2)							//从A(x1,y1)到B(x2,y2)画线,B点在A点的右上方
		{
			for (int i=0;i<=x2-x1;i++)				//注意循环条件
			{
				glBegin(GL_LINES);
				glVertex2f(x1,y1);
				glVertex2f(x1+i,k*(x1+i)+c);
				glEnd();
				Sleep(100-speed);
				glFlush();							//立刻开始处理保存在缓冲区中的OpenGL函数调用
			}
		}
		else if (x1>x2&&y1<=y2)						//从A(x1,y1)到B(x2,y2)画线,B点在A点的左下方
		{
			for (int i=0;i>=x2-x1;i--)				//特别注意循环条件,既要避免死循环又要避免少循环
			{
				glBegin(GL_LINES);
				glVertex2f(x1,y1);
				glVertex2f(x1+i,k*(x1+i)+c);
				glEnd();
				Sleep(100-speed);
				glFlush();							//立刻开始处理保存在缓冲区中的OpenGL函数调用
			}
		}
		else if (x1>x2&&y1>=y2)						//从A(x1,y1)到B(x2,y2)画线,B点在A点的左上方
		{
			for (int i=0;i>=x2-x1;i--)				//特别注意循环条件,既要避免死循环又要避免少循环
			{
				glBegin(GL_LINES);
				glVertex2f(x1,y1);
				glVertex2f(x1+i,k*(x1+i)+c);
				glEnd();
				Sleep(100-speed);
				glFlush();							//立刻开始处理保存在缓冲区中的OpenGL函数调用
			}
		}
		else if (x1<x2&&y1>=y2)						//从A(x1,y1)到B(x2,y2)画线,B点在A点的左上方
		{
			for (int i=0;i<=x2-x1;i++)				//特别注意循环条件,既要避免死循环又要避免少循环
			{
				glBegin(GL_LINES);
				glVertex2f(x1,y1);
				glVertex2f(x1+i,k*(x1+i)+c);
				glEnd();
				Sleep(100-speed);
				glFlush();							//立刻开始处理保存在缓冲区中的OpenGL函数调用
			}
		}
	}
	else
	{
		if (y1<y2)									//沿y轴正方向画线
		{
			for (int i=0;i<=y2-y1;i++)				//特别注意循环条件,既要避免死循环又要避免少循环
			{
				glBegin(GL_LINES);
				glVertex2f(x1,y1);
				glVertex2f(x1,y1+i);
				glEnd();
				Sleep(100-speed);
				glFlush();							//立刻开始处理保存在缓冲区中的OpenGL函数调用
			}
		}
		else										//沿y轴负方向画线
		{
			for (int i=0;i>=y2-y1;i--)				//特别注意循环条件,既要避免死循环又要避免少循环
			{
				glBegin(GL_LINES);
				glVertex2f(x1,y1);
				glVertex2f(x1,y1+i);
				glEnd();
				Sleep(100-speed);
				glFlush();							//立刻开始处理保存在缓冲区中的OpenGL函数调用
			}
		}
	}

}

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);			//清除所有的像素
	//正方形ABCD
	DrawDynamicLine(100,500,500,500,1,1,0,60,0xFFFF);			//AB
	DrawDynamicLine(500,500,500,100,1,0,1,70,0xFFFF);			//BC
	DrawDynamicLine(500,100,100,100,1,1,1,80,0xFFFF);			//CD
	DrawDynamicLine(100,100,100,500,0,1,1,90,0xFFFF);			//DA

	//沿顺时针方向测试动态画线:第一象限,第四象限,第三象限,第二象限
	DrawDynamicLine(300,300,300,500,1,0,0,90,0xFFFF);			//1
	DrawDynamicLine(300,300,400,500,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,500,500,1,0,0,90,0xFFFF);
	DrawDynamicLine(300,300,500,400,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,500,300,1,0,0,90,0xFFFF);

	DrawDynamicLine(300,300,500,300,1,0,0,90,0xFFFF);			//2
	DrawDynamicLine(300,300,500,200,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,500,100,1,0,0,90,0xFFFF);
	DrawDynamicLine(300,300,400,200,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,400,100,1,0,0,90,0x00FF);

	DrawDynamicLine(300,300,300,100,1,0,0,90,0xFFFF);			//3
	DrawDynamicLine(300,300,200,100,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,100,100,1,0,0,90,0xFFFF);
	DrawDynamicLine(300,300,100,200,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,100,300,1,0,0,90,0xFFFF);

	DrawDynamicLine(300,300,100,300,1,0,0,90,0xFFFF);			//4
	DrawDynamicLine(300,300,100,400,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,100,500,1,0,0,90,0xFFFF);
	DrawDynamicLine(300,300,200,500,1,0,0,90,0x00FF);
	DrawDynamicLine(300,300,300,500,1,0,0,90,0xFFFF);

}

void reshape(int w,int h)
{
	glViewport(0,0,(GLsizei)w,(GLsizei)h);			 //为了选择一个更小的绘图区域,在窗口中定义一个像素矩形,将图像映射到这个矩形中
	glMatrixMode(GL_PROJECTION);			  		 //指定哪一个矩阵是当前矩阵(GL_PROJECTION,对投影矩阵应用随后的矩阵操作)
	glLoadIdentity();							  	 //将当前的用户坐标系的原点移到了屏幕中心:类似于一个复位操作
	gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h);	 //将当前的可视空间设置为正投影空间,这个函数描述了一个平行修剪空间,意味着离观察者较远的对象看上去不会变小
}

int main(int argc,char** argv)						//注意参数
{
	glutInit(&argc,argv);							//初始化GLUT并处理命令行参数
	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);		//指定模式:单缓存OR双缓存;RGBA模式OR颜色索引模式
	glutInitWindowSize(600,600);					//指定窗口大小(像素)
	glutInitWindowPosition(300,50);					//指定窗口左上角在屏幕上的位置
	glutCreateWindow(argv[0]);						//使用OpenGL场景创建一个窗口,参数为窗口名称
	init();											//调用初始化函数
	glutDisplayFunc(display);						//注册用于显示图形的回调函数,每当GLUT认为需要重绘窗口时,都会执行该函数,故应将重绘场景所需调用的函数都放到显示回调函数中。
	glutReshapeFunc(reshape);						//重绘回调函数
	glutMainLoop();									//进入主循环并处理事件,此时创建的所有窗口都会显示出来,被渲染到这些窗口中的内容也将显示出来,程序开始处理事件,注册的显示回调函数被触发
	return 0;										//ANSI C要求函数main()返回一个int值
}

效果如下:

OpenGL进阶示例1——动态画线(虚线、实线、颜色、速度等),布布扣,bubuko.com

时间: 2024-08-24 03:52:12

OpenGL进阶示例1——动态画线(虚线、实线、颜色、速度等)的相关文章

计算机图形学(二)输出图元_2_ OpenGL画线函数

 OpenGL画线函数 图形软件包一般都提供一个描述一条或多条直线段的函数,其中每一直线段由两个端点坐标位置定义.在OpenGL中,和选择一个点位置一样,我们使用glVertex函数选择单个端点的坐标位置.我们使用一对glBegin/g1End来引入一串端点位置.有三个OpenGL符号常量可用于指定如何把这一串端点位置连接成一组直线段.默认情况下,每一符号常量显示白色实线. 使用图元线常量GL_LINES可连接每一对相邻端点而得到一组直线段.通常,这会导致一组未连接的线段,除非重复某些坐标位置.

Bresenham画线算法详解及其OpenGL编程实现

http://blog.csdn.net/xiajun07061225/article/details/7018719 Bresenham是由Bresenham提出的一种精确而有效地光栅线生成算法,该算法仅使用增量整数计算.另外,它还可以用于显示其它曲线. 我们以斜率大于0小于1的线段来进行考虑.以单位x间隔进行取样.每次绘制了当前像素点(xk,yk)之后,需要确定下一个要绘制的点是(xk+1,yk)还是(xk+1,yk+1),需要判断哪一个点像素点更接近线路径. 在取样位置,我们使用d1和d2

PHP合成图片、生成文字、居中对齐、画线、矩形、三角形、多边形、图片抗锯齿、不失真 高性能源码示例

function generateImg($source, $text1, $text2, $text3, $font = './msyhbd.ttf') { $date = '' . date ( 'Ymd' ) . '/'; $img = $date . md5 ( $source . $text1 . $text2 . $text3 ) . '.jpg'; if (file_exists ( './' . $img )) { return $img; } $main = imagecrea

用OpenGL画线

. 两点之间的连线称之为线段,在屏幕上显示线段放在现在已经不是稀奇的事情,大多数高级图形API都可以轻松实现,我尝试用OpenGL画线,在这里记录一下收获. . OpenGL这个级别的图形API,通常会提供一些绘制基本图形的接口,这些基本图形称之为图元,而OpenGL提供了点,线段,三角形三种图元绘制接口,说出来你可能不信,OpenGL就只能绘制这三种图形,本篇博文的主题是画线,OpenGL能直接绘制的图元之一. 用OpenGL绘制线段图元 给出两点的坐标,调用API即可直接画出线段. // 伪

Highcharts动态画曲线

使用Highcharts画曲线的过程中,有时候曲线个数是从数据库中取出来的,不能确定曲线的条数. 可以利用Highcharts里的addSeries函数进行动态添加曲线: 示例如下: 1 for(var i=0;i<=<%=intRet %>;i++){ 2 var chart = $('#container').highcharts(); 3 4 newstr=strArray.pop(); 5 6 tempArray = newstr.split('a'); 7 //用于剔出空值与0

unity3d GL画线/物体跟随/坐标系转换

看见标题的人是不是在想... 一个小小的GL画线难吗? 一个小小的物体跟随难吗? 嗯,的确,一点不难.... 我一开始也是像你们那样想的,但是实际操作起来,还是和理论有区别的 写这个demo起因是这样的: 面试到了一家虚拟现实的公司,因为没有去公司 网上直接谈的,谈妥了hr估计是想看看我能不能胜任 给了我一张效果图,让我去实现画线的功能 咳咳,要求还是比较细致的,这里我们后面说 废话不多说,老规矩,先上效果图,然后直接进入主题 第一张是hr给我的图,第二张是我自己实现的 需求如下: 1.模型是旋

IOS Quartz 各种绘制图形用法---实现画图片、写文字、画线、椭圆、矩形、棱形等

转自:http://blog.csdn.net/zhibudefeng/article/details/8463268 [cpp] view plain copy // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { CGC

Quartz 各种绘制图形用法---实现画图片、写文字、画线、椭圆、矩形、棱形等

// Only override drawRect: if you perform custom drawing.// An empty implementation adversely affects performance during animation.- (void)drawRect:(CGRect)rect{    CGContextRef context = UIGraphicsGetCurrentContext();         /*NO.1画一条线     CGContex

Android OpenGL入门示例:绘制三角形和正方形 (附完整源码)

Android上对OpenGl的支持是无缝的,所以才有众多3D效果如此逼真的游戏,在Camera的一些流程中也有用到GLSurfaceView的情况.本文记录OpenGL在Android上的入门级示例,绘制一个三角形和正方形.尽管功能简单,可是我捣腾了好几个晚上,大量网上文章上的代码都有点问题,不是绘制不出来就是挂了. 第一个文件:MainActivity.java package com.example.learnopengl1; import android.opengl.GLSurface