Lección 3 de 10 · El Sistema Solar en GLSL

Venus

Nubes de ácido sulfúrico. Dan la vuelta en cuatro días; el planeta, en 243.

Mercurio giraba entero. Venus no: sus nubes dan la vuelta en unos 4 días y el planeta tarda 243, y al revés. A eso se le llama superrotación. El truco: la latitud, asin(n.y), decide cuánto gira cada punto: el ecuador más, los polos menos.

lap es el ángulo de cada latitud. cos(lat)*cos(lat) vale 1 en el ecuador y 0 en los polos, así que shear separa las velocidades. Una forma que cruza latitudes se estira en franjas y en forma de V. Las nubes son el warp de Domain Warp sobre un ruido en 3D, estirado en y para hacer bandas.

Venus refleja el 76 % de la luz y abajo hay 465 °C. La atmósfera es tan gruesa que la luz da la vuelta: soft corre el terminador hacia la noche. Abajo: Velocidad, Cizalla y Suave.

Un capuchino visto desde arriba. A 465 °C.

latitud y giroasin(n.y) = latitud. Giro que depende de la latitud = rotación diferencial. (dot(n, sun) + soft)/(1.0 + soft) = la luz que da la vuelta.
PruebaPon shear en 0.0: gira como un trompo. Súbelo a 1.5 y espera un minuto: franjas. Lleva soft a 0.8: casi sin noche.

El código

precision highp float;
// The exact sphere: how far along the ray it is hit, or -1 if the ray misses
float sphere(vec3 ro, vec3 rd, float r){
  float b = dot(ro, rd), c = dot(ro, ro) - r*r, h = b*b - c;
  return h < 0.0 ? -1.0 : -b - sqrt(h);
}
// WoGL close: knee at 0.70, sRGB, chroma 1.3
vec3 wogl(vec3 c){
  float l = dot(c, vec3(0.2126, 0.7152, 0.0722)), k = max(l - 0.7, 0.0);
  c *= l > 0.0 ? (l - k + k/(1.0 + k))/l : 0.0;
  c = pow(clamp(c, 0.0, 1.0), vec3(0.4545));
  l = dot(c, vec3(0.2126, 0.7152, 0.0722));
  return clamp(mix(vec3(l), c, 1.3), 0.0, 1.0);
}
// Noise in 3D: the usual fb with one more dimension. On a globe it leaves no seam.
float h3(vec3 p){ return h2(p.xy + p.z*vec2(37.0, 17.0)); }
float n3(vec3 p){
  vec3 i = floor(p), f = fract(p);
  f = f*f*(3.0 - 2.0*f);
  return mix(mix(mix(h3(i), h3(i + vec3(1,0,0)), f.x), mix(h3(i + vec3(0,1,0)), h3(i + vec3(1,1,0)), f.x), f.y),
             mix(mix(h3(i + vec3(0,0,1)), h3(i + vec3(1,0,1)), f.x), mix(h3(i + vec3(0,1,1)), h3(i + vec3(1,1,1)), f.x), f.y), f.z);
}
float f3(vec3 p){
  float v = 0.0, a = 0.5;
  for (int i = 0; i < 5; i++){ v += a*n3(p); p = p*2.03 + vec3(1.7, 9.2, 4.1); a *= 0.5; }
  return v;
}
// A 2D turn (to spin the globe about its axis)
mat2 turn(float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }
// The background: black, with a star now and then
vec3 sky(vec2 f){
  float s = h2(floor(f));
  return vec3(0.0002, 0.0003, 0.0006) + vec3(0.7, 0.7, 0.8)*step(0.9982, s)*h2(floor(f) + 3.1);
}
float speed = 0.25;    // the clouds' lap
float shear = 0.9;     // how much faster the equator goes than the poles
float soft = 0.25;     // the light that wraps around through the air
void main(){
  vec2 p = (gl_FragCoord.xy*2.0 - R)/min(R.x, R.y);
  vec3 ro = vec3(0.0, 0.0, 3.2), rd = normalize(vec3(p, -2.4));   // the camera looks at the center
  vec3 sun = normalize(vec3(M.x*4.0 - 3.8, M.y*3.0 - 1.0, 1.0));   // you move the sun: it is the pointer
  vec3 col = sky(gl_FragCoord.xy);
  float t = sphere(ro, rd, 1.0);
  if (t > 0.0){
    vec3 n = normalize(ro + rd*t);
    float lat = asin(n.y);                                   // latitude: -1.57 at the south pole, 1.57 at the north
    float lap = T*speed*(1.0 + shear*cos(lat)*cos(lat));     // the equator laps more
    vec3 q = n; q.xz = turn(lap)*q.xz;
    float cloud = f3(q*vec3(2.2, 5.5, 2.2) + f3(q*3.0)*1.2); // bands: y stretched, and a warp (04)
    vec3 cream = vec3(0.95, 0.83, 0.58), ochre = vec3(0.62, 0.46, 0.24);
    vec3 albedo = mix(ochre, cream, smoothstep(0.30, 0.70, cloud))*0.76;   // Venus reflects 76%
    float light = max((dot(n, sun) + soft)/(1.0 + soft), 0.0);
    col = albedo*light*2.4;
  }
  gl_FragColor = vec4(wogl(col), 1.0);
}