前端特效18:使用cs与js生成的raymarching幽暗景观效果

今天,小编将与大家分享web前端特效荟萃系列第十八期,喜欢把玩儿炫酷效果的小伙伴快快看过来^_^ ,希望大家喜欢呦~





第18期,给大家分享一个使用cs与js生成的raymarching幽暗景观效果,相关代码如下:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>cloth</title>
  <style>
    body {
  margin: 0;
  padding: 0;
}
#container {
  position: fixed;
}
  </style>
</head>

  
<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
    void main() {
        gl_Position = vec4( position, 1.0 );
    }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
    uniform vec2 u_resolution;
    uniform float u_time;
  
    const int octaves = 2;
    const float seed = 43758.5453123;
    const float seed2 = 73156.8473192;

    // Gloable variables for the raymarching algorithm.
    const int maxIterations = 128;
    const float stepScale = .7;
    const float stopThreshold = 0.0005; // I'm not quite sure why, but thresholds in the order of a pixel seem to work better for me... most times. 
  
    // smooth min
    // reference: http://iquilezles.org/www/articles/smin/smin.htm
    float smin(float a, float b, float k) {
        float res = exp(-k*a) + exp(-k*b);
        return -log(res)/k;
    }
  
    float random(float val) {
      return fract(sin(val) * seed);
    }
  
    vec2 random2(vec2 st, float seed){
        st = vec2( dot(st,vec2(127.1,311.7)),
                  dot(st,vec2(269.5,183.3)) );
        return -1.0 + 2.0*fract(sin(st)*seed);
    }
  
    float random2d(vec2 uv) {
      return fract(
                sin(
                  dot( uv.xy, vec2(12.9898, 78.233) )
                ) * seed);
    }
  
    // Value Noise by Inigo Quilez - iq/2013
    // https://www.shadertoy.com/view/lsf3WH
    float noise(vec2 st, float seed) {
        vec2 i = floor(st);
        vec2 f = fract(st);

        vec2 u = f*f*(3.0-2.0*f);

        return mix( mix( dot( random2(i + vec2(0.0,0.0), seed ), f - vec2(0.0,0.0) ), 
                         dot( random2(i + vec2(1.0,0.0), seed ), f - vec2(1.0,0.0) ), u.x),
                    mix( dot( random2(i + vec2(0.0,1.0), seed ), f - vec2(0.0,1.0) ), 
                         dot( random2(i + vec2(1.0,1.0), seed ), f - vec2(1.0,1.0) ), u.x), u.y);
    }
  // Simplex 2D noise
  //
  vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }

  float snoise(vec2 v){
    const vec4 C = vec4(0.211324865405187, 0.366025403784439,
             -0.577350269189626, 0.024390243902439);
    vec2 i  = floor(v + dot(v, C.yy) );
    vec2 x0 = v -   i + dot(i, C.xx);
    vec2 i1;
    i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
    vec4 x12 = x0.xyxy + C.xxzz;
    x12.xy -= i1;
    i = mod(i, 289.0);
    vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
    + i.x + vec3(0.0, i1.x, 1.0 ));
    vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
      dot(x12.zw,x12.zw)), 0.0);
    m = m*m ;
    m = m*m ;
    vec3 x = 2.0 * fract(p * C.www) - 1.0;
    vec3 h = abs(x) - 0.5;
    vec3 ox = floor(x + 0.5);
    vec3 a0 = x - ox;
    m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
    vec3 g;
    g.x  = a0.x  * x0.x  + h.x  * x0.y;
    g.yz = a0.yz * x12.xz + h.yz * x12.yw;
    return 130.0 * dot(m, g);
  }
  
    vec3 plotCircle(vec2 pos, vec2 uv, float size) {
      return vec3(smoothstep(size, size + 0.05, length(uv - pos)));
    }
  
    float fbm (in vec2 st, float seed) {
      // Initial values
      float value = 0.0;
      float amplitude = .5;
      float frequency = 0.;
      //
      // Loop of octaves
      for (int i = octaves; i > 0; i--) {
          value += amplitude * abs(noise(st, seed));
          st *= 2.;
          amplitude *= .5;
      }
      return value;
  }
    float fbm1 (in vec2 st, float seed) {
      // Initial values
      float value = 0.0;
      float amplitude = .5;
      float frequency = 0.;
      //
      // Loop of octaves
      for (int i = octaves; i > 0; i--) {
          value += amplitude * fract(noise(st, seed));
          st *= 2.;
          amplitude *= .5;
      }
      return value;
  }
  
  // params:
  // p: arbitrary point in 3D space
  // c: the center of our sphere
  // r: the radius of our sphere
  float sphere_sdf(in vec3 p, in vec3 c, float r)
  { 
    return length(p - c) - r;
  }
  float torus_sdf( vec3 p, in vec3 c, vec2 t )
  {
    vec3 pos = p - c;
    vec2 q = vec2(length(pos.xz)-t.x,pos.y);
    return length(q)-t.y;
  }
  float roundbox_udf( vec3 p, vec3 b, float r )
  {
    return length(max(abs(p)-b,0.0))-r;
  }
  vec2 W(vec2 p){

    float t = u_time / 20.;

    // Layered, sinusoidal feedback, with time component.
    for (int i=0; i<octaves; i++){
        p += cos( p.yx * 3. + vec2(t,1.6)) / 3.,
        p += sin( p.yx + t + vec2(1.6,0)) / 2.,
        p *= 1.3;
    }

    // A bit of jitter to counter the high frequency sections.
    // p += fract(sin(p+vec2(13, 7))*5e5)*.03-.015;

    return mod(p,2.)-1.; // Range: [vec2(-1), vec2(1)]

  }
  float landscape_sfd(vec3 p, float offset, bool reverse) {
    float a = fbm(p.xz / 3., seed);
    if(reverse) {
      a = 1. - a;
    }
    // a = length(W(p.xz / 5.)) * .5 + .5;
    vec3 plane = vec3(p.x, a * 3. +offset, p.z);
    return length(plane - p);
  }
  
  mat4 rotationMatrix(vec3 axis, float angle)
  {
      axis = normalize(axis);
      float s = sin(angle);
      float c = cos(angle);
      float oc = 1.0 - c;

      return mat4(oc * axis.x * axis.x + c,           oc * axis.x * axis.y - axis.z * s,  oc * axis.z * axis.x + axis.y * s,  0.0,
                  oc * axis.x * axis.y + axis.z * s,  oc * axis.y * axis.y + c,           oc * axis.y * axis.z - axis.x * s,  0.0,
                  oc * axis.z * axis.x - axis.y * s,  oc * axis.y * axis.z + axis.x * s,  oc * axis.z * axis.z + c,           0.0,
                  0.0,                                0.0,                                0.0,                                1.0);
  }
  
  float world_sdf(in vec3 p)
  {
    // p = (vec4(p, 0.) * rotationMatrix(vec3(0., 1., 0.), u_time * .05)).xyz;
    float world = 0.;
    
    world = landscape_sfd(p, -8., true);
    
    world = smin(world, world, .4); // I have no idea why this removes the tears, but it does...
    
    world = smin(world, sphere_sdf(p, vec3(cos(u_time / 5.) * 5., -3., 15. + u_time), 4.), .5);
    world = smin(world, landscape_sfd(p, 3., false), .5);
    // world = min(world, sphere_sdf(p, vec3(cos(u_time / 5.) * 5., -1., 15. + u_time), 4.));
    
    // world = smin(world, sphere_sdf(p, vec3(cos(u_time / 5.) * 5. + cos(u_time / 2.) * 2., 2., 15. + u_time + sin(u_time / 2.) * 2.), .5), 1.);
    // world = smin(world, sphere_sdf(p, vec3(sin(u_time / 5.) * 5., cos(u_time) + 2., 15. + u_time), 3.), .5);
    
    return world;
  }
  
  vec3 calculate_normal(in vec3 p)
  {
      const vec3 small_step = vec3(0.0001, 0.0, 0.0);

      float gradient_x = world_sdf(p + small_step.xyy) - world_sdf(p - small_step.xyy);
      float gradient_y = world_sdf(p + small_step.yxy) - world_sdf(p - small_step.yxy);
      float gradient_z = world_sdf(p + small_step.yyx) - world_sdf(p - small_step.yyx);

      vec3 normal = vec3(gradient_x, gradient_y, gradient_z);

      return normalize(normal);
  }
  



// Raymarching.
float rayMarching( vec3 origin, vec3 dir, float start, float end, inout float field ) {
  
  float sceneDist = 1e4;
	float rayDepth = start; // Ray depth. "start" is usually zero, but for various reasons, you may wish to start the ray further away from the origin.
	for ( int i = 0; i < maxIterations; i++ ) {
		sceneDist = world_sdf( origin + dir * rayDepth ); // Distance from the point along the ray to the nearest surface point in the scene.

		if (( sceneDist < stopThreshold ) || (rayDepth >= end)) {	
			break;
		}
		rayDepth += sceneDist * stepScale;

	}
	if ( sceneDist >= stopThreshold ) rayDepth = end;
	else rayDepth += sceneDist;
		
	// We've used up our maximum iterations. Return the maximum distance.
	return rayDepth;
}
  
  
vec3 lighting( vec3 sp, vec3 camPos, int reflectionPass, float dist, float field){

    // Start with black.
    vec3 sceneColor = vec3(0.0);

    // Obtain the surface normal at the scene position "sp."
    vec3 surfNormal = calculate_normal(sp);

    // Object's color.
    vec3 objColor = vec3(1.2);
    objColor += vec3(0., 0., 1.) * field * 5.;
    objColor += vec3(-1.5, -1.5, -1.5) * 0.3 * clamp((sp.y) / 2., 0., 2.);
    objColor += vec3(2., -1.2, -.2) * clamp(sp.y - 3., 0., 1.);
    objColor += vec3(-3., -3.2, -3.2) * clamp(-sp.y - 3.2, 0., 1.);

    // Lighting.

    // lp - Light position. Keeping it in the vacinity of the camera, but away from the objects in the scene.
    vec3 lp = vec3(0., 3.0, -2.0+u_time);
    // ld - Light direction.
    vec3 ld = lp-sp;
    // lcolor - Light color.
    vec3 lcolor = vec3(1.,0.97,0.92) * 2.;
    
     // Light falloff (attenuation).
    float len = length( ld ); // Distance from the light to the surface point.
    ld /= len; // Normalizing the light-to-surface, aka light-direction, vector.
    float lightAtten = min( 1.0 / ( 0.25*len ), 1.0 ); // Keeps things between 0 and 1.   

    // Obtain the reflected vector at the scene position "sp."
    vec3 ref = reflect(-ld, surfNormal);

    float ambient = .05; //The object's ambient property.
    float specularPower = 0.9; // The power of the specularity. Higher numbers can give the object a harder, shinier look.
    float diffuse = max( 0.0, dot(surfNormal, ld) ); //The object's diffuse value.
    float specular = max( 0.0, dot( ref, normalize(camPos-sp)) ); //The object's specular value.
    specular = pow(specular, specularPower); // Ramping up the specular value to the specular power for a bit of shininess.
  
    // Bringing all the lighting components togethr to color the screen pixel.
    sceneColor += (objColor*(diffuse*0.8+ambient)+specular*0.5)*lcolor*lightAtten;
    
    return sceneColor;

}

    void main() {
      
      // Setting up our screen coordinates.
      vec2 aspect = vec2(u_resolution.x/u_resolution.y, 1.0); //
      vec2 uv = (2.0*gl_FragCoord.xy/u_resolution.xy - 1.0)*aspect;
      
      // Using polars to warp the domain
      float len = length(uv);
      float angle = atan(uv.y, uv.x);
      angle += sin(u_time / 20.) * .3;
      
      uv = vec2(len * cos(angle), len * sin(angle));

      // Camera Setup.
      // the scene now has a moving camera.
      vec3 lookAt = vec3(0., 0.8, u_time);  // This is the point you look towards, or at, if you prefer.
      // vec3 lookAt = vec3(0., 1.*sin(time*0.5), time);  // This is the point you look towards, or at, if you prefer.
      vec3 camera_position = vec3(0., 1., -1.0 + u_time); // This is the point you look from, or camera you look at the scene through. Whichever way you wish to look at it.

      vec3 forward = normalize(lookAt-camera_position); // Forward vector.
      vec3 right = normalize(vec3(forward.z, 0., -forward.x )); // Right vector... or is it left? Either way, so long as the correct-facing up-vector is produced.
      vec3 up = normalize(cross(forward,right)); // Cross product the two vectors above to get the up vector.

      // FOV - Field of view.
      float FOV = 0.8;

      // ro - Ray origin.
      vec3 ro = camera_position; 
      // rd - Ray direction.
      vec3 rd = normalize(forward + FOV*uv.x*right + FOV*uv.y*up);
      
      // Ray marching.
      const float clipNear = 0.0;
      const float clipFar = 64.0;
      float field = 0.;
      float dist = rayMarching(ro, rd, clipNear, clipFar, field );
      if ( dist >= clipFar ) {
          gl_FragColor = vec4(vec3(0.), 1.0);
          return;
      }

      // sp - Surface position.
      vec3 sp = ro + rd*dist;

      // Light the pixel that corresponds to the surface position.
      vec3 sceneColor = lighting( sp, camera_position, 0, dist, field);

        // Clamping the lit pixel, then put it on the screen.
      gl_FragColor = vec4(clamp(sceneColor, 0.0, 1.0), 1.0);


    }
</script>


<div id="container"></div>
  <script>
    let container;
let camera, scene, renderer;
let uniforms;

function init() {
  container = document.getElementById( 'container' );

  camera = new THREE.Camera();
  camera.position.z = 1;

  scene = new THREE.Scene();

  var geometry = new THREE.PlaneBufferGeometry( 2, 2 );

  uniforms = {
    u_time: { type: "f", value: 1.0 },
    u_resolution: { type: "v2", value: new THREE.Vector2() },
    u_mouse: { type: "v2", value: new THREE.Vector2() }
  };

  var material = new THREE.ShaderMaterial( {
    uniforms: uniforms,
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent
  } );

  var mesh = new THREE.Mesh( geometry, material );
  scene.add( mesh );

  renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio( 1 );

  container.appendChild( renderer.domElement );

  onWindowResize();
  window.addEventListener( 'resize', onWindowResize, false );

  document.onmousemove = function(e){
    uniforms.u_mouse.value.x = e.pageX
    uniforms.u_mouse.value.y = e.pageY
  }
}

function onWindowResize( event ) {
  renderer.setSize( window.innerWidth, window.innerHeight );
  uniforms.u_resolution.value.x = renderer.domElement.width;
  uniforms.u_resolution.value.y = renderer.domElement.height;
}

function animate() {
  requestAnimationFrame( animate );
  render();
}

function render() {
  uniforms.u_time.value += 0.05;
  renderer.render( scene, camera );
}
init();
animate();
  
  </script>
</body>
</html>

在线演示:Here~ 



今天的分享就是这些啦,这里是igeekbar,希望可以给各位geek小伙伴们带来帮助呦~~~如果你制作出了或收藏了哪些炫酷的前端特效,赶快留言分享给我们呦~~~


Geek豪哥   iGeekBar社区大管家

iGeekBar创始人之一,热爱科技与设计,正在探索研究数据科学的女猿,最爱勾搭极客帅哥美女的逗比疯姑娘~~
     扫一扫立刻加入iGeekBar会员QQ群(545980198)
    和更多iG客会员交流分享吧~