《Learn Three.js》学习(2)构建Three.js根本组件

打印 上一主题 下一主题

主题 799|帖子 799|积分 2397

媒介:

本章将相识内容包括Three中的主要组件;THERE.SCENE对象的作用;多少图形和格网怎样关联;区别正射/透视投影摄像机
基础理论知识:


Three.scene(场景图)保存所有对象、光源和渲染所需的其他对象。
Three.scene 不仅仅是一个对象数组,还包含场景树形结构中的所有节点。
所有场景中的对象包括Three.scene都继续于THREE.Object3D的对象
为了更自由的查看场景,可以添加相关控制器,使用鼠标移动场景观看视角
  1.   // 创建鼠标控制器
  2.   let mouseControls = new OrbitControls(camera, renderer.domElement);
  3.   // 监听控制器,每次拖动后重新渲染画面
  4.   mouseControls.addEventListener('change', function(){
  5.     renderer.render(scene, camera);
  6.   });
复制代码
  THREE.Scene.Add - 向场景中添加对象
  THREE.Scene.Remove - 向场景中移除对象
  THREE.Scene.children - 获取场景中所有的子对象列表
  THREE.Scene.getObjectByName - 利用name属性,用于获取场景中的特定对象
  THERE.Scene中常用的方法和属性表:

demo

效果:

代码: 
  1. <script setup>// 导入three.jsimport * as THREE from 'three';//导入轨道控制器import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';// 导入调试工具import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';import Stats from 'three/examples/jsm/libs/stats.module.js';import { ElMessage } from 'element-plus';import { ref, onMounted } from 'vue';const webglOutput = ref(null);const statsOutput = ref(null);onMounted(() => {  const stats = initStats();  const scene = new THREE.Scene();  const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);  scene.add(camera);  const renderer = new THREE.WebGLRenderer();  renderer.setClearColor(new THREE.Color(0xFFFFFF, 1.0));  renderer.setSize(window.innerWidth, window.innerHeight);  renderer.shadowMap.enabled = true;  const planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);  const planeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, side: THREE.DoubleSide });  const plane = new THREE.Mesh(planeGeometry, planeMaterial);  plane.receiveShadow = true;  plane.rotation.x = -0.5 * Math.PI;  plane.position.set(0, 0, 0);  scene.add(plane);  camera.position.set(-30, 40, 30);  camera.lookAt(scene.position);  const ambientLight = new THREE.AmbientLight(0x0c0c0c);  scene.add(ambientLight);  const spotLight = new THREE.SpotLight(0xffffff);  spotLight.position.set(-40, 60, -10);  spotLight.castShadow = true;  scene.add(spotLight);  webglOutput.value.appendChild(renderer.domElement);  const controls = {    rotationSpeed: 0.02,    numberOfObjects: scene.children.length,    removeCube() {      const lastObject = scene.children[scene.children.length - 1];      // 判断最后一个物体是否是一个网格,制止移除摄像机和光源      if (lastObject instanceof THREE.Mesh) {        scene.remove(lastObject);        // 重新计算物体数量        controls.numberOfObjects = scene.children.length;      }    },    addCube() {      const cubeSize = Math.ceil(Math.random() * 3);      const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);      const cubeMaterial = new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff });      const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);      cube.castShadow = true;      cube.name = "cube-" + scene.children.length;      cube.position.x = -30 + Math.round(Math.random() * planeGeometry.parameters.width);      cube.position.y = Math.round(Math.random() * 5);      cube.position.z = -20 + Math.round(Math.random() * planeGeometry.parameters.height);      scene.add(cube);      controls.numberOfObjects = scene.children.length;    },    outputObjects() {      console.log(scene.children);    }  };  const gui = new GUI();  gui.add(controls, 'rotationSpeed', 0, 0.5);  gui.add(controls, 'addCube');  gui.add(controls, 'removeCube');  gui.add(controls, 'outputObjects');  gui.add(controls, 'numberOfObjects').listen();  function render() {    stats.update();    scene.traverse((e) => {      if (e instanceof THREE.Mesh && e !== plane) {        e.rotation.x += controls.rotationSpeed;        e.rotation.y += controls.rotationSpeed;        e.rotation.z += controls.rotationSpeed;      }    });    requestAnimationFrame(render);    renderer.render(scene, camera);  }  function initStats() {    const stats = new Stats();    stats.setMode(0);    stats.domElement.style.position = 'absolute';    stats.domElement.style.left = '0px';    stats.domElement.style.top = '0px';    statsOutput.value.appendChild(stats.domElement);    return stats;  }  // 创建鼠标控制器
  2.   let mouseControls = new OrbitControls(camera, renderer.domElement);
  3.   // 监听控制器,每次拖动后重新渲染画面
  4.   mouseControls.addEventListener('change', function(){
  5.     renderer.render(scene, camera);
  6.   });  render();});</script><template>  <div class="webgl-output" ref="webglOutput"></div>  <div class="stats-output" ref="statsOutput"></div></template><style>*{  margin:0;  padding:0;}canvas{  display: block;  position: fixed;  top: 0;  left: 0;  width: 100vw;  height: 100vh;}</style>
复制代码

THERE.Scene

THERE.Scene包含两个属性 ——fog、overrideMaterial
        fog

Scene.fog 线性雾


  1.   scene.fog = new THREE.Fog(0xffffff, 0.015, 100); // 0.015是近处的雾的浓度,100是远处的雾的浓度
复制代码
Scene.fogExp2 指数雾


  1.   // 指数雾
  2.   scene.fog = new THREE.FogExp2(0xffffff, 0.01); // 0.01是雾的浓度
复制代码
        overrideMaterial

设置overrideMaterial属性后,场景中所有物体都会使用该属性指向的材质,即使物体本身也设置了材质,使用该属性可以减少Three管理的材质数来提高运行效率。

  1.   scene.overrideMaterial = new THREE.MeshLambertMaterial({ color: 0x95d2c3 });
复制代码
THERE.Geometry 

一个立方体(三维空间中点集)有8个角,6个面,每个面都是包含3个顶角的三角形。
创建简朴立方体


  1. // 创建顶点
  2. const vertices = new Float32Array([
  3.     1, 3, 1,
  4.     1, 3, -1,
  5.     1, -1, 1,
  6.     1, -1, -1,
  7.     -1, 3, -1,
  8.     -1, 3, 1,
  9.     -1, -1, -1,
  10.     -1, -1, 1
  11. ]);
  12. // 创建面(使用索引而不是直接引用顶点)
  13. const indices = new Uint32Array([
  14.     0, 2, 1,
  15.     2, 3, 1,
  16.     4, 6, 5,
  17.     6, 7, 5,
  18.     4, 5, 1,
  19.     5, 0, 1,
  20.     7, 6, 2,
  21.     6, 3, 2,
  22.     5, 7, 0,
  23.     7, 2, 0,
  24.     1, 3, 4,
  25.     3, 6, 4
  26. ]);
  27. // 创建BufferGeometry
  28. const geometry = new THREE.BufferGeometry();
  29. geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
  30. geometry.setIndex(new THREE.BufferAttribute(indices, 1));
  31. geometry.computeVertexNormals(); // 计算顶点法线
  32. // 创建材质
  33. const material = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide });
  34. // 创建网格(Mesh)
  35. const mesh = new THREE.Mesh(geometry, material);
  36. mesh.position.set(0, 10, 0);
  37. // 将网格添加到场景中
  38. scene.add(mesh);
复制代码




阐明:由于版本更新使用对于简朴多少体构造的方法出现不同,但核心思想同等 
THREE.Geometry和THREE.Face在最新的Three.js版本中被THREE.BufferGeometry和THREE.Float32BufferAttribute所取代
举行面的绘制的点次序很紧张,顺时针为面向摄像机,反之背向摄像机
clone()

创建出多少体对象的拷贝
  1.   this.clone = function(){
  2.     const clonedGeometry = mesh.geometry.clone();
  3.     const materials = [
  4.         new THREE.MeshLambertMaterial({ opacity: 0.6, color: 0xff44ff, transparent: true }),
  5.         new THREE.MeshBasicMaterial({ color: 0x000000, wireframe: true })
  6.     ];
  7.     const mesh = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
  8.     mesh.children.forEach((e) => {
  9.         e.castShadow = true;
  10.     });
  11.     mesh.name = "clone";
  12.     mesh.position.x = 0;
  13.     mesh.position.y = 10;
  14.     mesh.position.z = 0;
  15.     mesh.translateX = 5;
  16.     scene.add(mesh);
  17.   }
复制代码
可以使用createMultiMaterialObject 和 WireFrameGeometry来添加线框,并使用xxx.material.linewidth 设置线框粗细 
THERE.Mesh(网格)

Mesh作用于Geometry之上
mesh的常见的属性和方法:

 正射/透视投影摄像机

  若只必要简朴VR摄像机(即简朴的立体视觉效果),可用
   1、THREE.StereoCamera将左右眼画面并排渲染;
  2、使用其他特别摄像机渲染时差屏蔽式的3D图像
  3、传统的红蓝重叠式3D图像
  透视(perspective)——更贴近真实天下
perspectiveCamera:



转换函数PToO: 
  1.   // 相机转换函数
  2.   this.changeCamera = function(){
  3.     if(camera instanceof THREE.PerspectiveCamera){
  4.         camera = new THREE.OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
  5.         camera.position.set(120, 60, 180);
  6.         camera.lookAt(scene.position);
  7.         this.perspective = "Orthographic";
  8.   }else{
  9.         camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
  10.         camera.position.set(-30, 40, 30);
  11.         camera.lookAt(scene.position);
  12.         this.perspective = "Perspective";
  13.     }
  14.   }
复制代码
正射(orthographic)
orthographicCamera:



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

半亩花草

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表