ThreeJS实现3D星空隧道效果

图片

主要运用TubeGeometry来制作自定义的隧道效果

1.初始化场景

function init(){
  //创建 WebGL renderer
  var canvas = document.querySelector("canvas");
  renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true,
    shadowMapEnabled: true,
    shadowMapType: THREE.PCFSoftShadowMap });

  renderer.setSize(ww, wh);

  //创建场景 添加雾效果,是场景朦胧些
  scene = new THREE.Scene();
  scene.fog = new THREE.Fog(0x194794, 0, 100);

  var clock = new THREE.Clock();

  //创建透视类型的相机
  cameraRotationProxyX = 3.14159;
  cameraRotationProxyY = 0;

  camera = new THREE.PerspectiveCamera(45, ww / wh, 0.001, 200);
  camera.rotation.y = cameraRotationProxyX;
  camera.rotation.z = cameraRotationProxyY;

  group = new THREE.Group();
  group.position.z = 400;

  group.add(camera);
  scene.add(group);

  //创建点光源
  light = new THREE.PointLight(0xffffff, .35, 4, 0);
  light.castShadow = true;
  scene.add(light);
}

2.创建星空管道

用连续的空间点创建自定义曲线,然后根据曲线来创建管道 再添加贴图

function createSkyTube(){
  //Array of points
  var points = [
  [10, 89, 0],[50, 88, 10],[76, 139, 20],
  [126, 141, 12],[150, 112, 8],[157, 73, 0],
  [180, 44, 5],[207, 35, 10],[232, 36, 0]];

  var p1, p2;

  //points转化为 vertices
  for (var i = 0; i < points.length; i++) {
    var x = points[i][0];
    var y = points[i][2];
    var z = points[i][1];
    points[i] = new THREE.Vector3(x, y, z);
  }
  //根据路径点创建自定义曲线
  path = new THREE.CatmullRomCurve3(points);  
  path.tension = .5;

  //创建TubeGeometry
  var geometry = new THREE.TubeGeometry(path, 300, 4, 32, false);   

  //贴图
  var texture = new THREE.TextureLoader().load('res/3d_space_5.jpg', function (texture) {
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    texture.offset.set(0, 0);
    texture.repeat.set(15, 2);
  });

  //凹凸贴图,影响光照感知深度
  var mapHeight = new THREE.TextureLoader().load('res/waveform-bump3.jpg', function (texture) {
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    texture.offset.set(0, 0);
    texture.repeat.set(15, 2);
  });

  //创建MeshPhong镜面高光材质
  var material = new THREE.MeshPhongMaterial({
    side: THREE.BackSide,
    map: texture,
    shininess: 20,
    bumpMap: mapHeight,
    bumpScale: -.03,
    specular: 0x0b2349 }
  );

  //Create a mesh
  var tube = new THREE.Mesh(geometry, material);
  scene.add(tube);
}

此时效果如下,效果很干不够立体,然后我们加上辅助线效果

图片

3.添加立体辅助线

思路是创建比星空管道半径更小的TubeGeometry,然后用EdgesGeometry来创建

//再创建半径略小的管道,添加几何体辅助线
function createTubeEdges(){
  var geometry = new THREE.TubeGeometry(path, 150, 3.4, 32, false);
  //创建边缘几何体
  var geo = new THREE.EdgesGeometry(geometry);  
  var mat = new THREE.LineBasicMaterial({
    linewidth: 2,
    opacity: .2,
    transparent: 1 }
  );

  //创建线段
  var wireframe = new THREE.LineSegments(geo, mat);
  scene.add(wireframe);
}

此时效果如图,显得更加立体了 但是光线还是太暗,我们再用后期效果处理一下

图片

4.添加后期泛光通道

UnrealBloonPass是three.js后期处理的扩展库,可以用来模拟生活中的泛光或眩光效果,用在星空效果里恰到好处 用法如下

function initRenderPass(){
  var params = {
    exposure: 1.3,
    bloomStrength: .9,
    bloomThreshold: 0,
    bloomRadius: 0 
  };
  //set up render pass
  var renderScene = new THREE.RenderPass(scene, camera);
  //创建泛光通道
  var bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
  bloomPass.renderToScreen = true;
  bloomPass.threshold = params.bloomThreshold;	//阈值
  bloomPass.strength = params.bloomStrength;		//强度
  bloomPass.radius = params.bloomRadius;			  //半径
  composer = new THREE.EffectComposer(renderer);
  composer.setSize(window.innerWidth, window.innerHeight);
  composer.addPass(renderScene);
  composer.addPass(bloomPass);
}

此时效果图:

图片

5.加上粒子效果来点缀

这里以创建一个为例,项目中创建了三个来交叉运动,加上之后就有了文章开头的效果

var particleSystem1,particleSystem2,particleSystem3;
function createParticles(){
  var lastPlace = 0;
  var newPlace = 0;

  //粒子贴图
  var spikeyTexture = new THREE.TextureLoader().load('res/spikey.png');

  var particleCount = 6800;
  particles1 = new THREE.Geometry();

  //粒子材质
  pMaterial = new THREE.ParticleBasicMaterial({
    color: 0xFFFFFF,
    size: .5,
    map: spikeyTexture,
    transparent: true,
    blending: THREE.AdditiveBlending 
  });


  for (var p = 0; p < particleCount; p++) {
    // 随机创建粒子
    // 随机值 -250 -> 250
    var pX = Math.random() * 500 - 250,
    pY = Math.random() * 50 - 25,
    pZ = Math.random() * 500 - 250,
    particle = new THREE.Vector3(pX, pY, pZ);
    particles1.vertices.push(particle);
  }

  // create the particle system
  particleSystem1 = new THREE.ParticleSystem(particles1,pMaterial);

  // add it to the scene
  scene.add(particleSystem1);
}

6. render实时变化,让粒子动起来

function render() {
  //...
  particleSystem1.rotation.y += 0.00002;
  particleSystem2.rotation.x += 0.00005;
  particleSystem3.rotation.z += 0.00001;
  //...
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

7. 关联鼠标滚动,让摄像机跟随

用gsap的ScrollTrigger插件来关联滚动,用法如下:

//初始化gsap鼠标滚动
function initAction(){
  gsap.defaultEase = Linear.easeNone;

  var tubePerc = {percent: 0 };

  //注册ScrollTrigger
  gsap.registerPlugin(ScrollTrigger);

  var tl = gsap.timeline({
    scrollTrigger: {
      trigger: ".scrollTarget",
      start: "top top",
      end: "bottom 100%",
      scrub: 5,
      markers: { color: "white" } } 
  });

  tl.to(tubePerc, {
    percent: .96,
    ease: Linear.easeNone,
    duration: 10,
    onUpdate: function () {
      cameraTargetPercentage = tubePerc.percent;
    } 
  });
}

这里根据onupdate的cameraTargetPercentage值可以去更新相机的位置

8.更新相机的位置

function updateCameraPercentage(percentage) {
  //camera位于p1点看向p2点
  p1 = path.getPointAt(percentage);
  p2 = path.getPointAt(percentage + 0.03);

  group.position.set(p1.x, p1.y, p1.z);
  group.lookAt(p2);
  light.position.set(p2.x, p2.y, p2.z);
}

 

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值