Advertisement

Horizon:zero Dawn Cloud System

Started by July 27, 2016 06:39 PM
78 comments, last by IlPresidente 6 years, 5 months ago

Really great results guys! I wish I could achieve at least something relatively close to what you have for my game.

That GPU 7 Pro article mostly describes ways to create a realistic clouds in terms of density functions and overall weather simulation, but it somehow assumes that reader is already familiar with ray marching techniques. While I can understand the algorithm behind a single ray cast from a given point to sample various density functions and so on, I can't get my head over the more basic stuff like - what render pass does it all happen? Is it during rendering the skybox? Or do you render some special shape and then in it's shader you do all this? What does it mean to do raycasts in this cast? Is it per pixel? Per point in a world space? They say in the article they assume some spherical shell around the camera of some thickness, but how do you pick points on that sphere for actual raycast? And how is the result from such raycast used to actually shade the sky?

Are there some papers on basics like this? If you could provide some pseudocode used to actually "draw" and execute this shader that's supposed to create clouds, including what are you rendering, and what's the input for raymarching algorithm, it would greatly help me understand this concept.

it's a post-process render pass, so you just render a quad.

first you get a ray accord to the screen pixel's coordinate, calculate the intersect point of the camera ray and the bottom cloud sphere.

the intersect point is the start point, run step along the ray.


float Raymarcher::integrate(const V3f& pos, const V3f& dir, const float absorption) const
{
    // Determine intersection with the buffer
    float t0, t1;
    if (false == m_buffer->intersect(pos, dir, t0, t1))
        return 1.0f;

    // Calculate number of integration steps
    const int numsteps = int(ceil(t1 - t0) / m_stepsize);

    // Calculate step size
    const float ds = (t1 - t0) / numsteps;
    V3d stepdir(dir);
    stepdir *= ds;
    V3d raypos(pos);
    raypos += stepdir;
    const float rhomult = -absorption * ds;
    
    // Transmittance
    float T = 1.f;
    for (int step = 0; step < numsteps; ++step) {
        float rho = m_buffer.trilinearInterpolation(raypos);
        T *= std::exp(rhomult * rho);
        if (T < 1e-8)
        break;
        raypos += stepdir;
    }
    return T;
}

this code is from siggraph 2011 course Production Volume Rendering, you should read it.

hehe.

Hm, where does the buffer come from? This looks like C++ code, you do it on CPU? Do you run it for every pixel of the rendered image or only for those that are actually on "sky"?

Thanks for the paper, I will read it, need to find some good explanations how raymarching works, as I see a lot of weird equations about the actual volume sampling, but nothing about how is this actually rendered :)


Where are we and when are we and who are we?
How many people in how many places at how many times?
Advertisement

Hm, where does the buffer come from? This looks like C++ code, you do it on CPU? Do you run it for every pixel of the rendered image or only for those that are actually on "sky"?

Thanks for the paper, I will read it, need to find some good explanations how raymarching works, as I see a lot of weird equations about the actual volume sampling, but nothing about how is this actually rendered :)

just render on sky.

hehe.

You may find this useful !

http://bitsquid.blogspot.co.uk/2016/07/volumetric-clouds.html

thanks.

hehe.

rgba8 should be enough precision. After all it's just a simple density value. For the base detail, you can play araound with the scaling. My clouds start at around 1,8km in height and have a scaling of 68m per texel. The detail noise got a 16 times higher scaling.

For remapping i use a weird calculation.


float4 noise = tex3Dlod(WorleyCloud,float4(pos,0.0));
float mask = (noise.r*0.6+noise.g*0.8+noise.b+noise.a*0.6)/3.0;
float denom = 1.0/(coverage*0.25+0.0001);
float lcov = 1.0-saturate((mask - coverage)*denom);
float4 n = saturate((noise-lcov)/(1.0001-lcov));

float cloud = saturate(max(n.x*1.1,max(n.y*1.14,max(n.z*1.13,n.w*1.12))));

That's what i use to sample the volume texture

Btw @ChenA

where did you find a tiling 3D perlin noise ?

Advertisement

rgba8 should be enough precision. After all it's just a simple density value. For the base detail, you can play araound with the scaling. My clouds start at around 1,8km in height and have a scaling of 68m per texel. The detail noise got a 16 times higher scaling.

For remapping i use a weird calculation.


float4 noise = tex3Dlod(WorleyCloud,float4(pos,0.0));
float mask = (noise.r*0.6+noise.g*0.8+noise.b+noise.a*0.6)/3.0;
float denom = 1.0/(coverage*0.25+0.0001);
float lcov = 1.0-saturate((mask - coverage)*denom);
float4 n = saturate((noise-lcov)/(1.0001-lcov));

float cloud = saturate(max(n.x*1.1,max(n.y*1.14,max(n.z*1.13,n.w*1.12))));

That's what i use to sample the volume texture

Btw @ChenA

where did you find a tiling 3D perlin noise ?

i generate it myself, if you need, i can send you the source code.

hehe.

Thank you, that would be nice.

i modify from a github project znoise.

i use vs2013, the project is on build/vs2013.

i save the result to a dds, you can use nvidia dds tools to view it.

hehe.

i'm very confused that how to get these formula?

just try many times?

hehe.

This topic is closed to new replies.

Advertisement