Seymour Clufley wrote:
I might want to have objects moving through the cloud field, or floating around on top of it. But I doubt there would be anything beneath it.
The problem isn't just rendering objects under the clouds. Rendering objects in the clouds and above them could prove difficult as well. Technically rendering the objects isn't the difficult part. The difficult part lies in trying to make objects match the clouds proportionally since they are not using a standard matrix.
You may be able to tweak your objects enough to give nice results though. I guess experimentation will be the best path on this.
Seymour Clufley wrote:
What would be nice would be to have the camera itself be underneath the cloud field, looking up at it.
The clouds are only being rendered on one side. If you go under them you will just have a pure sky without any clouds.
If you don't plan on going through to the other side. Then the clouds could probably be flipped upside down which should give you the desired effect.
The clouds may be able to be calculated for above and below, but I don't know enough about this shader to say for sure.
Seymour Clufley wrote:
The cloud field is the same every time the demo is run. Could the shader be adapted to generate a random cloud field every time, perhaps with parameters for density etc. that could be set in the PB program code? (The cloud field seems to be derived from the noise graphic shown below the shader code. Perhaps just generating a new random noise graphic, customised by the parameters, would solve this problem.)
Yes, changing the noise image should alter how the clouds are generated. I'm not sure if it was generated in a specific way for any reason, but I believe random noise should give you random clouds.
There are also some parameters for how far away the clouds are rendered, and while I haven't found them yet, there should also be some for the height of the clouds.
Seymour Clufley wrote:
Could the cloud field be made "infinite", so that, no matter how long the animation lasted (an arbitrary duration set in the PB program code), we never ran out of cloud? (I'm not sure if this is already the case with this code, or whether the model is "looped" at some stage, or whether the clouds would eventually just vanish.)
The clouds are infinite and they appear to use a seamless loop.
Seymour Clufley wrote:
Could the lighting and colouring be changed so that it looked like night-time?
Yep, I'll post some code below for you to test in ShaderToy.
Seymour Clufley wrote:
Could the PB code include gradual camera moves to be executed through the course of the animation?
Yep, shouldn't be a problem.
Seymour Clufley wrote:
Given all of these requirements, would you now recommend either Ogre or OpenGL?
I'd go with OpenGL, but that's easier for me to say because I've been using it for several years now.
If this is your first 3D project then I'd recommend Ogre. If this is going to be a very large project you're working on. Then Ogre might not be a good permanent solution, but it would give you a base understanding of how 3D engines work. Which would make diving into OpenGL easier.
PB/Ogre is what I originally started with and I worked with it for 2 or so years. Then I swapped to straight OpenGL and all the things I learned with Ogre really helped me in creating my own engine.
Shadertoy example nighttime with extended cloud distance. Just paste this in the block and hit the play button below it to run.
Code: Select all
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// Volumetric clouds. It performs level of detail (LOD) for faster rendering
float noise( in vec3 x )
{
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
#if 1
vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy;
vec2 rg = textureLod( iChannel0, (uv+ 0.5)/256.0, 0. ).yx;
#else
ivec3 q = ivec3(p);
ivec2 uv = q.xy + ivec2(37,17)*q.z;
vec2 rg = mix( mix( texelFetch( iChannel0, (uv )&255, 0 ),
texelFetch( iChannel0, (uv+ivec2(1,0))&255, 0 ), f.x ),
mix( texelFetch( iChannel0, (uv+ivec2(0,1))&255, 0 ),
texelFetch( iChannel0, (uv+ivec2(1,1))&255, 0 ), f.x ), f.y ).yx;
#endif
return -1.0+2.0*mix( rg.x, rg.y, f.z );
}
float map5( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q ); q = q*2.03;
f += 0.12500*noise( q ); q = q*2.01;
f += 0.06250*noise( q ); q = q*2.02;
f += 0.03125*noise( q );
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
float map4( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q ); q = q*2.03;
f += 0.12500*noise( q ); q = q*2.01;
f += 0.06250*noise( q );
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
float map3( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q ); q = q*2.03;
f += 0.12500*noise( q );
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
float map2( in vec3 p )
{
vec3 q = p - vec3(0.0,0.1,1.0)*iGlobalTime;
float f;
f = 0.50000*noise( q ); q = q*2.02;
f += 0.25000*noise( q );;
return clamp( 1.5 - p.y - 2.0 + 1.75*f, 0.0, 1.0 );
}
vec3 sundir = normalize( vec3(-1.0,0.0,-1.0) );
vec4 integrate( in vec4 sum, in float dif, in float den, in vec3 bgcol, in float t )
{
// lighting
vec3 lin = vec3(0.65,0.7,0.75)*1.4 + vec3(1.0, 1.0, 1.0)*dif;
vec4 col = vec4( mix( vec3(1.0,0.95,0.8), vec3(0.1,0.15,0.2), den ), den );
col.xyz *= lin;
col.xyz = mix( col.xyz, bgcol, 1.0-exp(-0.003*t*t) );
// front to back blending
col.a *= 0.4;
col.rgb *= col.a;
return sum + col*(1.0-sum.a);
}
#define MARCH(STEPS,MAPLOD) for(int i=0; i<STEPS; i++) { vec3 pos = ro + t*rd; if( pos.y<-3.0 || pos.y>2.0 || sum.a > 0.99 ) break; float den = MAPLOD( pos ); if( den>0.01 ) { float dif = clamp((den - MAPLOD(pos+0.3*sundir))/0.6, 0.0, 1.0 ); sum = integrate( sum, dif, den, bgcol, t ); } t += max(0.05,0.02*t); }
vec4 raymarch( in vec3 ro, in vec3 rd, in vec3 bgcol, in ivec2 px )
{
vec4 sum = vec4(0.0);
float t = 0.0;//0.05*texelFetch( iChannel0, px&255, 0 ).x;
MARCH(60,map5);
MARCH(60,map4);
MARCH(60,map3);
MARCH(60,map2);
return clamp( sum, 0.0, 1.0 );
}
mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
{
vec3 cw = normalize(ta-ro);
vec3 cp = vec3(sin(cr), cos(cr),0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = normalize( cross(cu,cw) );
return mat3( cu, cv, cw );
}
vec4 render( in vec3 ro, in vec3 rd, in ivec2 px )
{
// background sky
float sun = clamp( dot(sundir,rd), 0.0, 1.0 );
vec3 col = vec3(0.0,0.0,0.1) - rd.y*0.2*vec3(1.0,1.0,1.0) + 0.15*0.5;
col += 0.2*vec3(1.0,1.0,1.0)*pow( sun, 64.0 );
// clouds
vec4 res = raymarch( ro, rd, col, px );
col = col*(1.0-res.w) + res.xyz;
// sun glare
col += 0.2*vec3(1.0,1.0,1.0)*pow( sun, 64.0 );
return vec4( col, 1.0 );
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (-iResolution.xy + 2.0*fragCoord.xy)/ iResolution.y;
vec2 m = iMouse.xy/iResolution.xy;
// camera
vec3 ro = 4.0*normalize(vec3(sin(24.0*m.x), 0.4*m.y, cos(24.0*m.x)));
vec3 ta = vec3(0.0, -1.0, 0.0);
mat3 ca = setCamera( ro, ta, 0.0 );
// ray
vec3 rd = ca * normalize( vec3(p.xy,1.5));
fragColor = render( ro, rd, ivec2(fragCoord-0.5) );
}
void mainVR( out vec4 fragColor, in vec2 fragCoord, in vec3 fragRayOri, in vec3 fragRayDir )
{
fragColor = render( fragRayOri, fragRayDir, ivec2(fragCoord-0.5) );
}