|
|
发表于 2005-3-16 14:19:00
|
显示全部楼层
Re:一个问题!
看过一篇文章,使用调色板实现的火焰,不知道对你有没有帮助?
原 文:Fire
译 者:狼舞(天涯游戏工作室)
首先,你需要建立一个调色板。我的思路大概是这样的:
1)黑色放在最底部(这样可以和顶部的亮光形成高度的色差对比),红色,动态色和黄色往上推移。
2)为了建立一个256色的调色板,我需要使用几个循环:
LPDIRECTDRAWPALETTE lpDDPal; // 调色板对象
PALETTEENTRY mypal[256]; // 保存调色板的颜色值
好,现在我们可以往里面填数据了。不过,我可不敢保证我的色学观是最好的,这样建立的调色板,只是我的一厢情愿,如果你觉得你可以把些颜色调配得更好,我是没有意见的。
index = 0;
srand();
for (index=95;index<200;index++)
{
mypal[index].peRed = index+70;
mypal[index].peGreen = index+30;
mypal[index].peBlue = rand()%10;
}
for (index = 1; index < 35; index++)
{
mypal[index].peRed = index+25;
mypal[index].peGreen = rand()%10;
mypal[index].peBlue = rand()%10;
}
for (index = 35; index < 55; index++)
{
mypal[index].peRed = index+25;
mypal[index].peGreen = index-25;
mypal[index].peBlue = rand()%10;
}
for (index = 55; index < 95; index++)
{
mypal[index].peRed = index+75;
mypal[index].peGreen = index;
mypal[index].peBlue = rand()%5;
}
for(index = 200; index < 255; index++)
{
mypal[index].peRed = index;
mypal[index].peGreen = index-rand()%25;
mypal[index].peBlue = rand()%5;
}
不过,这是我所找到的最好的化合方法了,哈哈,应该是很漂亮的。尽管简单,但还是浪费了我10多分钟。
现在,就轮到我们用DirectDraw来建立这个调色板了:
lpDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, mypal, &lpDDPal, NULL);
lpDDSPrimary->SetPalette(lpDDPal);
lpDD和lpDDSPrimary不知道是什么东西?不会吧,这可是微软流传给民间的通用取名法啊!
终于,我们开始做我们伟大工作的第二步了 — 锁定DirectDraw页面,往上面涂东西 — 这可不是乱涂:
unsigned char *Lock_Back_Buffer (void)
{
DDSURFACEDESC ddsd;
HRESULT ret;
ddsd.dwSize = sizeof(ddsd);
ret = DDERR_WASSTILLDRAWING;
while (ret == DDERR_WASSTILLDRAWING)
ret = lpDDSBack->Lock(NULL, &ddsd, 0, NULL);
return (ret == DD_OK ? (unsigned char *)ddsd.lpSurface : NULL);
}
别告诉我lpDDSBack你又不知道是什么东西啊。这样我的文章可不好继续下去。来,如果只有部分人不懂,那我也就不管了:
unsigned char *double_buffer = NULL;
double_buffer = (unsigned char *)malloc(307200);
别忘了在你的退出代码中加入:
(double_buffer); free(fire_buffer);
这样的代码。
好了。我们在640X480X8Bit模式下工作了,真是伟大的创举。你太棒了。
继续,我感到越来越兴奋了。现在的问题是怎么生成火焰?一个像素一个像素的渲染?那是肯定的。但是如果每渲染一次都要更换全屏幕数据的话,让我算算,喔,我的PIII都没有这种性能啊!看来只有看家技了:
for(x = 1; x < 637; x+=rand()%3)
{
if(rand()%2)
fire_buffer[(480*640) + x] = 255;
else
fire_buffer[(480*640) + x] = 0;
}
看懂了以上代码了么?我只渲染最底层的一根线的高度。哈哈,这样省事了。可是上面的怎么办?别急,跟我来。我用下面的伪代码表达一下:
for y = 1, y to screenheight, increment y
for x = 1, x to screenwidth, increment x
find our offset - what pixel we are going to start
averaging around - (Y*ScreenHeight)+x
add up the surrounding pixels - all eight of them
divide that total by 8 - hard concept there =)
now if that value is not 0 - not black
we decrement it - subtract 1 =)
end
Draw to our back buffer
end
看不懂,那我用C++代码表达吧:
int x,y,fireoffset;
// calculate the bottom line pixels
for(x = 1; x < 637; x+=rand()%3)
{
if(rand()%2)
fire_buffer[(480*640) + X] = 255;
else
fire_buffer[(480*640) + X] = 0;
}
// CALCULATE THE SURROUNDING PIXELS
for(y = 1; y < 480; ++y)
{
for(x = 1; x < 640; ++x)
{
offset = (y*640) + x; firevalue = ((fire_buffer[fireoffset-640] +
fire_buffer[fireoffset+640] +
fire_buffer[fireoffset+1] +
fire_buffer[fireoffset-1] +
fire_buffer[fireoffset-641] +
fire_buffer[fireoffset-639] +
fire_buffer[fireoffset+641] +
fire_buffer[fireoffset+639]) / 8); // this can be optimized by a
// look up table as I'll show you later
if(firevalue != 0) // is it black?
{
--firevalue; // Nope. Beam me down Scotty.
fire_buffer[fireoffset-640] = firevalue; // Plot that new color
// on the above pixel
// remember the typewriter analogy
}
}
}
double_buffer = Lock_Back_Buffer(); // Remember this function? Good
memcpy(double_buffer, fire_buffer, (640*480)); // Copy fire buffer to the screen
lpddsback->Unlock(NULL); // Unlock! Important! you have no idear!
我发现伟大的工作被我们做完一大半了,还有?当然还有,还有什么,别急,看:
int firelook;
for (firelook = 0; firelook < 1256; FIRELOOK++)
FTAB[FIRELOOK] = FIRER >> 3;
firevalue = ftab[(fire_buffer[fireoffset-640] +
fire_buffer[fireoffset+640] +
fire_buffer[fireoffset+1] +
fire_buffer[fireoffset-1] +
fire_buffer[fireoffset-641] +
fire_buffer[fireoffset-639] +
fire_buffer[fireoffset+641] +
fire_buffer[fireoffset+639])];
看懂了吗?fireoffset-640是什么?右上的像素?fireoffset-639是什么?一个上面的像素,但是有一点点在右边,那就是在右上角的像素了。fireoffset+640是什么?下面的像素。我告诉你的仅仅是一个示例,哈,但是你必须得相信我。不过,我怀疑你会被我搞糊涂。不过,你把这篇文章多看几次,想清楚了之后,你的想法就会改变的,你一定会来谢谢我的。
|
|