• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
ChenA

Horizon:zero Dawn Cloud System

64 posts in this topic

Another interesting part of the system is the weather simulation.
I found that a good way to handle cloud formation/dissipation and movement is using Cellular Automata as Dobashi tried:

 

http://evasion.imag.fr/~Antoine.Bouthors/research/dea/sig00_cloud.pdf

A very brief summary of the paper is this:

https://graphics.stanford.edu/courses/cs348b-competition/cs348b-05/clouds/index.html

 

A working implementaton is here:

https://software.intel.com/en-us/articles/dynamic-volumetric-cloud-rendering-for-games-on-multi-core-platforms

 

All the simulation is a 3D grid, and it can be used to generate the weather map.

Accumulating cloudiness on the y-axis could create the cloudtype parameter, and if over a certain threshold the coverage too.

Probably another pass could see spots areas with taller clouds (maybe doing a downscaled version of the simulation map) to check precipitation values.

 

Just a train of thoughts!

1

Share this post


Link to post
Share on other sites

Posted (edited)

Yaaaaaaaaaaayyyy!* Looking forward to it :D

*Excited Kermit voice

Related, does anyone know how Reset does their variable distance volume marching for their precipitation effect/large scale god rays? EG: 

 

Near camera volume marching is fine, you set your z-slices and go. Clouds are fine if they're on a defined plane/sphere. But they also seem to use such to represent rain, a very cool effect. 

I ask because the most dramatic scattering, or god rays, often comes between clouds/distant mountains. And somehow that seems to be accomplished here. A logarithmic march? If everything (including the clouds) was in some sort of shadowmap like depth buffer you could get a summed area table, then do a gradient domain like march. EG skip space till sunlight, etc. Any other ideas?

Edited by FreneticPonE
1

Share this post


Link to post
Share on other sites

Been working on this for a long time so I figured I’d share what I have, but I can’t find the right numbers to make the clouds look, well, good.

Selection_024.thumb.png.5a7fd80bcfe2cbeea9325e20a5fee074.png

The highlights are overblown and the shadows are way too deep. The powder term is also making a mess here.

Here is the picture from the GPU pro book, for comparison.

Selection_028.png.d30cc0415609bab046c6296ab86b70db.png

Some more angles:

Selection_025.thumb.png.64c949e823b0d85c8d0934b962de8d0f.png

Silver lining effect, seems to reach too far into the interiors of the clouds, even with the absorption turned way up. Meanwhile the holdouts are too dark.

Selection_026.thumb.png.5f44325a3d8b8bfeee0d9644ac5b8e22.png

Aerial view, the powder term causes some very strange shadow casting. They actually make the clouds behind them lighter instead of darker. Clouds also look too dark and generally unrealistic.

Selection_027.thumb.png.8b1adfc4047780b31e166df9cd9105a9.png

This is the only view that looks okay, but the highlights and shadows still look bad.

Here is my source code (GLSL) if it helps. I’m brute forcing the lightmarching with 16 samples to debug the lighting model.

#version 330 core

layout (std140) uniform CameraDataBlock
{
    vec3  position;     // [ 0 ..< 12]
    float z;            // [12 ..< 16]
    vec3  direction;    // [16 ..< 28]
    float twice_size;   // [28 ..< 32]
    float half_h;       // [32 ..< 36]
    float half_k;       // [36 ..< 40]
    vec2  shift;        // [40 ..< 48]
    mat3  world;        // [48 ..< 96] size = 96
} camera;

uniform sampler3D low_freq_noise;

in Planet
{
    vec3  center;
    vec2  cloud_deck;
    float radius;
    vec3  sun;
} planet;

out vec4 color;

vec2 sphere_intersect(const vec3 ray, const vec3 camera_to_center, const float r)
{
    float midpoint = dot(camera_to_center, ray);
    float D = r*r - dot(camera_to_center, camera_to_center) + midpoint*midpoint;
    if (D <= 0)
    {
        return vec2(0, 0);
    }
    else
    {
        float half_depth = sqrt(D);
        return vec2(max(0, midpoint - half_depth), max(0, midpoint + half_depth));
    }
}

vec2 box_intersection(const vec3 p1, const vec3 p2, const vec3 start, const vec3 ray)
{
    vec3 ray_inverse = 1 / ray;
    vec3 v1 = (p1 - start) * ray_inverse;
    vec3 v2 = (p2 - start) * ray_inverse;
    vec3 n  = min(v1, v2);
    vec3 f  = max(v1, v2);
    vec2 slice = vec2(max(n.x, max(n.y, n.z)), min(f.x, min(f.y, f.z)));

    if (slice.x < slice.y)
    {
        return max(slice, 0);
    }
    else
    {
        return vec2(0, 0);
    }
}

float height_fraction(const vec3 position)
{
    return clamp(0.5 * (position.z + 1f), 0, 1);
}

float density_gradient_stratus(const float h)
{
    return max(smoothstep(0.00, 0.07, h) - smoothstep(0.07, 0.11, h), 0); // stratus, could be better
}

float density_gradient_cumulus(const float h)
{
    //return max(smoothstep(0.00, 0.22, h) - smoothstep(0.4, 0.62, h), 0); // cumulus
    return smoothstep(0.3, 0.35, h) - smoothstep(0.425, 0.7, h); // cumulus
}

float density_gradient_cumulonimbus(const float h)
{
    return smoothstep(0, 0.1, h) - smoothstep(0.7, 1, h); // cumulonimbus
}

float erode(const float x, const float e)
{
    return max(1 - (1 - x) / e, 0);
}

float cloud_density(const vec3 position, const float detail)
{
    vec4 low_freq_noise_sample = textureLod(low_freq_noise, 0.5 * (position + 1), detail);
    float low_freq_fbm = low_freq_noise_sample.g * 0.725 +
                         low_freq_noise_sample.b * 0.3  +
                         low_freq_noise_sample.a * 0.15;

    float base_cloud = erode(low_freq_noise_sample.r, density_gradient_cumulus(height_fraction(position)));
    base_cloud = erode(base_cloud, low_freq_fbm);
    base_cloud = clamp(6 * (base_cloud - 0.390625 - 0.1) + 0.5, 0, 1);

    return base_cloud;
}

float exponential_integral(const float z)
{
	return 0.5772156649015328606065 + log( 1e-4 + abs(z) ) + z * (1.0 + z * (0.25 + z * ( (1.0/18.0) + z * ( (1.0/96.0) + z * (1.0/600.0) ) ) ) ); // For x!=0
}

vec3 ambient_color(float h, float extinction_coeff)
{
    // For now make ambient color white (less instructions)
    float ambient_term = -extinction_coeff * (1.0 - h);
    vec3 isotropic_scattering_top = vec3(0.8, 0.9, 1.0) * max(0.0, exp(ambient_term) - ambient_term * exponential_integral(ambient_term));

    ambient_term = -extinction_coeff * h;
    vec3 isotropic_scattering_bottom = vec3(0.6, 0.8, 1.0) * max(0.0, exp(ambient_term) - ambient_term * exponential_integral(ambient_term));

    // Modulate the ambient term by the altitude
    isotropic_scattering_top *= h * 0.5;

    return 7*(isotropic_scattering_top + isotropic_scattering_bottom);
}

float henyey_greenstein(const float phase, const float g)
{
    float g2 = g * g;
    return 1f / (3.14159 * 4f) * (1f - g2) / pow(1f + g2 - 2f * g * phase, 1.5f);
}

float lightmarch(vec3 start, float absorption, vec3 light)
{
    vec2 slice = box_intersection(vec3(-1, -1, -0.4), vec3(1, 1, 0.4), start, -light);

    float ds = (slice.y - slice.x) / 16f;
    float s  = slice.x + 0.5f * ds;

    //float T         = 1f;
    float sigma_ds  = absorption * ds;
    float optical_depth = 0;
    for (uint i = 0u; i < 16f; ++i)
    {
        vec3 position = start - s * light;
        optical_depth += sigma_ds * cloud_density(position, 0);

        /* early exit
        if (T < 1e-8)
        {
            break;
        }
        */
        s += ds;
    }

    return optical_depth;
}

vec4 raymarch(vec3 ray, float absorption, vec2 slice)
{
    float ds = (slice.y - slice.x) / 128f;
    float s  = slice.x + 0.5f * ds;

    vec4  color     = vec4(0);
    float T         = 1f;
    float sigma_ds  = -3*absorption * ds;
    float phase     = -dot(planet.sun, ray);

    for (uint i = 0u; i < 128f; ++i)
    {
        vec3 position = camera.position + s * ray;
        float density = cloud_density(position, 0);
        float Ti = exp(sigma_ds * density);
        T *= Ti;

        if (T < 1e-8)
        {
            break;
        }

        float lightmarch_depth = lightmarch(position, absorption, planet.sun);
        float powder_factor = mix(2f*(1 - exp(-2f*lightmarch_depth)), 1f, 0.5f * (phase + 1));
        float phase_factor = mix(henyey_greenstein(phase, 0.06f), henyey_greenstein(phase, 0.9f), 0.05f);
        vec3 light_color = powder_factor * exp(-lightmarch_depth) * 75f*vec3(5f, 4f, 3f) * mix(1f/(4 * 3.14159f), phase_factor, exp(-lightmarch_depth)) +
                            ambient_color(height_fraction(position), sigma_ds * density);

        color.rgb += T * light_color * vec3(1.0f) * density * ds;
        color.a   += (1.0f - Ti) * (1.0f - color.a);
        s += ds;
    }

    return color;
}



void main()
{
    vec3 ray   = camera.world *
                 normalize(vec3(camera.twice_size * ((gl_FragCoord.x - camera.shift.x) - camera.half_h),
                                camera.twice_size * ((gl_FragCoord.y - camera.shift.y) - camera.half_k),
                               -camera.z));

    vec2 slice = box_intersection(vec3(-1, -1, -0.4), vec3(1, 1, 0.4), camera.position, ray);
    vec4 cloud_color;
    if (slice.x == slice.y)
    {
        cloud_color = vec4(0, 0, 0, 0);
    }
    else
    {
        cloud_color = raymarch(ray, 7, slice);
    }


    vec2 horizon = sphere_intersect(ray, planet.center - camera.position, planet.cloud_deck.y + 1000000);
    float optical_depth = clamp(0.00000025 * (horizon.y - horizon.x), 0, 1);
    vec3 sky = vec3(mix(optical_depth*optical_depth*optical_depth*optical_depth, 1, 0.1),
                    mix(pow(optical_depth, 1.7), 1, 0.12),
                    mix(optical_depth, 1, 0.1));

    //float fade = 1.0 / (1 + 0.0000001*slice.x*slice.x);
    sky = cloud_color.rgb + sky * (1 - cloud_color.a);
    color = vec4(sky, 1);
}

PS to the person having problems with making the clouds taper, you have to feed the altitude gradient into a remap function, not just multiply it into the cloud density. That makes the clouds shrink as you go up rather than just get lighter.

1

Share this post


Link to post
Share on other sites

Posted (edited)

Andrew, looking forward to your SIGGRAPH 2017 Talk.

thanks for your share.

 

ps. the gallery pic can't show correctly now, is it because of gamedev revision? have chance to recover it?

 

Edited by ChenA
0

Share this post


Link to post
Share on other sites

Yeah, I think something with the site updates may have messed up the gallery link. You can find them by going to my profile and clicking the Albums tab, or use this link: 

 

0

Share this post


Link to post
Share on other sites

Posted (edited)

My results look a bit like yours, taylorswift:

5qsYchu.png

If I drop the absorption rate to get rid of the dark areas then the clouds get blown out. But I'm not modeling scattering yet, so I think this makes sense. The only light is that which comes directly from the sun but isn't absorbed on the way. I'll see what happens when I add ambient lighting and the henyey greenstein term but right now I'm trying to make sure what I already have is correct-ish. But it looks like you already have both. What happens if you remove them?

I'm not very happy with my cloud shapes either. I don't get very clean edges even at really high sample counts. It ends up looking pretty fuzzy. Your first image looks really good in that respect. Maybe I need some kind of exponential ramp on the density.

I also don't like how the clouds appear near the horizon but in that case I might just need some fog.

Really looking forward to Andrew's talk in a couple weeks.

Edited by wild_pointer
0

Share this post


Link to post
Share on other sites
2 minutes ago, wild_pointer said:

My results look a bit like yours, taylorswift:

5qsYchu.png

If I drop the absorption rate to get rid of the dark areas then the clouds get blown out. But I'm not modeling scattering yet, so I think this makes sense. The only light is that which comes directly from the sun but isn't absorbed on the way. I'll see what happens when I add ambient lighting and the henyey greenstein term but right now I'm trying to make sure what I already have is correct-ish. But it looks like you already have both. What happens if you remove them?

I'm not very happy with my cloud shapes either. I don't get very clean edges even at really high sample counts. It ends up looking pretty fuzzy. Your first image looks really good in that respect. Maybe I need some kind of exponential ramp on the density.

I also don't like how the clouds appear near the horizon but in that case I might just need some fog.

Really looking forward to Andrew's talk in a couple weeks.

Removing henyey greenstein takes away the bright fringes but brightens the clouds when viewed from the sun since it’s the source of the anisotropic shading in the clouds. Ambient lighting doesn’t do much except brighten the whole scene.

0

Share this post


Link to post
Share on other sites

Experimenting some with space-based cloud rendering gives some pretty good results:

596c1664cef85_Diannamy3_003.thumb.png.8ef433554793247cfaca22383d75c583.png

Needless to say, this doesn’t run very fast (~30ms fullscreen) but I was surprised how far I could get with nothing but procedural noises.

1

Share this post


Link to post
Share on other sites
On 7/15/2017 at 6:14 AM, taylorswift said:

Removing henyey greenstein takes away the bright fringes but brightens the clouds when viewed from the sun since it’s the source of the anisotropic shading in the clouds. Ambient lighting doesn’t do much except brighten the whole scene.

We use a triple henyey-greenstein phase function. I'll add an implementation to our slides. They should go online in 2.5 weeks or so. The talk is 2 weeks from yesterday! I better get back to making the slides. 😀

On 7/17/2017 at 3:46 AM, taylorswift said:

Experimenting some with space-based cloud rendering gives some pretty good results:

596c1664cef85_Diannamy3_003.thumb.png.8ef433554793247cfaca22383d75c583.png

Needless to say, this doesn’t run very fast (~30ms fullscreen) but I was surprised how far I could get with nothing but procedural noises.

Awesome. With enough noise sources and instructions you should be able to model everything. That is our goal in the long run at least. As processing power increases, the amount you can purchase with 2ms increases as well.

2

Share this post


Link to post
Share on other sites
On 7/18/2017 at 6:36 AM, VONSCHNEIDZ said:

We use a triple henyey-greenstein phase function. I'll add an implementation to our slides. They should go online in 2.5 weeks or so. The talk is 2 weeks from yesterday! I better get back to making the slides. 😀

Awesome. With enough noise sources and instructions you should be able to model everything. That is our goal in the long run at least. As processing power increases, the amount you can purchase with 2ms increases as well.

 

Will the talk be recorded? would be awesome for non attendees !

And example implementation would be fantastic, I've played through Horizon twice and loved the clouds, amazing!.

0

Share this post


Link to post
Share on other sites
On 7/18/2017 at 1:36 AM, VONSCHNEIDZ said:

We use a triple henyey-greenstein phase function. I'll add an implementation to our slides. They should go online in 2.5 weeks or so. The talk is 2 weeks from yesterday! I better get back to making the slides. 😀

Awesome. With enough noise sources and instructions you should be able to model everything. That is our goal in the long run at least. As processing power increases, the amount you can purchase with 2ms increases as well.

I’m still struggling with haze and cirrus clouds as when viewing from space, the lack of the thin wispy clouds is very obvious. Unfortunately, I have no idea how to produce good procedural cirrus clouds.

0

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