Re: [問題] 關於OpenGL貼圖的問題

看板C_and_CPP (C/C++)作者 (雲伴風 風隨雲)時間14年前 (2011/02/23 18:25), 編輯推噓17(170101)
留言118則, 5人參與, 最新討論串2/2 (看更多)
※ 引述《bbbbbbjeff (雲伴風 風隨雲)》之銘言: : 各位網友好,想請教關於用OpenGL貼圖的問題, : 目前用VC++ 2010的Windows Form專案寫了一個程式,需要貼 : 很多張圖,目前遇到的問題是所貼的圖其寬高在某些維度程式會爆 : ,某些維度不會??? 看超級手冊第2版第8章貼圖的部分有提 : 到寬高必須是2的冪次方,但我發現只要顯示卡是nVidia的晶 : 片不用2的冪次方也可以貼,而且每張貼圖大小可以不同,例如 : 下面兩張擷圖: : 1 : http://homepage8.seed.net.tw/web@5/bbbbbb/TemporaryShare/Texture1.jpg
: 2 : http://homepage8.seed.net.tw/web@5/bbbbbb/TemporaryShare/Texture2.jpg
: 在第1張擷圖內共貼3張圖,第1張貼圖的寬高是1000*600, : 第2張貼圖的寬高是3000*2000 : 在第2張擷圖內,是第1張擷圖沿著y軸轉180度,可以看到第3張貼圖, : 第3張貼圖的寬高是1920*1200 : 也就是說,3張貼圖的寬高完全不是2的冪次方也可以貼,只要顯示卡是 : nVidia的晶片就ok。(在Intel的顯示卡上就完全不行,變成空白一片) : 現在我的問題是,3000*2000都可以貼了,若小很多的應該沒問題才是 : ,但我試了以下幾種寬高,有的可以有的不行?? : 999*1000 ==>不行 ??? : 1000*1000 ==>可以 : 537*590 ==>可以 : 199x203 ==>可以 : 1999x2003 ==>不行 ??? : 我有以 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTextureSize); : 去測試我的卡可以顯示的最大維是:8192,所以不能貼應該不是太大 : 才對... : 請問是否有網友知道問題在哪?? 抱歉,上一篇文可能說得不夠仔細,我提到的貼某些維度的圖 會程式會爆的意思是,程式就直接寫錯誤,然後就關閉了,以 下是目前我在 GeForce 8600GTS 測試會錯誤的維度: 999*1000 (24Bits bmp檔) 1999x2003 (24Bits jpg檔) 2854x2894 (24Bits jpg檔) 我讀檔的方式主要是用 .NET Framework 提供的 Bitmap 物件,搭配 Bitmap 物件內的 LockBits 函式 將好幾張影像鎖在記憶體內,再取 出RGB三個通道的值,存到三維陣列內。不管是bmp jpg tif ...都是這樣 取出RGB三個通道的值。如果是8bits灰階圖,也是用一樣這個方式讀, 只是我還是將它視為24bits的圖,以三個通道的記憶體去存一張8bits 的圖,三個通道的灰階值設都設為一樣就存到一個三維陣列內就是了。 接著再 new 一個 GLubyte **Pixels,將存到三維陣列內的值轉存到 GLubyte型態的二維陣列內,並且三維的值要存成一維,以符合glTexImage2D() 此函式的規定。以下是我在此函式內的參數: glTexImage2D(GL_TEXTURE_2D, 0, 3, Images[z]->Width, Images[z]->Height, 0, GL_RGB, GL_UNSIGNED_BYTE, Pixels[z]); z就代表第z張image。 反覆看了可以貼圖的影像寬高與無法貼圖的影像寬高,還是不懂為什麼 有些可以貼,有些一貼程式就出現錯誤而停?? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.116.82.254

02/23 22:21, , 1F
這個問題是像素未達到memory alignment導致.
02/23 22:21, 1F

02/23 22:22, , 2F
長及寬 都要可以除以 某個值(譬如說4)
02/23 22:22, 2F

02/23 22:22, , 3F
確切的值多少要查. 總之npot 是讓你不用 512 , 1024 這樣跳
02/23 22:22, 3F

02/23 22:23, , 4F
但也並非是任何 長寬像素都允許 ,算是一個潛規則
02/23 22:23, 4F

02/23 22:25, , 5F
總之.不要故意找麻煩.把貼圖放大/加空白 到標準的解析度再傳
02/23 22:25, 5F

02/23 22:27, , 6F
就算有NPOT,到顯示卡裡面還是2^n次方.只是顯示卡幫你填空白
02/23 22:27, 6F

02/23 22:40, , 7F
謝謝指點,我試看看
02/23 22:40, 7F

02/23 23:47, , 8F
N大說的是Gfx HW這端的可能實作方式, 但是spec上並沒有
02/23 23:47, 8F

02/23 23:48, , 9F
對寫AP的programmer定出這樣的限制; 所以如果真的是N大
02/23 23:48, 9F

02/23 23:48, , 10F
所提的問題, 那是Gfx的driver或HW沒有處理好這個feature
02/23 23:48, 10F

02/23 23:49, , 11F
, 這應該是Gfx端的bug. 所以請問原po用的顯示卡與驅動程
02/23 23:49, 11F

02/23 23:50, , 12F
式版本.
02/23 23:50, 12F

02/23 23:51, , 13F
啊, 看到是86GTS了, 先試著換driver到新一點的版本試試,
02/23 23:51, 13F

02/23 23:51, , 14F
(但不要到最新, N家A家的最新版驅動對舊世代顯卡通常都
02/23 23:51, 14F

02/23 23:52, , 15F
不是最佳的); 如果可以的話找不同家顯卡或不同世代的卡
02/23 23:52, 15F

02/23 23:52, , 16F
也交叉測試看看. (當然檢查NPOT的支援還是要做的XD)
02/23 23:52, 16F

02/23 23:58, , 17F
剛發現漏了一個盲點, 程式錯誤要關閉前有訊息告知你錯誤
02/23 23:58, 17F

02/23 23:59, , 18F
昨天剛更新到最新版...
02/23 23:59, 18F

02/23 23:59, , 19F
的module是哪個嗎??或者可以看看windows的事件檢視器.
02/23 23:59, 19F

02/24 00:00, , 20F
主要是希望釐清問題是texture餵給GL畫以後才發生, 還是
02/24 00:00, 20F

02/24 00:00, , 21F
讀/解圖檔的時候使用的lib或中間自己處理的code有疏乎:)
02/24 00:00, 21F

02/24 00:03, , 22F
沒有告訴我是哪個模組錯,只寫Project.exe已經停止運作
02/24 00:03, 22F

02/24 00:05, , 23F
還有個除錯的按鈕可按,按下後出現一個訊息: 於0x0573f
02/24 00:05, 23F

02/24 00:06, , 24F
c29 的Project.exe 中發生未處理的例外狀況: 0xC000000
02/24 00:06, 24F

02/24 00:07, , 25F
5: 讀取位置0x0e00c001 時發生存取違規.
02/24 00:07, 25F

02/24 00:07, , 26F
0xC0000005嗎?? 這個比較像是您的code或其他SW的lib端出
02/24 00:07, 26F

02/24 00:08, , 27F
錯ㄟ.... 啊, 不好意思, 不小心斷到....Orz
02/24 00:08, 27F

02/24 00:09, , 28F
我按下中斷後,反組譯碼有個黃箭頭停在這一行:
02/24 00:09, 28F

02/24 00:09, , 29F
疑!?原來沒斷到XD 按下除錯後應該還會有VC的視窗導引你
02/24 00:09, 29F

02/24 00:09, , 30F
0573FC29 movzx ebx,byte ptr [esi+2]
02/24 00:09, 30F

02/24 00:09, , 31F
除錯程序, 找找看error發生的斷點是不是你的source code
02/24 00:09, 31F

02/24 00:10, , 32F
不是的話, 就看一下執行位址(就是0573FC29), 在VC的
02/24 00:10, 32F

02/24 00:10, , 33F
module list頁籤裡, 是屬於哪一個.exe或.dll的.
02/24 00:10, 33F

02/24 00:13, , 34F
除錯後發現,中斷在glTexImage2D()出現的那行
02/24 00:13, 34F

02/24 00:15, , 35F
我讀999*1000的彩色BMP,中斷在glTexImage2D()這行
02/24 00:15, 35F

02/24 00:18, , 36F
查一下call glTexImage2D這行時傳進去的圖檔指標, 算一
02/24 00:18, 36F

02/24 00:19, , 37F
一下 0x0e00c001 是不是正好超過你傳進去的圖檔所佔記憶
02/24 00:19, 37F

02/24 00:21, , 38F
體的範圍. 不過如果該位址和您傳入的指標距離相差甚遠關
02/24 00:21, 38F

02/24 00:21, , 39F
係兜不起來, 就比較難辦了XD 不過仍然可以看一下module
02/24 00:21, 39F
還有 39 則推文
02/24 02:06, , 79F
個人覺得這裡alignment下1不應該有什麼錯, 另外, 小弟這
02/24 02:06, 79F

02/24 02:07, , 80F
邊NV 88GT, driver 178.24, XP sp3 32bit, 可以做出一樣
02/24 02:07, 80F

02/24 02:08, , 81F
的錯誤, 而且錯誤的disasm address還一模一樣. 初步看了
02/24 02:08, 81F

02/24 02:10, , 82F
一下該段disasm的內容, 的確應該是在搬你的圖檔到某個位
02/24 02:10, 82F

02/24 02:10, , 83F
址去, 還沒跟到是不是就這樣搬到超過範圍; 不過暫時建議
02/24 02:10, 83F

02/24 02:11, , 84F
您改借個ATI的平台先測測看....@_@"
02/24 02:11, 84F

02/24 02:13, , 85F
喔喔 那可能要找看看有沒有ATI的平台了...
02/24 02:13, 85F

02/24 02:13, , 86F
還是感謝兩位 謝謝
02/24 02:13, 86F

02/24 02:22, , 87F
終於OK了 ^^
02/24 02:22, 87F

02/24 02:35, , 88F
查了一下, PACK與UNPACK的alignment, 對應到原po的issue
02/24 02:35, 88F

02/24 02:37, , 89F
應該是glTexImage2D餵進去的圖是3byte緊連的, row與row
02/24 02:37, 89F

02/24 02:38, , 90F
中間沒有特殊alignment, 所以此時UNPACK的alignment應該
02/24 02:38, 90F

02/24 02:39, , 91F
設為1, 設成4的話driver會以為來源影像的row有對齊4byte
02/24 02:39, 91F

02/24 02:40, , 92F
於是這case大概copy到最後幾個row時就超過source範圍了.
02/24 02:40, 92F

02/24 02:40, , 93F
相對的如果餵入的source有做ROW的2/4/8 alignment, 就需
02/24 02:40, 93F

02/24 02:41, , 94F
要把alignment設成2/4/8, 這樣driver才會copy到正確的
02/24 02:41, 94F

02/24 02:42, , 95F
pixels. 小弟以前多是餵3byte不align的texture, 所以
02/24 02:42, 95F

02/24 02:42, , 96F
alignment自己老設為1, 所以....XD
02/24 02:42, 96F

02/24 02:43, , 97F
除了GL官網的man page, 剛goo到的這網頁寫的也不錯:
02/24 02:43, 97F

02/24 02:43, , 98F

02/24 02:44, , 99F
所以這error應該不是driver有錯, 而且glTexImage2D的
02/24 02:44, 99F

02/24 02:44, , 100F
source的alignment與glPixelStore的UNPACK alignment設
02/24 02:44, 100F

02/24 02:45, , 101F
定不一致所造成的, 所以改成1能夠解決原po的issue:)
02/24 02:45, 101F

02/24 09:00, , 102F
我覺得原po你先把24bits BMP弄到ok再說 ... 讀圖檔應該用
02/24 09:00, 102F

02/24 09:01, , 103F
不到二維陣列,直接讀進去連 alignment都不用改就能用了XD
02/24 09:01, 103F

02/24 09:08, , 104F
確實是不用二維陣列, 但是如果直接把BMP的DIB拿進來用,
02/24 09:08, 104F

02/24 09:08, , 105F
反而可能需要設alignment為4, 因為BMP的DIB在row上是會
02/24 09:08, 105F

02/24 09:09, , 106F
做padding的@_@" 不過目前看起來原po處理模式是透過lib
02/24 09:09, 106F

02/24 09:10, , 107F
把raw直接連續串起來餵給TexImage2D, 所以alignment設1
02/24 09:10, 107F

02/24 09:10, , 108F
以後就能解決了:)
02/24 09:10, 108F

02/24 09:11, , 109F
PS. 上面這段推的alignment是只GL的UNPACK alignment.
02/24 09:11, 109F

02/24 23:32, , 110F
用到二維陣列是因為我會有好幾張圖要存,如果有10張我
02/24 23:32, 110F

02/24 23:34, , 111F
會動態宣告一個(10)*(寬*高*3)的二維陣列,也就是我是
02/24 23:34, 111F

02/24 23:35, , 112F
將每一張24bits圖存成1維的,擺到該2維陣列的某一列,
02/24 23:35, 112F

02/24 23:37, , 113F
然後,glTexImage2D()是放在for裡面,裡面參數是:
02/24 23:37, 113F

02/24 23:39, , 114F
glTexImage2D(GL_TEXTURE_2D,0,3,w,h,0,GL_RGB,
02/24 23:39, 114F

02/24 23:40, , 115F
GL_UNSIGNED_BYTE,Pixels[z]); 陣列索引z就代表第幾張
02/24 23:40, 115F

02/24 23:42, , 116F
所以寫Pixels[z]也是只送一維的資料進去繪
02/24 23:42, 116F

02/24 23:52, , 117F
了解 XD 另外 BMP 通常是 GL_BGR 排列
02/24 23:52, 117F

02/25 02:25, , 118F
了解^^
02/25 02:25, 118F
文章代碼(AID): #1DPE2mxy (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1DPE2mxy (C_and_CPP)