• 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.


  • Content count

  • Joined

  • Last visited

Community Reputation

7 Neutral

About taylorswift

  • Rank
  1. 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.
  2. Experimenting some with space-based cloud rendering gives some pretty good results: 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.
  3. High frequency just means add more octaves of noise to your FBM. However I’d recommend storing your noise in a texture; generating it in the shader might be okay for one octave of perlin noise but when you get more complex its faster to prebake it. By the way, I would steer clear of simplex-lattice additive gradient noise; it’s okay for two dimensions but when you scale it up to three or more dimensions the implementation gets very hairy. Take it from someone who maintains the Swift procedural noise library. Plus, a lot of popular noise recipes assume you’re working with a 3D classical gradient noise generator (3D cubic-lattice interpolated gradient noise). Contrary to the claims of CS theoreticians, classical gradient noise is much faster than simplex noise. Welcome to my hell. Procedural planet generation is no small task, it’s one of the more challenging feats in the procedural generation world, and there are a lot of poor-quality tutorials that give ugly results. How much detail do you need? If you only need marble-sized renders, it’s relatively easy to get something that looks good. If you need to fly over them, get ready to spend a few months getting it right.
  4. That looks so much nicer congratulations! If I had any suggestions I would add some more high frequency detail to the gas clouds and fix the star color selection because the big yellow stars in the front and the faint blue stars in the back look very weird to me. You have basically no red stars and way, way too many blue stars. Blue stars are actually less common compared to white, yellow, orange, and red stars.
  5. 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.
  6. I wanted to add you can get very nice results by combining gradient noise with cell noise which gives you a lot more well-defined structure than gradient noise alone. The horizon zero dawn cloud thread has a lot of useful info on this technique. It tends to be heavy to compute but you might have luck prerendering it since the camera is only moving in one direction and gas clouds in space don’t change much in time.
  7. That’s interesting i was not aware of this!
  8. I think you are approaching the star coloring the wrong way. In space (i.e., not from the atmosphere), all stars are white. You only see faint color tinges at the edges of the stars as they glow, see this hubble image: Since you said you’re using sprites, consider pre-rendering, say 256 stars that look like the ones in the picture varying along a heat gradient instead of just using round colored dots. The heat gradient is not gaussian, the true distribution is something astrophysicists have been measuring for god knows how long, but i’d be willing to bet that linear would look more realistic than gaussian. Then rendering the stars is as easy as picking a random star from your 256 stars. P.S., you’re confusing star distance with red shift. Closer stars aren’t any more prone to being yellow/red than more distant stars. Red shift comes from star velocity relative to the viewer; if anything more distant stars are slightly redder than nearer stars from universe expansion.
  9. 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. 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. Some more angles: 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. 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. 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.