用three.js实现一个圣诞节下雪场景

效果图:

148030528-0e158fc4-895b-47c8-86d6-055d39698a24.png

该场景中包含了动画,下雪,灯光,天空盒,音乐播放等效果,话不多说,上代码。

引入基本模块

需要分别引入three对象、相机视角控制器、模型加载器

import * as THREE from "./node_modules/three/build/three.module.js";
import { OrbitControls } from "./node_modules/three/examples/jsm/controls/OrbitControls.js";
import { OBJLoader } from "./node_modules/three/examples/jsm/loaders/OBJLoader.js";
import { MTLLoader } from "./node_modules/three/examples/jsm/loaders/MTLLoader.js";

定义初始变量

let { scene, camera, renderer, ray } = {
  scene: new THREE.Scene(), // 场景
  camera: new THREE.Camera(), // 相机
  renderer: new THREE.WebGLRenderer(), // webgl渲染器
  ray: new THREE.Raycaster(), // 下面需要用到射线查询的二维向量
}
let christmasTree = null; // 圣诞树
// 鼠标XY数据
let mouse = new THREE.Vector2(); // 配合射线查询的鼠标屏幕坐标
// 光 
let { point, ambient } = {
  ambient: new THREE.AmbientLight("#fff", 0.5),
  point: new THREE.PointLight("#fff", 0.6)
}
// 将下雪的精灵图放到一组group中方便控制
let snows = new THREE.Group();
scene.add(ambient);

let { that, lighePower } = {
  that: null,
  lighePower:1
}

现在开始架势了!

既然是三维场景,那么必然的相机、渲染器、灯光是必不可少的,搭配好场景元素之后,开始使用精灵图进行雪花的渲染

开始初始化界面

  init() {

    that = this;

    //创建相机对象
    camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 1, 3000);
    camera.position.set(5, 5, 50); //设置相机位置
    camera.lookAt(scene.position); //设置相机方向(指向的场景对象)



    point.position.set(0, 30 ,80); //点光源位置



    document.body.appendChild(renderer.domElement);
    renderer.shadowMap.enabled = true;
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor("#c2c2c2");


    var texture = new THREE.TextureLoader().load("./assets/images/snow.jpg");
    // 批量创建雨滴精灵模型
    for (let i = 0; i < 3800; i++) {



      var spriteMaterial = new THREE.SpriteMaterial({
        map:texture,//设置精灵纹理贴图
      });
      // 创建精灵模型对象
      var sprite = new THREE.Sprite(spriteMaterial);
      snows.add(sprite);
      // 控制精灵大小
      sprite.scale.set(0.8, 1, 1); //// 只需要设置x、y两个分量就可以
      var k1 = Math.random() - 0.5;
      var k2 = Math.random() - 0.5;
      var k3 = Math.random() - 0.5;
      // 设置精灵模型位置,在整个空间上上随机分布
      sprite.position.set(800 * k1, 800*k3, 600 * k2)
    }
    scene.add(snows);//雨滴群组插入场景中

  // 控制精灵大小,比如可视化中精灵大小表征数据大小
  sprite.scale.set(10, 10, 1); //// 只需要设置x、y两个分量就可以

    this.initSkyBox();
    this.initAudio();
    this.initChristmasThree();
    this.initMapMesh();
    this.animation();
    this.hanldRender();
    this.initLight();
    new OrbitControls(camera, renderer.domElement);//创建控件对象

    setTimeout(() => {
      document.querySelector("#loadingShadow").style.display = "none";
    }, 3000);

  }

设置天空盒

initSkyBox() {

 let skyBox = {
      path: "./assets/sky_box/christmas/",
      imageList: ["夜景_LF.jpg", "夜景_RT.jpg", "夜景_UP.jpg", "夜景_DN.jpg", "夜景_FR.jpg", "夜景_BK.jpg"]
    }


    let cubTextureLoader = new THREE.CubeTextureLoader();


    cubTextureLoader.setPath(skyBox.path);



    let realTexture = cubTextureLoader.load(skyBox.imageList);



    realTexture.encoding = THREE.sRGBEncoding;


    scene.background = realTexture;


  }


开始加载圣诞树

这个模型我是在网上找的,大家可以根据自己的需求进行替换,或者去我的网盘里拿,地址在底部

initChristmasThree () {
    // 添加颜色和材质
    new MTLLoader()
      .setPath('./3dPage/obj/')
      .load('charsitmasTree.mtl', function (materials) {

        materials.preload();

        new OBJLoader()
        .setMaterials(materials)
        .setPath('./3dPage/obj/')
        .load('charsitmasTree.obj', function (object) {
          
          object.position.y = - 40;
          object.position.x = - 40;
          object.isChristmasTree = true;
  
          let scaleVal = 1;
          object.scale.x = scaleVal;
          object.scale.y = scaleVal;
          object.scale.z = scaleVal;
  
          christmasTree = object;
          scene.add(object);

          var christmasTreeLight = new THREE.SpotLight( "#fff", 5 );

          christmasTreeLight.castShadow = true;
          christmasTreeLight.angle = 0.8;
          christmasTreeLight.position.y = 80;
          christmasTreeLight.position.x = 50;
          christmasTreeLight.position.z = -40;
          scene.add(christmasTreeLight);
          // scene.add(new THREE.SpotLightHelper(christmasTreeLight))
          christmasTreeLight.target = christmasTree;
          
        });
      });
     
  }

加载音频

这个算是DOM的啦,一眼就会,没用three.js的音频加载

initAudio () {
    let audioElem = document.createElement("audio");
    audioElem.setAttribute("src", "./music/ddd.mp3");
    audioElem.setAttribute("autoplay", "true");
    audioElem.style.display = "none";
    document.body.appendChild(audioElem);
  }

画礼物箱

现在开始用mesh画圣诞老人的礼物箱啦

  initMapMesh () {
    let theMeshArr = new THREE.Group();;
    let mesh1Geomertry = new THREE.BoxBufferGeometry(18, 18, 18);
    let mesh1Map = new THREE.TextureLoader().load('assets/mapping/christmas/src=http___img.51miz.com_Element_00_74_37_37_c2cb4906_E743737_6664c406.jpg!_quality_90_unsharp_true_compress_true_format_jpg&refer=http___img.51miz.jpg');
    let material1 = new THREE.MeshPhongMaterial({map: mesh1Map});
    let mesh = new THREE.Mesh(mesh1Geomertry, material1);
    mesh.rotateY(-20);
    mesh.position.x = -32;
    mesh.position.y = -15;
    theMeshArr.add(mesh);



    let mesh2Geomertry = new THREE.BoxBufferGeometry(55, 55, 5);
    let mesh1Map1 = new THREE.TextureLoader().load('./assets/mapping/christmas/src=http___img1.dowebok.com_6457s.jpg&refer=http___img1.dowebok.jpg');
    let material2 = new THREE.MeshPhongMaterial({map: mesh1Map1});
    let mesh2 = new THREE.Mesh(mesh2Geomertry, material2);
    this.testMesh = mesh2;
    mesh2.position.z = -11;
    console.log(mesh2.position);
    theMeshArr.add(mesh2);



    let mesh3Geomertry = new THREE.BoxBufferGeometry(10, 10, 10);
    let mesh1Map2 = new THREE.TextureLoader().load('assets/mapping/christmas/src=http___picnew13.photophoto.cn_20181204_lvseshengdanhaibaobeijing-32425348_1.jpg&refer=http___picnew13.photophoto.jpg');
    let material3 = new THREE.MeshPhongMaterial({map: mesh1Map2});
    let mesh3 = new THREE.Mesh(mesh3Geomertry, material3);
    mesh3.position.y = - 17.5;
    mesh3.position.x = - 15;
    theMeshArr.add(mesh3);


    theMeshArr.position.x = 40;
    theMeshArr.position.y = -12;
    theMeshArr.position.z = 5;
    theMeshArr.rotateY(5.9);



    theMeshArr.children.forEach(item =>{
      item.receiveShadow = true;
      item.castShadow = true;
    });
    

    scene.add(theMeshArr);
  }

圣诞灯光

圣诞节专属的红蓝绿三原色灯光,那可不能少

initLight () {
    // 圣诞节三色灯光
    let redLight = new THREE.PointLight("red",lighePower, 70, 2);
    let greenLight = new THREE.PointLight("green",lighePower, 60, 2);
    let blueLight = new THREE.PointLight("blue",lighePower, 60 ,2);
    let sporLight = new THREE.SpotLight("#fff");
    sporLight.position.y += 5;
    sporLight.angle = 0.8;
    sporLight.penumbra = 0.9;
    sporLight.position.x = 35;
    sporLight.position.z = 10;

    scene.add(sporLight);
    sporLight.target = this.testMesh;
    // sporLight.penumbra = 1;


    redLight.position.set(35,6,30);
    greenLight.position.set(55,5,30);
    blueLight.position.set(20,5,20);
    // scene.add(new THREE.PointLightHelper(light1))
    //添加灯光
    // scene.add(light1);
    let lightGroup = new THREE.Group();


    lightGroup.add(redLight);
    lightGroup.add(greenLight);
    lightGroup.add(blueLight);


    lightGroup.isLightGroup = true;

    scene.add(lightGroup);
  }

三维场景其他基本元素

这些就不多说了,直接一把梭吧!

hanldRender() {
    window.addEventListener("resize", this.windowResize, false);
    document.querySelectorAll("canvas")[0].addEventListener("click", this.moueMove, false);
    // document.querySelectorAll("canvas")[0].addEventListener("mousemove", this.moueMove, false);


  }


  windowResize() {



    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);


  }


  moueMove(e) {


    mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;



    ray.setFromCamera(mouse, camera);

    let theInt = ray.intersectObjects(christmasTree.children);


    if (theInt.length) {

      theInt.sort();
      console.log(theInt);

    }

  }



  animation() {

    renderer.render(scene, camera);

    let chrsitmas = scene.children.find(item => item.isChristmasTree);
    

    let lightGroup = scene.children.find(item => item.isLightGroup);

    if (lightGroup) {

     lightGroup.children.forEach(item => {

      var time = new Date() * 0.003;

      item.intensity = Math.sin(time) * 1 + 0.8;

     })

    }
    
    // 落雪
    snows.children.forEach(sprite => {

      sprite.position.y -= 0.4;

      if (sprite.position.y < - 200) {

        sprite.position.y = 200;

      }

    });
   
    // console.log(lighePower);
    if (chrsitmas) {

      chrsitmas.rotateY(0.004);

    };
    
    requestAnimationFrame(that.animation);

  }

跑起来你就可以得到一个有三原色灯光闪动,不断旋转自动播放的有浓浓圣诞节气氛的三维场景啦!

源码在这里github.com/GoGeChang/t… 两年前写的项目了,比较菜,欢迎大佬交流。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYuR6OV0' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片