|
DirectXGraphics访问贴图内存
Jack Hoxley译:zh1110
1.介绍
2. 贴图到贴图的拷贝
3. 快速访问贴图内存
4. 快速访问背景缓冲及前缓冲
5.内存中的操作
1. 介绍
也许你想将一些小的贴图组合成一张大的贴图,也许你想通过数学方法创建贴图(如羽化),也许你想将一张世界地图通过一定接口到贴图上。。。这些方法是我们将介绍的.
2. 贴图到贴图的拷贝
很典型的应用是一些小图形的平铺(草坪,石头,水)。
Direct3D 只允许在surfaces (Direct3DSurface8)间拷贝 , not textures (Direct3DTexture8) - 所以首先要转化成一个surface. 本质上我们并不是转化或拷贝他们到 surfaces, 我们是造了一个输入点, 相当于C/C++ 中的指针(如果你了解它)surface的改变会反映到textures 上,这样我们渲染就有了修改的目标. 下面是全部代码:
'## 声明DECLARATIONS ##
'//Our renderable textures 我们渲染的贴图
Dim TexSource As Direct3DTexture8
Dim TexDest As Direct3DTexture8
Dim TexComb As Direct3DTexture8
'//The surfaces that will point to them.它们的指针
Dim SurfSource As Direct3DSurface8
Dim SurfDest As Direct3DSurface8
Dim SurfComb As Direct3DSurface8
'## 初始INITIALISATION ##
'//Create Our TEXTURE objects创建我们的TEXTURE对象
Set TexSource = D3DX.CreateTextureFromFileEx(D3DDevice, App.Path & "\texsource.bmp", _
128, 128, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, _
D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, ByVal 0, _
ByVal 0)
Set TexDest = D3DX.CreateTextureFromFileEx(D3DDevice, App.Path & "\texdest.bmp", _
128, 128, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, _
D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, ByVal 0, _
ByVal 0)
Set TexComb = D3DX.CreateTexture(D3DDevice, 128, 128, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED)
'## 渲染循环RENDER LOOP ##
'//渲染时创建一个texture指针
Set SurfSource = TexSource.GetSurfaceLevel(0)
Set SurfDest = TexDest.GetSurfaceLevel(0)
Set SurfComb = TexComb.GetSurfaceLevel(0)
'我们拷贝1/2的SurfSource面及1/2的 SurfDest面到SurfComb
rctSource.Top = 0: rctSource.Left = 0: rctSource.Right = 64: rctSource.bottom = 128
ptDest.X = 0: ptDest.Y = 0
D3DDevice.CopyRects SurfSource, rctSource, 1, SurfComb, ptDest
rctSource.Top = 0: rctSource.Left = 64: rctSource.Right = 128: rctSource.bottom = 128
ptDest.X = 64: ptDest.Y = 0
D3DDevice.CopyRects SurfDest, rctSource, 1, SurfComb, ptDest
|
|
|
|
我使用CreateTextureFromFileEx( ) - 这样可以指定特别的贴图类型。我们还可指定 D3D的Mip Mapping ,我们用主贴图所以我们输入0。
最后用 CopyRects( ) 函数.特别要说明的是rectangles区域不能超过贴图边缘,否则 D3D会拒绝,它也不同于coordinates的尺寸 0.0 to 1.0 scale...
3. 快速访问贴图内存
它可以产生一些特殊效果(Alpha Blending, Colour Blending, Particle Effects, Lighting etc...),一些复杂程序也用到,此外你还可以自定义你的图片格式...
Dim pData As D3DLOCKED_RECT, pxArr() As Byte
TexDMA.LockRect 0, pData, ByVal 0, 0
'我们现在可以访问 stuff 利用 pData
ReDim pxArr(pData.Pitch * 128) As Byte '所有 bytes类型就足够了,其他如integers or longs浪费
DXCopyMemory pxArr(0), pData.pBits, pData.Pitch * 128 ' surface高度为128
DXCopyMemory ByVal pData.pBits, pxArr(0), pData.Pitch * 128 'pxArr() 包含了 texture's 每一点的数据
TexDMA.UnlockRect 0
|
|
|
|
vb本身不支持指针所以我们用 DXCopyMemory( ) (它包含了API 函数CopyMemory )....
4. 快速访问背景缓冲及前景缓冲
这其实是前面所讲的延伸.
Dim FrontBuffer As Direct3DSurface8
Dim BackBuffer As Direct3DSurface8
D3DDevice.GetFrontBuffer FrontBuffer
Set BackBuffer = D3DDevice.GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO)
'you can now lock as per normal:
FrontBuffer.LockRect pData, rct, 0
BackBuffer.LockRect pData, rct, 0
'etc...
|
|
|
|
5.内存中的操作
什么是象数格式? 8 bit, 16 bit, 24 bit and 32 bit 是基本的格式, 它告诉你每点存储多少 bits 内存。如标志"D3DFMT_X8R8G8B8" and "D3DFMT_R5G6B5" (在 CreateTextureFromFileEx( ) 函数中)。8 bits = 1 byte.
TexDMA2.LockRect 0, pData, ByVal 0, 0
'我们现在可以访问 stuff用 pData
ReDim pxArr(pData.Pitch * 128) As Byte
If Not (DXCopyMemory(pxArr(0), ByVal pData.pBits, pData.Pitch * 128) = D3D_OK) Then
'发生错误时的语句
End If
' XRGB 格式...
For x = 0 To (pData.Pitch * 128) - 1 Step 4
'unused = pxArr(x + 3)
bRed = pxArr(x + 2)
bGreen = pxArr(x + 1)
bBlue = pxArr(x + 0)
bRed = 0
bGreen = 0
bBlue = 255
pxArr(x + 2) = bRed
pxArr(x + 1) = bGreen
pxArr(x + 0) = bBlue
Next x
If Not (DXCopyMemory(ByVal pData.pBits, pxArr(0), pData.Pitch * 128) = D3D_OK) Then
'拷贝发生错误时的语句
End If
TexDMA2.UnlockRect 0
|
|
|
|
original array 存储数据,排序为BGRXBGRXBGRXBGRXBGRX 所以我们在主循环用 "Step 4" ,我们同时要正确使用X/Ycoordinates .
16位格式的排序:[RRRRRGGG] [GGGBBBBB] (where [] signifies a byte)
16位下提取颜色的过程如下:
1. Take the two bytes, combine them into one straight 16 bit line
2. Mask out the green and blue channels, shift right 11 bits = Red
3. Mask out the red and blue channels, shift right 5 bits = Green
4. Mask out the red and green channels = Blue
- Manipulate colours here -
5. Shift the Red left by 11 bits, shift the green across by 5 bits
6. Combine the Red, Green and Blue values into a 16 bit long
7. Mask out the lowest 8 bits, shift right 8 bits = second byte
8. Mask out the highest 8 bits = first byte.
Step 1: 组合
bFirst = pxArr(x)
bSecond = pxArr(x + 1)
lRes = (bSecond * 2 ^ 8) Or bFirst
|
|
|
|
OR 操作真值表:
|
A
|
B
|
A Or B
|
|
0
|
0
|
0
|
|
1
|
0
|
1
|
|
0
|
1
|
1
|
|
1
|
1
|
1
|
1111111100000000 = bSecond shifted left 8 bits
0000000011111111 = bFirst
---------------------
1111111111111111 = lRes
Step 2: 提取红色部分
And操作真值表
|
A
|
B
|
A And B
|
|
0
|
0
|
0
|
|
1
|
0
|
0
|
|
0
|
1
|
0
|
|
1
|
1
|
1
|
1011011101100111 = 16 bit chain
1111100000000000 = Red mask, 63488
---------------------
1011000000000000 = output, red shifted left by 11 bits
0000000000010110 = Red correctly shifted right by 11 bits.
bRed = (lRes And 63488) / 2 ^ 11
bRed = (255 / 31) * bRed 'to convert to the familiar 0-255 range.
|
|
|
|
Step 3: 提取绿色部分
bGreen = (lRes And 2016) / 2 ^ 5
bGreen = (255 / 63) * bGreen 'to convert it to 0-255 range
|
|
|
|
Again, we convert it to the 0-255 range.
Step 4: 提取蓝色部分
bBlue = lRes And 31
bBlue = (255 / 31) * bBlue 'convert it to 0-255 range |
|
|
|
Step 5 & 6: 再次处理
'//Convert RED
bRed = Int((31 / 255) * bRed) 'convert it back to the 0-31 scale
lRed = bRed * 2 ^ 11
'//Convert GREEN
bGreen = Int((63 / 255) * bGreen) 'convert it back to the 0-63 scale
lGreen = bGreen * 2 ^ 5
'//Convert BLUE
bBlue = Int((31 / 255) * bBlue) 'convert back to the 0-31 scale
lBlue = bBlue
'//Assemble Complete Long
lRes = lRed Or lGreen Or lBlue
|
|
|
|
'bSecond is the highest 8 bits
bSecond = (lRes And 65280) / 2 ^ 8
'bfirst is the lowest 8 bits
bFirst = lRes And 255
pxArr(x) = bFirst
pxArr(x + 1) = bSecond
|
|
|
|
|