这事opencv鼠标事件中为什么两个drawtext函数-box,为什么主函数和鼠标事件函数都写了呢,我觉得多余呢,求指教

源代码_源码下载_源码爱好者
& 所有源码win7+VS2013+OpenCV 2.4.9
鼠标事件响应采用回调函数CallBack的方式来处理。
*******************************************************************************
其实回调就是一种利用函数指针进行函数调用的过程. &
为什么要用回调呢?比如我要写一个子模块给你用, &&来接收远程socket发来的命令.当我接收到命令后,
&&需要调用你的主模块的函数, &&来进行相应的处理.但是我不知道你要用哪个函数来处理这个命令, & &&我也不知道你的主模块是什么.cpp或者.h,
&&或者说, &&我根本不用关心你在主模块里怎么处理它, &&也不应该关心用什么函数处理它...... &&怎么办?
——&lone wolf
使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。
——&某专家
回调函数,就是由你自己写的。你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。
&是一篇比较好的文章。
什么是回调函数?
  回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。回调函数必须遵守事先规定好的参数格式和传递方式,否则DLL一调用它就会引起程序或系统的崩溃。通常情况下,回调函数采用标准WindowsAPI的调用方式,即__stdcall,当然,DLL编制者可以自己定义调用方式,但客户程序也必须遵守相同的规定。在__stdcall方式下,函数的参数按从右到左的顺序压入堆栈,除了明确指明是指针或引用外,参数都按值传递,函数返回之前自己负责把参数从堆栈中弹出。
  理解回调函数!
——&jufengfeng
Function Pointers provide the concept of callback functions.
——&newty.de
*******************************************************************************
看了这么多的资料,我只将每位的定义总结一下就一句话:回调函数就是函数指针的一种用法。
在鼠标事件处理中,
回调函数callback可以是满足指定输入参数以及返回参数类型的任何函数。
这里,我们必须清楚告诉回调函数触发的事件以及触发位置。
函数还需要知道,用户是否在触发鼠标事件的同时触发了shift或alt等按键。
回调函数格式:
void CvMouseCallback(
int event,//鼠标事件
int x,//鼠标指针(cruser)当前位置的水平坐标
int y,//鼠标指针(cruser)当前位置的垂直坐标
int flags,//鼠标事件标志
void* param//额外需要传入的参数
还需要将回调函数注册到OpenCV中,实现的函数是cvSetMouseCallback
void cvSetMouseCallback(
const char* window_name,//指定回调函数需要注册到的窗口,也就是产生事件的窗口
CvMouseCallback on_mouse,//自己定义的回调函数
void* param=NULL//给CvMouseCallback传入的参数
实现一个程序,使得用户可以通过鼠标来画矩形。
//An example program in which the
//user can draw boxes on the screen.
#include &cv.h&
#include&highgui.h&
void my_mouse_callback(int event,int x,int y, int flags,void* param);//自定义的回调函数声明
bool drawing_box=
void draw_box(IplImage* img,CvRect rect)
cvRectangle(
cvPoint(box.x,box.y),
cvPoint(box.x+box.width,box.y+box.height),
//cvScalar(0xff,0x00,0x00);
CV_RGB(255,0,0)//red
int main(int argc,char** argv)
box=cvRect(-1,-1,0,0);
IplImage* image=cvCreateImage(
cvSize(512,512),
IPL_DEPTH_8U,
cvZero(image);
IplImage* temp=cvCloneImage(image);//复制全部图片内容
cvNamedWindow(&Box Example&);
cvSetMouseCallback(//注册回调函数
&Box Example&,
my_mouse_callback,
(void*)image);
cvCopyImage(image,temp);
if(drawing_box) draw_box(temp,box);
cvShowImage(&Box Example&,temp);
if(cvWaitKey(15)==27)
cvReleaseImage(&image);
cvReleaseImage(&temp);
cvDestroyAllWindows();
void my_mouse_callback(int event,int x,int y, int flags,void* param)
IplImage* image=(IplImage*)
switch (event)
//鼠标拖动
//依照当前点坐标和矩形起始点坐标设置矩形的宽度和高度
case CV_EVENT_MOUSEMOVE:{
if(drawing_box)
box.width=x-box.x;
box.height=y-box.y;
//鼠标左键按下,开始绘图,设置矩形起始点
case CV_EVENT_LBUTTONDOWN:{
drawing_box=
box=cvRect(x,y,0,0);
//鼠标左键弹起,绘图结束,把矩形写入image
//如果width或height是负数,取其绝对值,并将靠近左上角的顶点设为矩形起始点
case CV_EVENT_LBUTTONUP:{
drawing_box=
if(box.width&0)
box.x+=box.
box.width*=-1;
if(box.height&0)
box.y+=box.
box.height*=-1;
draw_box(image,box);//将矩形写入image
运行cmd,效果图:
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3833次
排名:千里之外
原创:24篇
(9)(4)(7)(1)(2)(4)Opencv学习之鼠标响应及画图操作
通过下面的检测程序练习了openCV中的鼠标响应操作,并可以实现画图功能。所用到的新函数有:
(1)cvSetMouseCallback(const char* Window_Name,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
cvMouseCallBack on_Mouse,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
void *param = NULL);
==&实现对窗口Window_Name上的对象param添加鼠标响应操作on_Mouse。
其中回调函数cvMouseCallBack的定义格式如下:
void CvMouseCallBack(int event,int x,int y,int
flags,void*prama);
其中,event的取值类型有:(均以CV_EVENT_开头,以下略)
MOUSEMOVE--&0&&&&
L/R/MBUTTONDOWN--&1/2/3&&&&&
L/R/MBUTTONUP--&4/5/6
L/R/MBUTTONDBCLICK--&7/8/9
(x,y)代表出现鼠标事件的位置点的坐标;flags的值用于说明事件发生是的一些条件,其取值类型有(均以CV_EVENT_FLAG_开头):L/R/MBUTTON--&1/2/4
CTRLKEY/SHIFTKEY/ALTKEY--&8/16/32(具体含义有待研究)。
(2)有关图像操作的函数有:void cvCopyImage(src,dist)、IplImage* cvCloneImage(src)
(3)绘制矩形:void cvRectangle(point1,point2,cvScalar(R,G,B))
另外注意鼠标移动过程中矩形位置的确定,尤其是当width和heigth出现负值时的操作。
程序实现代码如下:
<span STYLE="CoLor: #
#include &cv.h&<span STYLE="CoLor: #
#include &highgui.h&<span STYLE="CoLor: #
<span STYLE="CoLor: # #pragma comment(lib,"cv.lib")<span STYLE="CoLor: #
#pragma comment(lib,"highgui.lib")<span STYLE="CoLor: #
<span STYLE="CoLor: # CvRect
<span STYLE="CoLor: # bool Drawing=false;<span STYLE="CoLor: #
<span STYLE="CoLor: # void MouseDraw(int event,int
x,int y,int
flags,void*param);<span STYLE="CoLor: #
<span STYLE="CoLor: # void DrawRect(IplImage*img,CvRect
rect)<span STYLE="CoLor: #
{<span STYLE="CoLor: # &&&&
cvRectangle(img,<span STYLE="CoLor: #
cvPoint(box.x,box.y),<span STYLE="CoLor: # &&&&&&&&
cvPoint(box.x+box.width,box.y+box.height),<span STYLE="CoLor: # &&&&&&&&
cvScalar(<span STYLE="CoLor: #xff,<span STYLE="CoLor: #x00,<span STYLE="CoLor: #x00));
<span STYLE="CoLor: # }<span STYLE="CoLor: #
<span STYLE="CoLor: # int main(int argc,char**argv)<span STYLE="CoLor: # {<span STYLE="CoLor: # &&&&
box=cvRect(<span STYLE="CoLor: #,<span STYLE="CoLor: #,-<span STYLE="CoLor: #,-<span STYLE="CoLor: #);<span STYLE="CoLor: # &&&&
cvNamedWindow("Draw_Win",CV_WINDOW_AUTOSIZE);<span STYLE="CoLor: # &&&&
IplImage*img=cvCreateImage(cvSize(<span STYLE="CoLor: #0,<span STYLE="CoLor: #0),IPL_DEPTH_8U,<span STYLE="CoLor: #);<span STYLE="CoLor: # &&&&
cvSetMouseCallback("Draw_Win",<span STYLE="CoLor: # &&&&&&&&
MouseDraw,<span STYLE="CoLor: #
(void*)img);&&&&&&&&&&&//Set
the callback function of mouse event<span STYLE="CoLor: # &&&&
cvZero(img);<span STYLE="CoLor: #
IplImage*temp=cvCloneImage(img);<span STYLE="CoLor: #
<span STYLE="CoLor: # &&&&while(<span STYLE="CoLor: #)
<span STYLE="CoLor: # &&&&
{<span STYLE="CoLor: # &&&&&&&&
cvCopyImage(img,temp);<span STYLE="CoLor: # &&&&&&&&if(Drawing)
<span STYLE="CoLor: # &&&&&&&&&&&&
DrawRect(temp,box);<span STYLE="CoLor: # &&&&&&&&
cvShowImage("Draw_Win",temp);
<span STYLE="CoLor: # <span STYLE="CoLor: # &&&&&&&&if(cvWaitKey(<span STYLE="CoLor: #0)==<span STYLE="CoLor: #)
<span STYLE="CoLor: # &&&&&&&&&&&&break;
<span STYLE="CoLor: # &&&&
}<span STYLE="CoLor: # <span STYLE="CoLor: # &&&&
cvReleaseImage(&img);<span STYLE="CoLor: # &&&&
cvReleaseImage(&temp);<span STYLE="CoLor: # &&&&
cvDestroyWindow("Draw_Win");<span STYLE="CoLor: # &&&&return
<span STYLE="CoLor: #;<span STYLE="CoLor: # }<span STYLE="CoLor: #
<span STYLE="CoLor: # void MouseDraw(int event,int
x,int y,int
flags,void*param)<span STYLE="CoLor: # {<span STYLE="CoLor: # &&&&
IplImage*img=(IplImage*)<span STYLE="CoLor: # &&&&switch(event)
<span STYLE="CoLor: # &&&&
{<span STYLE="CoLor: # &&&&case
CV_EVENT_MOUSEMOVE:<span STYLE="CoLor: # &&&&&&&&
{<span STYLE="CoLor: # &&&&&&&&&&&&if(Drawing)
<span STYLE="CoLor: # &&&&&&&&&&&&
{<span STYLE="CoLor: # &&&&&&&&&&&&&&&&
box.width=x-box.x;<span STYLE="CoLor: # &&&&&&&&&&&&&&&&
box.height=y-box.y;<span STYLE="CoLor: # &&&&&&&&&&&&
}<span STYLE="CoLor: # &&&&&&&&
}<span STYLE="CoLor: # &&&&&&&&&&&&break;
<span STYLE="CoLor: # &&&&case
CV_EVENT_LBUTTONDOWN:<span STYLE="CoLor: # &&&&&&&&
{<span STYLE="CoLor: # &&&&&&&&&&&&
Drawing=true;<span STYLE="CoLor: # &&&&&&&&&&&&
box=cvRect(x,y,<span STYLE="CoLor: #,<span STYLE="CoLor: #);<span STYLE="CoLor: # &&&&&&&&
}<span STYLE="CoLor: # &&&&&&&&break;
<span STYLE="CoLor: # &&&&case
CV_EVENT_LBUTTONUP:<span STYLE="CoLor: # &&&&&&&&
{<span STYLE="CoLor: # &&&&&&&&&&&&
Drawing=false;<span STYLE="CoLor: # &&&&&&&&&&&&if
(box.width&<span STYLE="CoLor: #)<span STYLE="CoLor: # &&&&&&&&&&&&
{<span STYLE="CoLor: # &&&&&&&&&&&&&&&&
box.x+=box.<span STYLE="CoLor: # &&&&&&&&&&&&&&&&
box.width*=-<span STYLE="CoLor: #;<span STYLE="CoLor: # &&&&&&&&&&&&
}<span STYLE="CoLor: # &&&&&&&&&&&&if
(box.height&<span STYLE="CoLor: #)<span STYLE="CoLor: # &&&&&&&&&&&&
{<span STYLE="CoLor: # &&&&&&&&&&&&&&&&
box.y+=box.<span STYLE="CoLor: # &&&&&&&&&&&&&&&&
box.height*=-<span STYLE="CoLor: #;
<span STYLE="CoLor: # &&&&&&&&&&&&
}<span STYLE="CoLor: # &&&&&&&&&&&&
DrawRect(img,box);<span STYLE="CoLor: # &&&&&&&&
}<span STYLE="CoLor: # &&&&&&&&break;
<span STYLE="CoLor: # &&&&
}<span STYLE="CoLor: # }
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。MINIGUI學習總結一
(一)MiniGUI的各種消息的區別
MiniGUI中的消息種類通常可分为系統消息、對話框消息、窗口繪制消息、窗口創建和銷毀消息、鍵盤和鼠標(後處理)消息以及用戶自定義消息。
總結使用消息時需注意的問
(一)的各種消息的區別
中的消息種類通常可分为系統消息、對話框消息、窗口繪制消息、窗口創建和銷毀消息、鍵盤和鼠標(後處理)消息以及用戶自定義消息。
總結使用消息時需注意的問題:
PostMessage和函數的區別即前者將消息置於指定窗口的消息隊列後便返回,通常用於發送一些非關鍵性信息(如鍵盤和鼠標消息),而後者則是通知指定窗口的窗口過程立即完成某項任務後才返回.“是非阻塞的,而是阻塞的。結和源碼說明,为什麼是阻塞的。注意:有兩種工作模式”
和的實現源碼,在運行模式下,僅把消息添加至消息隊列即返回成功(消息隊列滿或沒有消息隊列時都會立即返回相應的信息,故为非阻塞的);而當處理的消息在同一線程內時立即將調用窗口過程或桌面過程處理函數,當處理的消息不在同一線程時將會調用來處理,這個函數會使發送線程將阻塞(等待接收線程處理的結果)。
是同步消息,但是有同線程同步消息和異線程同步消息。牢記這個概念,對以後的調試有用。
定時器消息
()是優先級最低的消息類型,只有消息隊列中不存在其他類型的消息時,系統才會去檢查是否定時器到期。
通過閱讀源碼文件,總結出消息的優先級如下:(由高至低)
消息的確是優先級最低的,這也是部分不能通過來實現照相機延遲拍攝、秒表、錄音時間統計等功能。
<<(包括、、、、、、、、等)<(包括、、、等)
響應順序是:
SendNotifyMessage函數和類&#20284;,即不等待消息被處理就返回,但其不同在於該函數發送的消息不會因緩沖區滿而丟失。
为什麼不會丟失?而又为什麼會丟失。
Minigui針對控件的通知消息處理引入了函數,該函數可以为控件設置一個通知消息的回調函數,當控件有通知消息時,將調用該函數,而不是發送通知消息到父窗口。
當鉤子回調函數是在桌面線程中執行時,不能在該回調函數中向其他線程以方式發送消息。
關於消息的優先級,發出的消息應該是優先級最高的,其次是發出的消息,最後是發出的消息,在的所有消息中又以定時器消息的優先級最低。
幾個重要消息的使用意義:
處理該消息時不能使用等函數獲得該窗口的設備上下文,也不能在消息中建立子窗口。(原因:該消息在建立主窗口的過程中被發送,此時窗口對象未建立。對於輸入法窗口,必須在該消息處理中注冊)。
:通過改變該消息的默認處理,可使消息窗口尺寸固定。
:通過判斷該消息的返回&#20540;,可確定窗口創建添加操作是否成功。
:若窗口不允許用戶改變默認字體,則截獲該消息並返回非零&#20540;。
:窗口過程收此消息後,就可以進行一些處理一反映出新的字體設置。
:該消息在窗口重繪時發送到窗口過程,應用程序在處理完該消息後應直接返回。
:應用程序在響應該消息時調用銷毀主窗口。
:用於清除窗口背景,默認窗口過程是用背景色刷新窗口客戶區,也可在消息處理中進行填充圖片操作。
:該消息用來通知系統銷毀一個窗口。需注意的是在使用非模式對話窗口和普通主窗口時應遵循如下幾個策略:。應用程序應在消息中銷毀被托管主窗口的位圖、字體等資源;在被托管主窗口響應消息時,調用函數並調用函數;在托管主窗口中,處理消息,並調用函數。
注意的內容,這一點我們目前經常會遺漏,造成內存泄露。請說明釋放了什麼資源?
的空間,實際上就是地址所指向的內容。可以結合看一下。
二)的各種創建方式、使用條件
在中設備上下文分为圖形設備上下文、系統內存中的設備上下文和屏幕設備上下文三種。下面對上述幾種設備上下文中的創建方式和使用條件進行簡要說明。
圖形設備上下文中的創建方式和使用條件
創建的方式之一是通過函數,函數原型如下:
實際通過調用函數實現
使用條件:此函數只能在處理的消息中調用
創建的方式也可通過函數,函數原型如下:
所獲取的設備上下文是針對整個窗口
所獲取的設備上下文是針對窗口客戶區
使用條件:避免同時使用多個設備上下文,避免在遞歸中調用
創建還可通過函數原型略
使用注意:若建立主窗口時設定了風&#26684;則會自動为該窗口函數建立,或控件類具有屬性時屬於該控件類的控件也將自動建立。
在、、所描述的創建方式中,、中的在使用完後需及時釋放,而“使用注意”中兩種情況的是伴隨整個窗口生命期使用後不需另調用釋放函數。
系統內存中的設備上下文
創建方式是通過函數;函數原型:
屏幕設備上下文
MiniGUI在启動之後,就建立一個全局。該用標識,不需進行創建和釋放操作。
的复制使用:
在的主菜單源碼中函數()和()處理消息時都通過函數()把“圖形設備上下文”的复制为“系統內存中的設備上下文”,這样做之後即在系統內存中建立一個類&#20284;顯示內存的區域,然後在該區域進行圖形操作,結束後再复制到顯示內存。這種方式的意義在於繪圖速度快、能減少直接操作顯存可能造成的閃爍現象。
的使用的確可以避免閃爍,同時結合的复制,還可以實現顯示的放大、縮小,甚至通過計時器還可以實現動畫效果。當然,還有一些其他用途。
三)字串顯示風&#26684;
在中字串的顯示可通過、、、函數實現,下面依次說明各函數的功能。
TextOutLen:用來在给定位置輸出指定長度的字符串。
:用來輸出&#26684;式化字符串。
:用來輸出&#26684;式化字符串,但可以指定字符中每個鍵的位置
:以不同的對齊方式在指定的矩形內部輸出文本。
(四)窗口的創建方式和默認處理函數
窗口分为主窗口、對話框和控件三類,下面分別列出了三種窗口的創建原型和默認處理函數原型:
創建主窗口
創建模態對話框
創建非模態對話框
注冊控件類
Int& GUIAPI CreateWindow(class_name, caption, style, id, x, y, w, h, parent, add_data);//創建控件
------分隔線----------------------------
byte[] buffer=new byte[4*1024];
在Android開發中,會遇到對View的不同區域設置不同的響應事...
常用Action說明:
String ADD_SHORTCUT_ACTION 動作:在系統中添加一...
&#65279; & &前晚夢見作詩算是偶然了,可昨晚竟然又夢見寫...
Android中提供了ViewGroup、View、Activity三個等級的Touch事件處理。也...
main.xml如下:
&RelativeLayout
xmlns:android=&http://schemas.androi...企业信息化
计算机技术
座右铭:每个人在他生活中都经历过不幸和痛苦。有些人在苦难中只想到自己,他就悲观消极发出绝望的哀号;有些人在苦难中还想到别人,想到集体,想到祖先和子孙,想到祖国和全人类,他就得到乐观和自信。——洗星海
OSG开发概览日联系商易上海电子商务网站建设,了解更多
OSG开发概览
1&OSG基础知识
&O&OSG是的缩写,于年诞生于以为滑翔机爱好者之手,为了对滑翔机的飞行进行模拟,对的库进行了封装,的雏形就这样诞生了,年遇到了同样喜欢滑翔机和计算机图形学的,从此加入了小组的开发并一直担任开发小组的组长。
&O&OSG不但有的跨平台的特性和较高的渲染性能,还提供了一系列可供程序开发者使用的功能接口,包括和数据文件的加载、纹理字体支持、细节层次()控制、多线程数据分页处理等。广泛应用于飞行仿真等领域,包括,及美国军方投资的仿真项目等
1.1&计算机绘图的基本知识
&O&首先要先回顾一下,在显示世界中,我们是如何作画的。
&O&在现实世界中,绘制一副画,我们需要的东西就是彩笔、白纸。通过选择不同颜色的彩笔,在白纸上移动,就可以将白纸上的不同的点描绘上不同的颜色,而所有这些点连接起来,从人的宏观视野看来,就构成了一副对人有意义的画作。
&O&类比到计算机的实际中来。在计算机的世界里。作画的过程又是怎样的呢?
&O&同样,绘制虚拟的图像,也需要&彩笔&和&白纸&。在计算机的世界里,&彩笔&就是之类的绘图函数,而&白纸&就是存储数据的内存。我们在内存中划分出一块区域,其中的数据就是对一个真实世界的模拟。一个数据就描述真实世界中一个点的属性。在我们作画前,他们都只有一个初始值,就像白纸在作画前只有白色一样。而在作画后,每一个数据都有了独特的意义,将整片数据连接在一起看,就是一副有意义的图景。作画的过程就是对内存中的每一个数据进行赋值的过程,相当于用彩笔给白纸上的一个点进行着色。选择不同的函数,可以画出不同的形状。
1.2&OSG程序框架
&O&一个最简单的程序如下所示,当然在如果是在下面进行编辑的话要进行一些设置,要设置的和目录。
&
1 #include&osgDB/ReadFile& 2
3 #include&osgViewer/Viewer& 4
5 &void main() 6
9 osgViewer::V10 11 viewer.setSceneData(osgDB::readNodeFile("glider.osg"));12 13 viewer.realize();14 15 viewer.run();16 17 }18 &
&
&
osgViewer::Viewer&viewer 申请了一个,可以理解为申请一个观察器,该观察可以查看模型
viewer.setSceneData(osgDB::readNodeFile("glider.osg")) 这里是设置观察器中的数据,换句话说,有了观察器,就可以添加模型了
viewer.realize() 这个语句表达的意思非常多,事实上可以定位到的realize函数,会发现里面的操作非常多,可以理解为这是在渲染前的最后一步,会检查和设置图形上下文,屏幕啊什么的,会让你以前的设置,对的设置都生效。
viewer.run(); 这一句的意思就是渲染了,如果要解释它的意思的话,可以用下面的几个语句来替代:
while(!viewer.done()){viewer.frame();}.意思也就是说,只要没有结束,那么就绘制它的每一个帧[]。
1.3&OSG简单模型控制
1.3.1&添加模型
在当中模型是使用和来装载在一起的,比如同时需要加入两个模型,模型了模型,各自是一个,那么可以使用以下语句来做到,首先使用一个然后同样,之后要。然后再把添加到当中就可以了。如图所示之间的关系。在这里要申明的是是的父类,在类中都有相应的方法可以转到对方,故与
是通用的,也可以被当作来用。
&
图&31&AB都加入到Group当中
简单示例代码如下:
&
1 #include&osgDB/ReadFile& 2
3 #include&osgViewer/Viewer& 4
5 #include&osg/Node& 6
7 &void main() 8
9 {10 11 osgViewer::V12 13 osg::Group * root=new osg::Group();14 15 root-&addChild(osgDB::readNodeFile("glider.osg"));16 17 root-&addChild(osgDB::readNodeFile("osgcool.osg"));18 19 viewer.setSceneData(root);20 21 viewer.realize();22 23 viewer.run();24 25 }26 &
&
&
则运行结果为:
&
图&32示例运行结果
1.3.2&删除结点
如果我们不需要某个结点了,比如图我们看那个小飞机很不爽,我们想把它从场景中删除掉。不知道于某种目的,反正现在要删除掉,可能是开始想看见它现在不想看见它了。可以通过方法,除多个孩子也可以通过方法,里面的参数有些需要索引值,有些需要结点本身的指针,读者可以自己尝试。这里要注意的是,如果要删除一个结点,那么该结点下的所有结点都会被删除。如果一个结点被加入到一个组中两次,那么这两次是分别存在的,删除一次还有另一次。删除操作不能说不是个危险的操作,有些时候,尤其在有移动结点等等混在一起时,删除操作有时候会发生一些比较奇怪的现象。在内存映象当中,如果一个模型被读取一次,而用了多次,那么所占用的空间是不会改变的。
1.3.3&隐藏模型与结点开关
&O&隐藏模型
&&&隐藏模型其实模型仍在渲染当中,因此损耗并未减少,只不过隐藏了而已,隐藏的确不是个什么好操作,但是有时候对小模型确实也很实用。可以设置隐藏与显示。
&O&节点开关
在当中,专门有一个类来负责打开与关闭结点,该类名为,里面有相应的方法来控制它所管理的结点的打开与关闭。
两个方法都能控制模型的显示和隐藏,区别在于隐藏模型方法不会让模型在内存中消失,这样对于小的物体频繁的调用会节省一些时间,而对于有些大的模块在用一次以后可能很久再用第二次,这个时候用节点开关可以将模型销毁,再次使用再调入内存,以防止占用更多的资源。
1.3.4&超级指针
超级指针的机制,其实就是引用一个计数器,这个计数器会计算这个箱子被引用的次数,被别人引用一次这个计数器增加一,别人不用一次,即:释放一次,则计数器减一。当减至时,内存放掉不用。
们来看使用一个的三种方法对比一下:
&O&//方法一,最好的方法十分安全,也是中最常用的方法,多少版本它都没变
osg::ref_ptr&osg::Node&aNode(new&osg::Node());
group-&addChild(aNode.get());
&O&//方法二,也是非常好的方法,有时候不适用,但也十分安全
group-&addChild(new&osg::Node());
&O&//方法三,非常危险,但是令许多人无故铤而走险的方法
osg::Node*anotherNode=new&osg::Node();
group-&addChild(anotherNode);
方法一:在时申请了一个的资源,这时在堆内引用该的计算器会被置。在时又引用了一次,会再加。在这两次引用都结束时,的资源就会被释放。
方法二:这个方法也是很实用的,但是无法引出的指针,也许在别处可以用到,事实上会经常用到。如果已经这样做了,得到指针也不是不可以的,可以使用来得到的指针,也可以使用方法来做这件事。
方法三:这个应该是最常用,但是最烂的方法了,原因在于如果在之后发生了错误,抛出了异常,谁来释放所占用的资源呢。而这个异常在后面被捕获,程序正常的走下去,而内存却没有被正常的放掉。
1.3.5&移动旋转缩放模型
移动旋转缩放其实都是对矩阵进行操作,在当中,矩阵可以当作一个特殊的结点加入到当中,而矩阵下也可以另入结点,而加入的结点就会被这个矩阵处理过,比如移动过旋转过缩放过。在中控制矩阵的类为。
&O&移动
osg::Matrix::translate
&O&旋转
osg::Matrix::rotate
&O&缩放
osg::Matrix::scale
1.4&基本几何图元
1.4.1&基本绘制方法
首先来看一些中的最基本的绘制路数。如果我们要绘制一个正方形,绘制有色彩,未贴图。首先我们必须要申请一个把这个加入到就可以了。在这个中要设置一些元素,最基本的是顶点颜色以及顶点的关联方式和法线就可以了。如图所示。
&
图&33几何体绘制过程
1.4.2&可绘制的图元
所有可绘制的图元包括:
&O&POINTS[点
&O&LINES[线
&O&LINE_STRIP[线带
&O&LINE_LOOP[闭合线段
&O&TRIANGLES[三角形
&O&TRIANGLE_STRIP[三角带
&O&TRIANGLE_FAN[三角扇
&O&QUADS[四方块
&O&QUAD_STRIP[四方块带
&O&POLYGON[多边形
在中设置直线线宽的专门有一个函数来管理,叫做,它本身属于状态与属性类别中的类。事实上也是从那里派生而来。所有设置状态的操作都与此类似。
1.4.3&内置几何类型
如同一样,同样有一套内置几何类型,这些几何类型都在类中,这些本身都可以本当成一个结点加入到中,然后再人中添加到里进行渲染。形状共有九种,分别为:盒子,胶囊形,组合型,圆锥形,圆柱形,高程形,有限面,球形,三角蒙皮。
内置几何类型的渲染过程如图所示
&
图&34基本几何图元的添加过程
这里要注意的是,一般的形状态都有特定的因素,比如有长宽,圆有半径,以及各个图形所画的精细度都需要指明,这些精细度在球这样的形状上意义还是十分巨大的。在中有专门指明精细度的类,名为:。以球为例,只需要规定,圆心,半径和精细度就可以画出该球。
1.5&交互
1.5.1&交互过程
viewer的主要的功能是控制场景,它是场景的核心类,如果能响应键盘时得到,那么也可以从键盘的响应中控制整个场景。中有一个方法,名为就是专门做这件事情的。他会加入一个事件处理器。于是我们就想,一定要自己写一个事件处理器才行,这就必须要了解事件处理器的格式,只要有一个接口就可以了解它的格式,这个接口就是:,于是我们可以写一个类从该类公有派生出来,即::在里面处理好各种操作然后加入到当中,即:里面可以有参数这样就可以完成操作。
假如类是一个事件处理类,那么加入类可以这样理解,如图:
&
图&35事件A控制场景过程
&
1.5.2&事件类型与响应
代码&&&&&&&&&&&&&& & 值&&&&&&&&&   事件类型
NONE&&&&&&&&&&& & &0&&&&&&&&&&&&&   无事件。
PUSH&&&&&&&&&&& &&& &1       鼠标某键按下,在上面代码行有用到。
RELEASE&&&&&  &2       鼠标某键弹起。
DOUBLECLICK&& 4       鼠标某键双击。
DRAG&&&    & 8       鼠标某键拖动。
MOVE      16       鼠标移动。
KEYDOWN&   32       键盘上某键按下。
KEYUP&     64       键盘上某键弹起。
FRAME&     128     应该是鼠标每帧。没用过。
RESIZE&     256     窗口大小改变时会有的事件。
SCROLL&&    512     鼠标轮滚动。
PEN_PRESSURE& 1024     手写板的某事件?
PEN_PROXIMITY_ENTER& 2048   手写板的某事件?
PEN_PROXIMITY_LEAVE & 4096   手写板的某事件?
CLOSE_WINDOWS&   8192   关闭窗口。
QUIT_APPLICATION&   16384   退出程序。
USER&          32768   用户定义。
至于为什么都用的次方,主要是因为它的二进制编码只有一位是一,判断事件时很好判断,只要年哪位是一就可以了。
1.5.3&PICK
pick主要是通过鼠标的点击来拾取一些物体,或者判断鼠标所点击的位置在哪里。Pick实现的思路如下图所示:
&
图&36pick事件流程
判断射线与中物体相交的方法为发出射线并相交。在中有库函数,他共有三个参数:第一个是屏幕坐标,第二个是屏幕坐标,第三个是存放被交的结点以及相交的坐标结点路径等等相关信息。
判断相交结点为我想要的那个结点:只需要判断存放相交射线交场景的结果集中有没有要用的结点就可以了。
&
1.6&漫游
1.6.1&MatrixManipulator
场景的核心管理器是,而漫游必须响应事件,比如鼠标动了,场景也在动。响应事件的类是。我们想把响应事件的类派生一个新类出来,这个类专门用来根据响应控制。这个类就是,这个类有一些设置矩阵的公共接口,有了这些接口就可以有效的控制了,根据不同的习惯,大家还会设置不同的控制方式,如同自带的几个操作器,操作都不尽相同。来看一下漫游的主要流程如图:
&
图&37一般的场景操作器
操作器必须从派生而来。有四个可以控制场景的重要接口:
&
1 virtual void setByMatrix(const osg::Matrixd&matrix)=02 3 &virtual void setByInverseMatrix(const osg::Matrixd&matrix)=04 5 &virtual osg::Matrixd getMatrix()const=06 7 &virtual osg::Matrixd getInverseMatrix()const=08 &
&
&
四个矩阵接口可以有效的向来传递矩阵的相关信息。
1.6.2&碰撞检测
最简单的碰撞检测如下图所示:
&
图&38简单的碰撞检测原理图
TravelManipulator.dll中用到的就是如图所示的原理,黑三角形代表没有移动之的位置,控制移动的函数是,参数意思是要移动的相对于当前点的增量,在黑三角形没有移动时该函数在计算时先假设一点为移动后的点,而后通过连接这两个点,而后通过判断与场景的模型是否有交点来判定这个移动可不可以执行,如图所示,两者之间有个大盒子,是穿不过去的,所以只有保持在原地。就算没有这个盒子,移动后的新点又与地面在某种程序上有一个交点,这证明移动是不可行的。这可以防止用户穿过地板到达地下去。
1.6.3&路径漫游
使用文件的方法如下面示例
&
1 #include&osgDB/ReadFile& 2
3 #include&osgViewer/Viewer& 4
5 #include&osg/Node& 6
7 #include&osgGA/AnimationPathManipulator& 8
9 &void main()10 11 {12 13 osgViewer::V14 15 viewer.setSceneData(osgDB::readNodeFile("glider.osg"));16 17 &//申请一个操作器,参数为一个path文件。18 &19 osg::ref_ptr&osgGA::AnimationPathManipulator&amp=new osgGA::AnimationPathManipulator("glider.path");20 21 &//选择使用这个操作器。22 &23 viewer.setCameraManipulator(amp.get());24 25 viewer.realize();26 27 viewer.run();28 29 }30 31 &
&
&
我们可以用路径编辑器编辑文件,或者可以控制程序中的某个物体的运动轨迹然后保存为文件。
1.7&更新&回调
回调的意思就是说,你可以规定在某件事情发生时启动一个函数,这个函数可能做一些事情。这个函数就叫做回调函数,我们可以使用已有回调函数或者自定义回调函数。
&O&使用已有回调
已有的回调的类型有很多种,一般很容易就想到的是,或者等
&O&自定义回调
自定义回调为从一个回调类型派出生自己的回调,然后具有该种回调的特点等等。
NodeVisitor是一个极有用的类,可以访问结点序列,使用的方法大同小异,的工作流程如下图所示:
&
图&39NodeVisitor工作流程
在主结点之后,结点数据立即传至中去,应用函数,可以将数据定任一些操作,更多的操作还是需要硬性的制做与调用。
1.8&粒子系统初步
在中提供有专门的粒子系统工具,名字空间为,对经常使用的粒子模拟都做了专门的类,如:用于暴炸的模拟,用于火的模拟,用于爆炸后四散的颗粒模拟等等。
在中使用粒子系统一般要经历以下几个步骤:
第一步:确定意图(包括粒子的运动方式等等诸多方面)。第二步:建立粒子模版,按所需要的类型确定粒子的角度(该角度一经确定,由于粒子默认使用有所以站在任何角度看都是一样的),形状(圆形,多边形等等),生命周期等。第三步:建立粒子系统,设置总的属性,第四步:设置发射器(发射器形状,发射粒子的数目变化等),第五步:设置操作(旋转度,风力等等因素)。第六步:加入结点,更新。下图描述了各个部分是协调工作的方式:
&
图&310粒子系统各个部分是协调工作的方式
上图中各个部分所对应的类如下图所示
&
图&311粒子系统各部分对应的类
&
1.9&视口&LOD&Imposter
1.9.1&多视口
多视口的原理是自己创建所有的相机,包括主相机,这样我们可以随意的添加相机。
首先我们要创建视口必须有以下几件东西,第一,了解整个屏幕的分辩率有多大,这样可以分辩视口的大小,好分割开来。第二,上下文。我们必须自己手动的打开设置上下文。每个视口的数据也不一定非要与主视口的相同。但是矩阵一般是同步的。也就是说:主视口里有栋楼,从视口里可以是平面图什么的。了解整个屏幕的分辩率可以用这个类:意思是说系统接口,可以获得当前环境的各种信息。有一方法叫,可以得到分辩率。之后上下文了,里面可以设置窗口大小,缓存什么的,大多数的东西都在这里面设置。
1.9.2&LOD
LOD即
LOD比起而言并非十分的常用,有个地方用的特别多,那就是把一个好好的模型加一个视矩压成一个模型,这个模型比以前的看来就是多了个视矩的控制,远了看不见,近了能看见。
在模型中加头结点的方式如下所示:
&
1 #include&osgDB/Registry& 2
3 #include&osgDB/ReadFile& 4
5 #include&osgDB/ReaderWri ter& 6
7 #include&osgDB/Wri teFile& 8
9 #include&osg/Node&10 11 #include&osgViewer/Viewer&12 13 &int main()14 15 {16 17 osgViewer::V18 19 &//读取模型20 &21 osg::Node*node=osgDB::readNodeFile("fountain.osg");22 23 &//隐藏结点24 &25 node-&asGroup()-&getChild(0)-&setNodeMask(0);26 27 viewer.setSceneDa ta(node);28 29 &//输出结点到free.os g中30 &31 osgDB::writeNodeFile(*(viewer.getSceneData()),"free.osg",osgDB::Registry32 33 ::instance()-&getOptions());34 35 &return 0;36 37 }38 39 &
&
&
1.9.3&Imposter
用动态图片来替换场景的实用技术:可以把它法做一样使用,只不过它
不是变模型变没有,而是使它换成一张图
示例代码如下:设置一个视矩,超过这个视距模型会变为一张动态图
&
1 #include&osgViewer/Viewer& 2
3 #include&osgGA/TrackballManipulator& 4
5 #include&osgSim/Impostor& 6
7 #include&osgDB/ReadFile& 8
9 &int main(inta rgc,cha r**a rgv)10 11 {12 13 &//申请viewer14 &15 osgViewer::V16 17 //读取模型18 19 osg::Node*node=osgDB::readNodeFile("ceep.ive");20 21 //申请一个i mpos tor结点22 23 osgSim::Impos tor*sim=new osgSim::I24 25 //在到之内显示模型,之外显示贴图26 27 sim-&addChild(node,0,50000);28 29 sim-&setImpostorThreshold(1000);30 31 osg::Group*root=new osg::G32 33 root-&addChild(sim);34 35 viewer.setSceneData(root);36 37 viewer.realize();38 39 viewer.run();40 41 return 0;42 43 }44 45
&
&
1.10&文字&模型阴影
1.10.1&HUD&
HUD即
文字在场景中显示往往要经历以下几步:读取字体点阵信息转化为图像反走样最终图像。在反走样期间可以处理可种模糊效果,在最终图像形成时可以设置如何摆放。中有一个类,提供可很多文字显示的方法,比如
&
1 void setFont(Font*font=0) 2
3 //设置/得到字体,如setFont("fonts/SIMYOU.TTF"); 4
5 void setFont(const std::string&fontfile) 6
7 const Font*getFont()const 8
9 //设置/得到字体显示的宽高10 11 void setFontResolution(unsigned int width,unsigned int height)12 13 unsigned int getFontWidth()const14 15 unsigned int getFontHeight()const16 17 //设置/得到文字的具体内容18
&
&
等等,可以很方便的调用
1.10.2&阴影
OSG对阴影的支持也相当的好,可以很容易的写出简单的阴影效果,可以参考例子
OSG有一个专门的类来支持阴影效果,提供了很多接口,如:
&
1 void setBackdropType(BackdropType type) 2
3 //说明:设置阴影类型。 4
5 void setBackdropOffset(float offset=0.07f) 6
7 void setBackdropOffset(float horizontal,float vertical) 8
9 //说明:设置阴影的离开程度与方向10 11 void setBackdropColor(const osg::Vec4&color)12 13 //说明:设置阴影颜色14 15 void setColorGradientMode(ColorGradientMode mode)16 17 //说明:设置颜色映射方式,可以得到渐变效果18
&
&
等等
&
PS:本文为几个月前整理,参考书:FreeSouth的《QpenSceneGraph程序设计》
Admin
好文章,让大家一起欣赏:
此页面上的内容需要较新版本的 Adobe Flash Player。

我要回帖

更多关于 drawtext函数 的文章

 

随机推荐