第一次铁幕解答及OPENGL的入门

输出其实分两部分。

 

一部分就是从NI中获取的深度/彩色图像数组,这个你已经懂得了,然后循环把这些像素存储到纹理像素数组中,你可以找到这段循环的代码。

 

另一部分,就是在Display中,设置OpenGL渲染管线,启用纹理,指定纹理数组地址及启用方式,然后通过在屏幕中Z坐标位0的位置上,绘制一个带纹理的平面。

 

也就是,真正绘制的地方,是跟NI没关系的,就负责绘制一个数组到指定纹理。而你要在每一帧的绘制之前,从NI中取得数据,填充那个数组。

 

 

 

日期:2011/6/22
回复
激情の小力 18:13:10 
好的,那這個原始數據的大小應該是: 640x480個格子的矩陣,每一個格子的值是一個 8bit無符號整數 對嗎?

回复
激情の小力 18:13:42 
還是,每一個格子包含 8X3 bit ?因為是RGB
回复
铁幕诱惑 18:13:44 
彩色的,应该是24BIT
回复
激情の小力 18:13:53 
嗯嗯好的
回复
铁幕诱惑 18:14:56 
NI中,typedef了这个类型 XnRGB24Pixel
回复
激情の小力 18:16:51 
好的,
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
// Setup the OpenGL viewpoint
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
這裡,glPushMatrix(); 指定當前矩陣為有效矩陣,glLoadIdentity();是讓矩陣原點居中

我對這兩個函數的理解是:因為這個的GL輸出用的是雙緩存,

當一副紋理映射輸出時,下一幅紋理在後臺進行處理,然後他們之間交換,以達到smooth的效果。所以每次交換后,都要進行這兩個函數。這麼理解可以嗎?

回复
铁幕诱惑 18:19:26 
glMatrixMode
用来指定当前投影模式,具体可以参考API,就三种。GL_PROJECTION为正交投影
回复
铁幕诱惑 18:20:11 
但是掉用过这句指定投影模式的函数,并不会立即生效,必须LoadIdentity才会让其生效。
回复
激情の小力 18:20:30 
原來是這樣~
回复
激情の小力 18:20:42 
好的
回复
铁幕诱惑 18:22:16 
如果怕这么指定的投影模式对之前绘制的东西产生影响,比如我先用透视投影绘制了很多,突然想用正交投影了,为了不影响之前的渲染内容,那么将之前的矩阵压栈PushMatrix,这样,接下来我们绘制的内容,就是在新矩阵模式中操作了,不影响之前的。
回复
铁幕诱惑 18:22:51 
同理,你现在用正交投影模式绘制很多内容,以后还想在后面采用其他模式继续绘制,为了不影响现有的,再操作一次。
回复
铁幕诱惑 18:23:04 
glMatrixMode(
你要的模式);
glPushMatrix();
glLoadIdentity();
回复
激情の小力 18:24:50 
好的,這部份我能理解了,感謝~~,詳細的我自己再去學習調查!
接下來我想問一下這兩個函數,

glOrtho(0, GL_WIN_SIZE_X, GL_WIN_SIZE_Y, 0, -1.0, 1.0); 
xnOSMemSet(g_pTexMap, 0, g_nTexMapX*g_nTexMapY*sizeof(XnRGB24Pixel));

glOrtho — multiply the current matrix with an orthographic matrix
我不太明白,爲什麽要讓當前矩陣乘以正交矩陣,而且,是哪個矩陣乘以正交矩陣呢?


回复
铁幕诱惑 18:25:52 
矩阵相乘,这在数学上不正好是设置剪裁范围么 -_-#
回复
激情の小力 18:26:38 
哦哦,那就是  我設置的窗口與輸入圖像 兩個矩陣相乘,也就是把原始圖像剪裁?
回复
铁幕诱惑 18:26:39 
假设一个全部值为1的矩阵,乘以你指定的新矩阵,结果是什么?
回复
铁幕诱惑 18:27:02 
这个原始图像,你应该理解为GL内置的渲染矩阵
回复
铁幕诱惑 18:27:51 
就假象那是个无限大的矩阵,然后乘以你的矩阵,最后结果就是你所指定的宽、高、远、近
回复
铁幕诱惑 18:27:54 
明白?
回复
激情の小力 18:28:50 
啊!!我明白了,glOrtho 這個函數就是 我建立的窗口  一個無限大矩陣相乘?
回复
铁幕诱惑 18:29:33 
也就是说,你在一个三维空间里指定了一个盒子,GL只负责渲染你绘制在盒子之内的东西,绘制在盒子之外,它不会渲染,因为从你的视口看过去,那些是不可见的。
回复
激情の小力 18:32:59 
額,我還是不太明白,就這個函數來說,glOrtho()括號里的信息在這個代碼里,其實是我所創建的窗口的信息(雖然我肉眼看這個窗口是二維,但是參數表里,卻有Z方向,-1.0, 1.0),也就是說,可以理解為這個是個盒子?
回复
铁幕诱惑 18:34:04 
恩,窗口是窗口,剪裁范围是剪裁范围。
回复
铁幕诱惑 18:34:24 
glOrtho
是设置剪裁范围,glViewPort才是视口
回复
铁幕诱惑 18:35:02 
就比如你这个例子,z near  z-far 分别是 1  -1
回复
激情の小力 18:35:09 
嗯嗯是的,
回复
铁幕诱惑 18:35:38 
那么,假如你绘制一个顶点,但是Z参数指定为 -2,那么,这个点将被OpenGL抛弃
回复
激情の小力 18:35:52 
可以理解為 640 x 480 的面積,厚  2 盒子嗎?
回复
铁幕诱惑 18:35:59 
是的
回复
激情の小力 18:36:05 
好的,我想想
回复
铁幕诱惑 18:37:43 
就是这个范围,因为我们接下来的目的,是往这个方块的正中间,显示一副640x480的带纹理的方块,也就是Z轴为0的位置上放置一个平面。所以-1  1 就足够了
回复
激情の小力 18:37:51 
我大概能理解到了,那這個函數就是要剪裁 這個 盒子里的信息。

那請問第二個函數是?
回复
铁幕诱惑 18:37:53 
其实你可以指定的更大,但没意义
回复
铁幕诱惑 18:38:19 
xnOsMemSet
是为了通用性,考虑到跨平台……
回复
激情の小力 18:38:24 
好的~
回复
铁幕诱惑 18:38:34 
windos下,你可以理解这就是memset的另一种写法……
回复
激情の小力 18:38:48 
原來是這樣,我能理解,盒子這個概念很好^_^
回复
激情の小力 18:39:27 
嗯,好的,那我就先繼續往下看
回复
激情の小力 18:39:47 

回复
激情の小力 18:40:52 
進行到這裡,
我們有了 const XnUInt8* pImage = g_imageMD.Data();  pImage存放原始圖像。
而這裡    const XnRGB24Pixel* pImageRow = g_imageMD.RGB24Data(); 這一步是什麽意思呢?
回复
激情の小力 18:41:40 
pImageRow 
是一個 單位為24bit  新矩陣了嗎?
回复
铁幕诱惑 18:45:54 
这也不是矩阵……
回复
铁幕诱惑 18:46:09 
这个是数组,row不是行么……
回复
铁幕诱惑 18:48:28 
还有问题?
回复
激情の小力 18:49:41 
嗯是的,可是因為是  我就更不理解了= =
嗯抱歉,口誤。。之前用了好久matlab。。

這裡 pImageRow = g_imageMD.RGB24Data(),是否是原始圖像一行的信息呢?
 pImage = g_imageMD.Data();  有何區別呢?
回复
激情の小力 18:51:48 
我對 XnUInt8*   XnRGB24Pixel* 比較不理解,

如果 const XnUInt8* pImage = g_imageMD.Data();  是存放了一幀圖像。
       const XnRGB24Pixel* pImageRow = g_imageMD.RGB24Data(); 
存放一行圖像。

行信息怎麼是 3x8bit, 圖像是 8bit?
回复
铁幕诱惑 18:52:25 
在循环之外,指定pImageRow指向原始图像数据第一行。
for(y=0;…………)这个循环内,每次循环结束 pImageRow+=g_ImageMD.xres(),不就是串到下一行了么……
回复
铁幕诱惑 18:53:08 
pImage = g_imageMD.Data(); 
至于这句,我怎么没看到 -_-#
回复
铁幕诱惑 18:53:37 


我只看到在y循环里,有这句……
回复
激情の小力 18:54:02 

const XnUInt8* pImage = g_imageMD.Data(); 
這一句在開頭

回复
铁幕诱惑 18:55:53 
这个2B作者,它写了却不用,这句你可以删掉了,没有任何意义……
回复
激情の小力 18:56:15 
額額。。。這。。是版主寫的= =
回复
铁幕诱惑 18:57:14 
那也是没用的
回复
激情の小力 18:57:18 
他用了呀,在接下來的循環中有用到。
回复
铁幕诱惑 18:57:25 
很明显,逻辑不严谨
回复
铁幕诱惑 18:57:56 
你把整个display的代码拷贝进来就行,不用截图
回复
激情の小力 18:57:59 
好的
回复
激情の小力 18:58:10 
void glutDisplay (void)
{

int tmp=0;
static int flag=0;
g_context.WaitAnyUpdateAll();
g_image.GetMetaData(g_imageMD);
const XnUInt8* pImage = g_imageMD.Data();
unsigned int nImageScale = GL_WIN_SIZE_X / 640;
// Copied from SimpleViewer
// Clear the OpenGL buffers
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup the OpenGL viewpoint
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, GL_WIN_SIZE_X, GL_WIN_SIZE_Y, 0, -1.0, 1.0);//multiply current matrix with 
xnOSMemSet(g_pTexMap, 0, g_nTexMapX*g_nTexMapY*sizeof(XnRGB24Pixel));
/
if(flag == 0)
{

printf("g_nTexMapX*g_nTexMapY*sizeof(XnRGB24Pixel)=%ld/n",
g_nTexMapX*g_nTexMapY*sizeof(XnRGB24Pixel));
}
//
const XnRGB24Pixel* pImageRow = g_imageMD.RGB24Data();
XnRGB24Pixel* pTexRow = g_pTexMap + g_imageMD.YOffset() * g_nTexMapX;
for (XnUInt y = 0; y < g_imageMD.YRes(); ++y)
{
const XnRGB24Pixel* pImage = pImageRow;
XnRGB24Pixel* pTex = pTexRow + g_imageMD.XOffset();
for (XnUInt x = 0; x < g_imageMD.XRes(); ++x, ++pImage, ++pTex)
{
*pTex = *pImage;
if(x==320||x==319||x==321||y==239||y==240||y==241)
{
*pTex = (const XnRGB24Pixel &)tmp; 
}
}
pImageRow += g_imageMD.XRes();
pTexRow += g_nTexMapX;
}
if(flag == 0)
{

printf("g_imageMD.XRes()=%d/n",g_imageMD.XRes());
printf("g_imageMD.YRes()=%d/n",g_imageMD.YRes());
}
// Create the OpenGL texture map
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, g_nTexMapX, g_nTexMapY, 0, GL_RGB, GL_UNSIGNED_BYTE, g_pTexMap);


// Display the OpenGL texture map
glColor4f(1,1,1,1);

glBegin(GL_QUADS);
int nXRes = 640;
int nYRes = 480;

if(flag == 0)
{

printf("g_depthMD.FullXRes()=%d/n",nXRes);
printf("g_depthMD.FullYRes()=%d/n",nYRes);
}
//
// upper left
glTexCoord2f(0, 0);
glVertex2f(0, 0);
// upper right
glTexCoord2f((float)nXRes/(float)g_nTexMapX, 0);
// glTexCoord2f(0.6, 0);
glVertex2f(GL_WIN_SIZE_X, 0);
// bottom right
glTexCoord2f((float)nXRes/(float)g_nTexMapX, (float)nYRes/(float)g_nTexMapY);
glVertex2f(GL_WIN_SIZE_X, GL_WIN_SIZE_Y);
// bottom left
glTexCoord2f(0, (float)nYRes/(float)g_nTexMapY);
glVertex2f(0, GL_WIN_SIZE_Y);

glEnd();
// Swap the OpenGL display buffers
glutSwapBuffers();
flag = 1;
}
回复
铁幕诱惑 18:58:47 
const XnUInt8* pImage = g_imageMD.Data();
unsigned int nImageScale = GL_WIN_SIZE_X / 640;
回复
铁幕诱惑 18:59:02 
这两句,可能刚设计的时候想用,但是对本程序一点意义没有
回复
铁幕诱惑 18:59:05 
他没用上
回复
铁幕诱惑 18:59:07 
删掉
回复
铁幕诱惑 19:00:00 
for (XnUInt y = 0; y < g_imageMD.YRes(); ++y)
{
const XnRGB24Pixel* pImage = pImageRow;
XnRGB24Pixel* pTex = pTexRow + g_imageMD.XOffset();
for (XnUInt x = 0; x < g_imageMD.XRes(); ++x, ++pImage, ++pTex)
{
*pTex = *pImage;
if(x==320||x==319||x==321||y==239||y==240||y==241)
{
*pTex = (const XnRGB24Pixel &)tmp; 
}
}
pImageRow += g_imageMD.XRes();
pTexRow += g_nTexMapX;
}

循环内部用的pImage,在Y循环里定义的,不是那个pImage
回复
激情の小力 19:00:20 
好的,那一幀圖像所存放的位置 應該是 
const XnRGB24Pixel* pImageRow = g_imageMD.RGB24Data();

存放在 pImageRow 里吧?循環里的 pImage只是個變量
回复
激情の小力 19:00:35 
嗯嗯,好的
回复
激情の小力 19:01:09 
所以 pImageRow 不應該這麼叫,沒有ROW這個字眼
回复
铁幕诱惑 19:01:51 
pImageRow,
用来指定每行图像的起始地址,随着Y变量每循环一次,递增到下一行。
回复
铁幕诱惑 19:02:34 
pImage
,用来指定当前行(pImageRow)的第X像素,起始位置在当前行第一个像素,随着X变量循环,递增到下一个像素
回复
铁幕诱惑 19:03:25 
for (XnUInt x = 0; x < g_imageMD.XRes(); ++x, ++pImage, ++pTex)
这是pImage递增的方式,采用的是++,也就是一次向后移动sizeof(XnRGB24Pixel)大小,正好是下一个像素
回复
激情の小力 19:04:09 
原來是這樣,好的,一下子清楚多了。
回复
铁幕诱惑 19:04:17 
pImageRow += g_imageMD.XRes();
这是pImageRow的递增方式,XRes()640,所以pImageRow每次循环,移动640xsiezof(XnRGB24Pixel),正好是一行
回复
激情の小力 19:05:40 
好的!我理清一下
回复
激情の小力 19:09:02 
那么說,這個代碼是一行一行從KINECT讀取的,而不是一次讀取一幀圖像存儲下來嘍?
回复
激情の小力 19:11:12 
XnRGB24Pixel* pImageRow = g_imageMD.RGB24Data();
因為這裡用的函數,好像是讀取一行
回复
铁幕诱惑 19:11:28 
整个签到循环完毕,就将一帧图像的所有数据,保存到纹理数组中了。
回复
铁幕诱惑 19:11:35 
当然,作者还干了点别的
回复
激情の小力 19:11:59 
嗯,if(x==320||x==319||x==321||y==239||y==240||y==241)
我刪掉了,他是想四分割
回复
铁幕诱惑 19:13:23 
XnRGB24Pixel* pImageRow = g_imageMD.RGB24Data();
这句就是让pImageRow指向图像数据的起始位置,只不过是通过后面的逻辑代码,以递增的方式实现了一次Y循环一行的功能
回复
激情の小力 19:14:13 
啊,我明白了!!!
回复
激情の小力 19:14:32 
太謝謝您了~~
回复
铁幕诱惑 19:15:28 
也就是说,如果不考虑kinect的数据偏移问题,一句话就可以完成图像数据拷贝至纹理数组
memcpy(g_pTexMap,g_imageMD.RGB24Data(),640x480x3);
640
480以及3的含义,你应该懂
回复
激情の小力 19:16:13 
明白了~~g_imageMD.RGB24Data()返回是一個數組,pImageRow 剛開始指向這個數組(一幀圖像)的首地址,隨後循環中疊加進行運算,循環出來了就是一幀圖像的紋理處理
回复
铁幕诱惑 19:17:08 
是的 ^_^
回复
激情の小力 19:17:31 
您指的 數據偏移問題 是指?
memcpy(g_pTexMap,g_imageMD.RGB24Data(),640x480x3);
這個從字面意思是很好理解(數組賦值)
回复
激情の小力 19:18:09 
是哦,爲什麽不直接將 圖像數組 賦值 給紋理數組呢,還需要一個像素一個像素賦值
回复
铁幕诱惑 19:18:59 
便于你进行其他操作
回复
激情の小力 19:20:56 
嗯嗯,可以隨著輸入圖像一個像素一個像素的輸入,進行一些圖像處理功能。
如果一口氣將圖像拷貝進紋理數組,然後再進行圖像處理和輸出,會浪費不少時間。
所以這麼做,看似打散了,其實可以壓榨很多時間嘍?
回复
铁幕诱惑 19:21:20 
另外,根据配置不同,NI提取出的kinect图像,可能有一段空白,它提取出一幅800x600的图像,而实际上有内容的地方确实640x480,那么一行就是800个像素,可我们在这一行只需要循环640次,另外的160个像素就直接丢弃掉了,如果真是这样,那么memcpy就不对了,不会拷贝完整的图像,而且也拷贝了很多无用的像素。
回复
激情の小力 19:22:14 
嗯嗯,這倒是,這麼做比較靈活
回复
激情の小力 19:22:27 
也提高了效率
回复
铁幕诱惑 19:22:29 
你终于明白了
回复
激情の小力 19:23:02 
感謝您的指導,讓我明白了這麼多,太謝謝您了
回复
激情の小力 19:24:13 
佔用了您不少時間,謝謝您的無私幫助!
回复
铁幕诱惑 19:24:18 
不客气 ^_^
回复
激情の小力 19:25:17 
我把聊天記錄存起來,好複習= = 
回复
铁幕诱惑 19:26:58 
-_-#
回复
铁幕诱惑 19:28:02 
你还是自己从头写一个,不要拷贝代码,首先认真的思考下流程,然后又条例的实现它,具体到某个函数不记得了,可以参考这个例子。另外记得写有你自己风格的注释。
回复
铁幕诱惑 19:28:22 
这是最能一次成型的学会某种技术
回复
激情の小力 19:28:46 
好的,我今晚就重新編寫~

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

orta

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值