Sign in to follow this  
malyskolacek

Harris cloud shading & voxel datafield

Recommended Posts

Hi! I have an almost working cloud system - something ala the clouds in the famous sky thread. It's a perlin noise layer shaded by raytracing through low-res voxel datafield. The raytracing doesn't approximate the light scattering integral though - it just traces from the bottom of each voxel to the sun and adds up the amount of cloud it goes through. The result is then exponentially scaled. This works more or less OK(Screenie 1 and Screenie 2) but I decided to change it so that it approximates the scattering integral like in the paper Real-time cloud rendering for games by Harris (2002). But I want to do it on CPU, not with GPU blending like in the paper. What I have come up with basically is: for each voxel trace from the bottom to the sun and determine the distance the ray travelled through the clouds Now, do something like this(I'm also not sure with it) totalAmount=albedo*extinction_factor*phase_function*totalAmount/4*Pi+exp(-albedo)*totalAmount; They do it for each particle, but I don't know how to do this with the voxel datafield - I tried something like: for(int i=0;i<distance_through_clouds/N;i++) totalAmount=albedo*extinction_factor*phase_function*totalAmount/4*Pi+exp(-albedo)*totalAmount; But it seems way off :( because I don't know how to pick N. Also, what should I supply as white to totalAmount before starting the approximation? 1.0f or 255.0f? I am very confused here... Another thing that seems weird to me is that they use albedo=80.0f in the demo program on the website. Considering that exp(-80.0f) is almost zero I don't know why there is this part: +exp(-albedo)*totalAmount. Even with albedo=8.0f as written in the paper is exp(-albedo) very small. And my last question :) How should I make the clouds have the color of sun? At least near the sun. They are now only grayscale map which is blended onto the sky dome - and this looks very weird during for example a sunset when the clouds should be slightly yellow/orange. I tried multiplying the grayscale with the color of the sun but this was much uglier. I would really appreciate some help with this... Many thanks in advance

Share this post


Link to post
Share on other sites
I've decided to post the code of the tracer:


float CWeatherSystem::ComputeIntegral(int x, int y)
{
int iWidth=m_iSunX - x;
int iHeight=m_iSunY - y;
int Yerror=0, selX, selY, upX, upY;
float total=0.0f, vheight;

if(iWidth<0) upX=-1;
else upX=1;

if(iHeight<0) upY=-1;
else upY=1;

iWidth=abs(iWidth);
iHeight=abs(iHeight);

float fSlope=m_iSunZ/o_sqrt(iWidth*iWidth+iHeight*iHeight);
float fSlopeFac=o_sqrt(1.0f+1.0f/(fSlope*fSlope));

if(iWidth>=iHeight) {
selY=y;

float deltaHeight=(m_iSunZ-m_pNoiseLast[y*256 + x])*o_fabs(1.0f/(float)iWidth);
vheight = 0;

for(selX=x; selX != m_iSunX+upX; selX+=upX)
{
float b=m_pNoiseLast[selY*256 + selX]-(vheight+deltaHeight);
if(b<0) b=0;
float a=vheight;
if(a<0) a=0;
float len=m_pNoiseLast[selY*256 + selX]-a-b;
if(len<0) len=0;
total+=len*fSlopeFac;

Yerror=Yerror+iHeight;
if(Yerror>=iWidth) {
selY+=upY;
Yerror=Yerror-iWidth;
}
vheight+=deltaHeight;
if(vheight>256.0f)
break;
}
} else {
selX=x;

float deltaHeight=(m_iSunZ-m_pNoiseLast[y*256 + x])*o_fabs(1.0f/(float)iHeight);
vheight = 0;

for(selY=y; selY != m_iSunY+upY; selY+=upY)
{
float b=m_pNoiseLast[selY*256 + selX]-(vheight+deltaHeight);
if(b<0) b=0;
float a=vheight;
if(a<0) a=0;
float len=m_pNoiseLast[selY*256 + selX]-a-b;
if(len<0) len=0;
total+=len*fSlopeFac;

Yerror=Yerror+iWidth;
if(Yerror>=iHeight) {
selX+=upX;
Yerror=Yerror-iHeight;
}

vheight+=deltaHeight;
if(vheight>256.0f)
break;
}
}
return total;
}



This is the code that just finds the distance travelled through the clouds. The value is then exponentially scaled. The screenshots in my first post were taken with this code.

I still haven't figured how to convert this to compute the scattering integral from the Harris paper...

Share this post


Link to post
Share on other sites
To get the proper coloring at sunset, you should take a look at an article I wrote a while back on atmospheric scattering (demo source code included):
http://www.gamedev.net/columns/hardcore/atmscattering/

Since then I've written an article explaining a modified version of the algorithm that runs on the GPU that was included in GPU Gems 2. There is a simplified version of the algorithm that assumes a constant atmospheric density at:
http://www.ati.com/developer/dx9/ATI-LightScattering.pdf (if you look around on the ATI web site, you can find a demo of this)

Share this post


Link to post
Share on other sites
Oh, and here's a short answer for determining the color of the sunlight:

1) Cast a ray through the cloud volume toward sun to determine the amount of cloud "mass" shadowing the current voxel. The ray should stop at the top of the cloud volume. Use this to determine the voxel's brightness.

2) Cast the same ray again, but this time go all the way to the top of the atmosphere. The longer this ray is, the more blue and green light will be scattered out of the light's path before reaching the voxel. Scale this color by the brightness determined above to get the final color.

As a hint, most light scatters through our atmosphere at a rate of pow(1.0/wavelength, 4.0). For wavelength try 650 for red, 570 for green, and 475 for blue. Multiply this by the length of the ray and then by the atmospheric density. If you want to make this more accurate, and more complicated, assume that atmospheric density falls off exponentially with increasing altitude and break the ray into smaller sample rays, calculating the equation at each sample point.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this