赞
踩
D3DXCreateTexture(m_pd3dDevice, m_iTextureSize, m_iTextureSize, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture) ;
在渲染火焰之前 必须有一个颜色调色板来说明火焰值是如何映射到RGBA颜色的
1. 可以把调色板直接嵌入到程序代码中
2. 也可以使用调色板文件 这是一个1024字节的文件
加载调色板的代码 read (hFile, &m_Palette[0], 256*4) ;
保存调色板的代码 save (hFile, &m_Palette[0], 256*4) ;
3. 还可以从图形文件中提取调色板
LPDIRECT3DTEXTURE8 pTexture ;
D3DXCreateTextureFromFileEx (m_pd3dDevice, strBMPfile, 0, 0, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
0, 0, 0, NULL, m_Palette, &pTexture) ;
SAFE_RELEASE (pTexture) ;
这个函数完成了许多工作 但是我们只关心的是把图像使用的调色板放到变量m_Palette中
现在可以进入帧循环渲染火焰了
// 循环遍历所有的火焰值
for (int y=0; y < m_iTextureSize; y++) {
for (int x=0; x < m_iTextureSize-0; x++) {
// 它们将立即存放这个火焰值到它的左边、右边、上边和下边的火焰值中
unsigned char firevalue_left, firevalue_right, firevalue_bottom, firevalue_top;
int finalfirevalue;
// 必须考录围绕水平轴的绕接(而不是垂直轴)
// 因此需要计算x/y +- 1, 并且先临时存储起来
int xplus1, xminus1, yplus1, yminus1;
xplus1 = x+1; if (xplus1 >= m_iTextureSize) xplus1=0;
xminus1= x-1; if (xminus1 < 0) xminus1 = m_iTextureSize-1;
yplus1 = y+1; if (yplus1 >= m_iTextureSize) yplus1=m_iTextureSize-1;
yminus1= y-1; if (yminus1 < 0) yminus1 = 0;
// 现在可以获取的相邻像素的火焰值
firevalue_right = m_pActiveBuffer[(y*m_iTextureSize)+xplus1];
firevalue_left = m_pActiveBuffer[(y*m_iTextureSize)+xminus1];
firevalue_bottom= m_pActiveBuffer[((yplus1)*m_iTextureSize)+x];
firevalue_top = m_pActiveBuffer[((yminus1)*m_iTextureSize)+x];
// 现在是最重要的部分——计算新的火焰值
finalfirevalue = (firevalue_left+firevalue_right+firevalue_top+firevalue_bottom)/4;
// 减去一个特定的值来模拟火焰的“冷却”效果
// 这里需要应用冷却贴图
finalfirevalue -= m_iCoolAmount;
// 保证减去冷却量后的结果不会小于0
if (finalfirevalue < 0) finalfirevalue = 0;
// 在中间结果暂存数组中存放火焰值, 位置在它初始行的上面一行
// 这样来模拟火焰上升的效果
m_pScratchBuffer[((yminus1)*m_iTextureSize)+x] = finalfirevalue;
}
为火焰添加数字燃料来让它持续燃烧
// 处理整个2×1块
for (int x=0; x < m_iTextureSize; x+=2) {
// 只对最下面一行添加燃料
int y=m_iTextureSize-1;
// 确定这个特定点是需要增加燃料还是减少, 方法是加上一个(-31, 31)之间的数
int fuel = m_pActiveBuffer[(y*m_iTextureSize)+x] + (rand() % 64) - 32;
// 结果必须在0~255之间
if (fuel > 255) fuel = 255;
if (fuel < 0) fuel = 0;
// 把新燃料值用于相邻的两个像素
// 这有助于减少火焰可能出现的“抖动”
m_pScratchBuffer[(y*m_iTextureSize)+x] = (unsigned char)fuel;
m_pScratchBuffer[(y*m_iTextureSize)+x+1] = (unsigned char)fuel;
}
1. 调用IDirect3DTexture8接口的LockRect方法锁定纹理并返回两个关键信息
2. 使用从LockRect中获取的指针来操作纹理元素
3. 操作完成后解锁纹理
HRESULT hr;
// 锁定纹理
D3DLOCKED_RECT lockedrect;
::ZeroMemory(&lockedrect, sizeof(lockedrect));
if (FAILED(hr = m_pTexture->LockRect(0, &lockedrect, NULL, 0))) return(false);
// 现在纹理表面已经被锁定, 我们可以使用间距来遍历纹理表面
unsigned char *pSurfBits = static_cast<unsigned char *>(lockedrect.pBits);
int index=0;
for (int y=0; y < m_iTextureSize; y++) {
for (int x=0; x < m_iTextureSize; x++) {
// 这个位置的火焰值确定了纹理元素的颜色
pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peBlue; // blue
pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peGreen; // green
pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peRed; // red
pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peFlags; // alpha
}
// 下一行
index += lockedrect.Pitch - (m_iTextureSize*4);
}
// 解锁纹理表面
if (FAILED(hr = m_pTexture->UnlockRect(0))) return(false);
要使用正交矩阵
D3DXMATRIX matProject;
D3DXMatrixOrthoLH (&matProject, 640.0f, 480.0f, 1.0f, 1000.0f) ;
Device->SetTransform (D3DTS_PROJECTION, &matProject) ;
摘自 《Directx特效游戏程序设计》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。