在遊戲制作中如何實現僞體積光照效果

王朝网络

僞體積光照

1、 引言(Introduction)

在今天的許多演示及遊戲中,你可能會看到各種類型的體積效果,就如上圖所示。一個可行的想法是使用數學技巧也能做出如此令人驚奇的效果。該文的目的就是給你這個演示的實現方法 ― 它真的很容易。

In many demos and games these days you see various volumetric effects like on the picture above. One might think that it takes amazing skills in both programming as well as mathematics to do such effects. The aim of this tutorial is to show one way of doing it - and it's even an easy way!

2、理論(Theory)

首先,請你看一眼這兩張紋理:

First, take a look at these two textures:

王朝网络

左圖

王朝网络

右圖

這是我們要做的事情:

This is what we do:

1)使用彩色紋理繪制對象“射出”的光(左圖)。

Draw the object 'emitting' the light using the colour-texture (the one on the left).

2)稍微變化對象的比例。

Slightly scale the object.

3)在混合方式下使用掩碼紋理繪制對象(右圖)。

Draw the object using the mask-texture (the one on the right) in a blend mode.

4)重複2與3點 ― 你重複次數愈多,它看起來會更加漂亮(上面的效果我循環了50次)。

Repeat points 2 and 3 - the more times you repeat them, the better it looks (the image above loops 50 times).

3、實現(Implementation)

這方法不受任何特定應用程序接口(它將會與硬件及軟件一起工作)的限制,但是我想聲明的是,它受到象素填充率的限制(在GF3的640x480下運行爲50幀,而Quadro2上僅僅爲25幀)。

This method is not limited to any specific API's (it'll work with both hardware and software), apart from the fact, that it is *very* fillrate limited (i get 50fps on gf3 in 640x480, but only 25fps on quadro2).

這裏是核心的OpenGL代碼(你只需將其放進你自己的程序框架或演示系統中):

Here is the needed code for OpenGL (you need to put this into your own framework or demosystem):

GLuint texture[2];

// Load the textures into this array.

GLUquadricObj *sphere;

// This is our object - you can use your own geometric data if you like.

// Call this function from your initroutine.

void InitQuadric()

// Initialise the quadric object.

{

sphere = gluNewQuadric();

// Create new quadric.

gluQuadricNormals(sphere, GLU_SMOOTH);

// Set normals to be smooth.

gluQuadricTexture(sphere, GL_TRUE);

// Enable texturemapping.

}

// This is the main routine - call this every frame.

void DrawVolLight()

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Clear screen and depthbuffer

static float angle = 0.0f;

// Variable to control rotation of the object.

glLoadIdentity();

// Reset the modelview matrix.

glTranslatef(0.0f, 0.0f, -15.0f);

// Move the object in place.

glRotatef(angle, 1.2f, 0.4f, 0.7f);

// Rotate the object.

glEnable(GL_TEXTURE_2D);

// Enable texturemapping.

glBindTexture(GL_TEXTURE_2D, texture[0]);

// Use the colour-texture.

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

// Full colour and no blending.

gluSphere(sphere, 2, 32, 16);

// Draw the object.

glBlendFunc(GL_SRC_ALPHA, GL_ONE);

// Setup blending.

glBindTexture(GL_TEXTURE_2D, texture[1]);

// Use the mask-texture.

glEnable(GL_BLEND);

// Turn on blending.

glDepthMask(GL_NEVER);

// Don't write to depth buffer

static float numlayers = 50;

// This it the amount of loops - higher values equals better looking (and slower) light.

for (float n = 0; n

// The loop!

{

float scale = 1+n/numlayers;

// calculate the scale-factor.

float color = 1.0f/n+sin(angle/10)/16; // Calculate the percentage of colour used in the blending.

glLoadIdentity();

// Reset the modelview matrix.

glTranslatef(0.0f, 0.0f, -15.0f);

// Position the object.

glRotatef(angle, 1.2f, 0.4f, 0.7f);

// Rotate the object.

glScalef(scale, scale, scale);

// Scale the object (the coordinatesystem actually)

glColor4f(color, color, color, 1.0f);

// Set the amount of colour (used for blending).

gluSphere(sphere, 2, 32, 16);

// Draw the object using the mask-texture

}

glDepthMask(GL_TRUE);

// Make it possilbe to write to the depth-buffer again.

glDisable(GL_BLEND);

// Disable blending.

angle = 0.02*(GetTickCount()-startticks);

// Set up rotation angle for the next fram

glFlush();

// Flush the GL-pipeline (force GL to finish everything it's doing).

}

在實踐中,我可能需要調整光照體積。其由調節glColor4f的值完成。

In my implementation, i have made it possible to adjust the volume of the light. It is done by modulating the glColor4f values.

這也就是光源看起來爲什麽好象在搏動的原因。

This is what makes the light look like it's pulsing.

4、後記(Afterword)

我知道的這個方法是使用了巨量的填充率,它可能會不適合以後的遊戲。但是請你注意,它看起來非常好,而且實現過程簡單。假如你有任何改進或建議歡迎給我來信。對了,文末的附帶的資源是一個執行版(包括紋理)。

I know that this method is a fillrate-eater and that it is probably not suitable for games for the next year or two. Nevertheless! It looks good and it is not too hard to do. Improvements / suggestions are welcome! Let me know if you make you own implementation.Download.Binary version (including textures) of my implementation can be downloaded here

用Photoshop實現水滴字體效果的制作
  效果圖:           ...查看完整版>>用Photoshop實現水滴字體效果的制作
 
2D遊戲中人物被遮擋的透明效果實現
  通常我們在2D遊戲中經常使用人物的半透明效果來表示人物被建築物所遮擋,這種效果做法不但畫面效果較佳,而且能讓玩家更好的了解自己所控制玩家當前位置,才不會被物件所遮擋,茫然失去方向。這裏,我們就是來講...查看完整版>>2D遊戲中人物被遮擋的透明效果實現
 
Flash如何實現透視的效果
  Flash真的很神奇,使用它可以模擬出現實生活中的很多現象。大家可能都有這樣的經曆,把一個信封對著強光,我們就可以看到裏面物體的形狀,甚至是字。本例就是模擬的這種現象。  在本例中,我們將蠟燭作爲光源,...查看完整版>>Flash如何實現透視的效果
 
如何在FLASH中實現眨眼睛的動畫效果
  許多FLASH動畫短片和MV中經常有精美生動的動畫人物出現,配合眨眼動作、口形變化以及頭發的飄動,再加上人物的配音,一個活脫脫的動畫人物形象就出現在FLASH動畫中了。很多人都想知道這樣的人物是如何做得栩栩如...查看完整版>>如何在FLASH中實現眨眼睛的動畫效果
 
Perl/TkFAQ-18.3.如何用after來實現動畫效果?
  原文:  18.3. How can I do animations using after?  There is a "toggling button" demo script supplied with Tk called after_demo that makes effective use of after().  Terry Greenlaw mailto:te...查看完整版>>Perl/TkFAQ-18.3.如何用after來實現動畫效果?
 
如何實現被百度快速收錄 推廣之制作專題篇
  最近在負責中國8U網站推廣的時候,首先對網站做了一個診斷,發現網站的內鏈很少,各個網頁都是獨立成章。另外發現産品在宣傳方面也不是太規範。于是有了一個做專題的計劃。另外做專題也是我在參加一次網絡營銷高...查看完整版>>如何實現被百度快速收錄 推廣之制作專題篇
 
如何在FLASH中實現眨眼睛的動畫效果
  許多FLASH動畫短片和MV中經常有精美生動的動畫人物出現,配合眨眼動作、口形變化以及頭發的飄動,再加上人物的配音,一個活脫脫的動畫人物形象就出現在FLASH動畫中了。很多人都想知道這樣的人物是如何做得栩栩如...查看完整版>>如何在FLASH中實現眨眼睛的動畫效果
 
如何實現無刷新的DropdownList聯動效果
  ASP.NET給我們帶了了事件模型的編程機制,這使得我們將所有的任務都放在 服務器 上執行哪怕是一個小小變動,其實這到不是什麽問題,可是有一點我們無法忍受,如果我們改變某一個輸入框中的內容頁面要刷新,改變D...查看完整版>>如何實現無刷新的DropdownList聯動效果
 
如何使頁面上的圖片實現水印的效果?
方法1:實現背景圖片的水印效果,只有IE支持:<body>元素的bgproperties=”fixed”; 方法2:實現背景圖片的水印效果:background-attachment:fixed;如:body{background-image:url(logo.gif);backgr...查看完整版>>如何使頁面上的圖片實現水印的效果?
 
 
回到王朝網路移動版首頁