当前位置: 首页 > news >正文

three.js之特殊材质效果

 *案例42 创建一个透明的立方体

<template>
  <div ref="container" className="container"></div>
</template>

<script setup>
import * as THREE from 'three';
import WebGL from 'three/examples/jsm/capabilities/WebGL.js'
// 引入轨道控制器扩展库OrbitControls.js
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
import {TransformControls} from 'three/examples/jsm/controls/TransformControls.js'
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import {ref, onMounted} from 'vue'

let container = ref(null)

onMounted(() => {
  /*
    * * 创建场景(渲染必加代码)
    */
  // 获取容器的实际宽高
  const containerWidth = container.value.clientWidth;
  const containerHeight = container.value.clientHeight;
  // 创建场景
  const scene = new THREE.Scene();


  /*
  * * 创建摄像机(渲染必加代码)
  * */
  // 创建摄像机(three.js有好几种摄像机,这里用的是透视摄像机)
  // 参数 1:fov视野角度(注意:这个参数如果调整不好,会导致物体的透视效果看起来怪怪的)
  //      控制相机能看到的角度范围。
  //      就像你眼睛睁得越大,看到的范围就越广;睁得越小,看到的范围就越窄
  // 参数 2:aspect长宽比,控制相机看到的画面的宽高比。
  //      就像你调整手机屏幕的横屏或竖屏模式,画面的宽高比会变化
  // 参数 3:near近截面,控制相机能看到的最小距离,默认值是0.1
  //      1 表示距离相机 1 个单位以内的物体不会被渲染
  // 参数 4:far远截面,控制相机能看到的最大距离
  //      1000 表示距离相机 1000 个单位以外的物体不会被渲染
  const camera = new THREE.PerspectiveCamera(30, containerWidth / containerHeight, 1, 100);
  // camera.position 和 camera.lookAt 如果不设置可能会导致画面看不到效果
  // 摄像机的位置
  camera.position.set(5, 3.5, 4.7);
  // 摄像机聚焦的位置
  camera.lookAt(0, 0, 0);
  // zoom属性可以获取或者设置摄像机的缩放倍数,其默认值为1
  camera.zoom = 1
  // 【注意,在大多数属性发生改变之后,需要调用.updateProjectionMatrix来使得这些改变生效】
  camera.updateProjectionMatrix()


  /*
  * * 创建渲染器(渲染必加代码)
  * */
  // 创建渲染器(three.js有好几种渲染器)
  const renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  // 第三个参数(选填):false代表以较低分辨率渲染
  renderer.setSize(containerWidth, containerHeight );
  // 将渲染器放入文档中
  container.value.appendChild(renderer.domElement);


  /*
  * 创建坐标轴对象(用于辅助创建3D场景)
  * */
  // AxesHelper() 的参数代表坐标轴的线段长度
  // 红色代表x轴,绿色代表y轴,蓝色代表z轴
  const axesHelper = new THREE.AxesHelper(5);
  scene.add(axesHelper);


  /*
  * 创建轨道控制器
  * */
  const orbitControls = new OrbitControls(camera, renderer.domElement);
  // 更新控制器
  orbitControls.update();
  orbitControls.addEventListener('change', function () {
    // 输出相机位置
    //console.log('camera.position', camera.position);
  });


  /*
    * 创建一个透明的立方体
    * (效果不太理想,立方体的背面没有显示)
    * */
  // 新建立方体对象
  const geometry = new THREE.BoxGeometry(1,1,1);

  // 创建材质
  // MeshBasicMaterial材质不受光照影响
  const material = new THREE.MeshBasicMaterial({
    // 材质颜色
    color: '#2ccdf1',
    // 启用透明
    transparent: true,
    // 设置透明度
    opacity: 0.35,
    // 渲染正面和背面
    side: THREE.DoubleSide,
  });

  // 新建网格(网格包含集合体和作用在几何体上面的材质)
  const cube = new THREE.Mesh(geometry, material);
  // 将网格添加到场景
  scene.add(cube);



  /*
  * 渲染场景必加代码 (渲染循环)
  * */
  // 渲染循环
  function animate() {
    // 每秒执行60次
    requestAnimationFrame(animate);

    // 更新控制器
    orbitControls.update();
    // 渲染场景
    renderer.render(scene, camera);
  }

  // WebGL兼容性检查
  if (WebGL.isWebGLAvailable()) {
    animate();
  } else {
    const warning = WebGL.getWebGLErrorMessage();
    container.value.appendChild(warning);
  }

  /**
   * 窗口变化自适应(必加代码)
   */
  const onWindowResize = () => {
    // 获取容器的实际宽高
    const containerWidth = container.value.clientWidth;
    const containerHeight = container.value.clientHeight;
    // 重置渲染器输出画布canvas尺寸
    renderer.setSize(containerWidth, containerHeight);
    // aspect属性 是摄像机视锥体的长宽比,通常设置为,画布的宽/画布的高
    // 全屏情况下:设置 观察范围长宽比aspect,为窗口宽高比
    camera.aspect =containerWidth / containerHeight;
    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
    // 因此如果相机的属性发生了变化,需要执行updateProjectionMatrix ()方法来使得这些属性生效
    camera.updateProjectionMatrix();
  }
  // 监听浏览器窗口大小改变
  window.addEventListener('resize', onWindowResize);

})
</script>
<style>

</style>
<style scoped>
.container {
  height: 100vh;
  box-sizing: border-box;
  /* overflow属性(必填),否则页面自适应时,偶尔会出现滚动条*/
  overflow: hidden;
}
</style>

*案例43 创建一个线框球体

<template>
  <div ref="container" className="container"></div>
</template>

<script setup>
import * as THREE from 'three';
import WebGL from 'three/examples/jsm/capabilities/WebGL.js'
// 引入轨道控制器扩展库OrbitControls.js
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
import {TransformControls} from 'three/examples/jsm/controls/TransformControls.js'
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import {ref, onMounted} from 'vue'

let container = ref(null)

onMounted(() => {
  /*
    * * 创建场景(渲染必加代码)
    */
  // 获取容器的实际宽高
  const containerWidth = container.value.clientWidth;
  const containerHeight = container.value.clientHeight;
  // 创建场景
  const scene = new THREE.Scene();


  /*
  * * 创建摄像机(渲染必加代码)
  * */
  // 创建摄像机(three.js有好几种摄像机,这里用的是透视摄像机)
  // 参数 1:fov视野角度(注意:这个参数如果调整不好,会导致物体的透视效果看起来怪怪的)
  //      控制相机能看到的角度范围。
  //      就像你眼睛睁得越大,看到的范围就越广;睁得越小,看到的范围就越窄
  // 参数 2:aspect长宽比,控制相机看到的画面的宽高比。
  //      就像你调整手机屏幕的横屏或竖屏模式,画面的宽高比会变化
  // 参数 3:near近截面,控制相机能看到的最小距离,默认值是0.1
  //      1 表示距离相机 1 个单位以内的物体不会被渲染
  // 参数 4:far远截面,控制相机能看到的最大距离
  //      1000 表示距离相机 1000 个单位以外的物体不会被渲染
  const camera = new THREE.PerspectiveCamera(30, containerWidth / containerHeight, 1, 100);
  // camera.position 和 camera.lookAt 如果不设置可能会导致画面看不到效果
  // 摄像机的位置
  camera.position.set(5, 3.5, 4.7);
  // 摄像机聚焦的位置
  camera.lookAt(0, 0, 0);
  // zoom属性可以获取或者设置摄像机的缩放倍数,其默认值为1
  camera.zoom = 1
  // 【注意,在大多数属性发生改变之后,需要调用.updateProjectionMatrix来使得这些改变生效】
  camera.updateProjectionMatrix()


  /*
  * * 创建渲染器(渲染必加代码)
  * */
  // 创建渲染器(three.js有好几种渲染器)
  const renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  // 第三个参数(选填):false代表以较低分辨率渲染
  renderer.setSize(containerWidth, containerHeight );
  // 将渲染器放入文档中
  container.value.appendChild(renderer.domElement);


  /*
  * 创建坐标轴对象(用于辅助创建3D场景)
  * */
  // AxesHelper() 的参数代表坐标轴的线段长度
  // 红色代表x轴,绿色代表y轴,蓝色代表z轴
  const axesHelper = new THREE.AxesHelper(5);
  scene.add(axesHelper);


  /*
  * 创建轨道控制器
  * */
  const orbitControls = new OrbitControls(camera, renderer.domElement);
  // 更新控制器
  orbitControls.update();
  orbitControls.addEventListener('change', function () {
    // 输出相机位置
    //console.log('camera.position', camera.position);
  });


  /*
    * 创建一个线框球体
    * */
  // 新建球体
  const geometry = new THREE.SphereGeometry( 1, 16, 16 );

  // 创建材质
  // MeshBasicMaterial材质不受光照影响
  const material = new THREE.MeshBasicMaterial({
    // 材质颜色
    color: '#2ccdf1',
    // 将几何体渲染为线框。默认值为false(即渲染为平面多边形)
    wireframe: true,
    // 控制线框宽度(chrome上不好使)
    wireframeLinewidth: 5,
    // 定义线连接节点的样式。可选值为 'round', 'bevel' 和 'miter'。默认值为 'round'
    wireframeLinejoin: 'round',
  });

  // 新建网格(网格包含集合体和作用在几何体上面的材质)
  const cube = new THREE.Mesh(geometry, material);
  // 将网格添加到场景
  scene.add(cube);



  /*
  * 渲染场景必加代码 (渲染循环)
  * */
  // 渲染循环
  function animate() {
    // 每秒执行60次
    requestAnimationFrame(animate);

    // 更新控制器
    orbitControls.update();
    // 渲染场景
    renderer.render(scene, camera);
  }

  // WebGL兼容性检查
  if (WebGL.isWebGLAvailable()) {
    animate();
  } else {
    const warning = WebGL.getWebGLErrorMessage();
    container.value.appendChild(warning);
  }

  /**
   * 窗口变化自适应(必加代码)
   */
  const onWindowResize = () => {
    // 获取容器的实际宽高
    const containerWidth = container.value.clientWidth;
    const containerHeight = container.value.clientHeight;
    // 重置渲染器输出画布canvas尺寸
    renderer.setSize(containerWidth, containerHeight);
    // aspect属性 是摄像机视锥体的长宽比,通常设置为,画布的宽/画布的高
    // 全屏情况下:设置 观察范围长宽比aspect,为窗口宽高比
    camera.aspect =containerWidth / containerHeight;
    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
    // 因此如果相机的属性发生了变化,需要执行updateProjectionMatrix ()方法来使得这些属性生效
    camera.updateProjectionMatrix();
  }
  // 监听浏览器窗口大小改变
  window.addEventListener('resize', onWindowResize);

})
</script>
<style>

</style>
<style scoped>
.container {
  height: 100vh;
  box-sizing: border-box;
  /* overflow属性(必填),否则页面自适应时,偶尔会出现滚动条*/
  overflow: hidden;
}
</style>

*案例44 用深度网格材质创建一个立方体

<template>
  <div ref="container" className="container"></div>
</template>

<script setup>
import * as THREE from 'three';
import WebGL from 'three/examples/jsm/capabilities/WebGL.js'
// 引入轨道控制器扩展库OrbitControls.js
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
import {TransformControls} from 'three/examples/jsm/controls/TransformControls.js'
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import {ref, onMounted} from 'vue'

let container = ref(null)

onMounted(() => {
  /*
    * * 创建场景(渲染必加代码)
    */
  // 获取容器的实际宽高
  const containerWidth = container.value.clientWidth;
  const containerHeight = container.value.clientHeight;
  // 创建场景
  const scene = new THREE.Scene();


  /*
  * * 创建摄像机(渲染必加代码)
  * */
  // 创建摄像机(three.js有好几种摄像机,这里用的是透视摄像机)
  // 参数 1:fov视野角度(注意:这个参数如果调整不好,会导致物体的透视效果看起来怪怪的,一般为30)
  //      控制相机能看到的角度范围。
  //      就像你眼睛睁得越大,看到的范围就越广;睁得越小,看到的范围就越窄
  // 参数 2:aspect长宽比,控制相机看到的画面的宽高比。
  //      就像你调整手机屏幕的横屏或竖屏模式,画面的宽高比会变化
  // 参数 3:near近截面,控制相机能看到的最小距离,默认值是0.1
  //      1 表示距离相机 1 个单位以内的物体不会被渲染
  // 参数 4:far远截面,控制相机能看到的最大距离
  //      1000 表示距离相机 1000 个单位以外的物体不会被渲染
  const camera = new THREE.PerspectiveCamera(75, containerWidth / containerHeight, 0.1, 1000);
  // camera.position 和 camera.lookAt 如果不设置可能会导致画面看不到效果
  // 摄像机的位置
  camera.position.set(2.35, 2.35, 2.35);
  // 摄像机聚焦的位置
  camera.lookAt(0, 0, 0);
  // zoom属性可以获取或者设置摄像机的缩放倍数,其默认值为1
  camera.zoom = 1
  // 【注意,在大多数属性发生改变之后,需要调用.updateProjectionMatrix来使得这些改变生效】
  camera.updateProjectionMatrix()


  /*
  * * 创建渲染器(渲染必加代码)
  * */
  // 创建渲染器(three.js有好几种渲染器)
  const renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  // 第三个参数(选填):false代表以较低分辨率渲染
  renderer.setSize(containerWidth, containerHeight );
  // 将渲染器放入文档中
  container.value.appendChild(renderer.domElement);


  /*
  * 创建坐标轴对象(用于辅助创建3D场景)
  * */
  // AxesHelper() 的参数代表坐标轴的线段长度
  // 红色代表x轴,绿色代表y轴,蓝色代表z轴
  const axesHelper = new THREE.AxesHelper(5);
  scene.add(axesHelper);


  /*
  * 创建轨道控制器
  * */
  const orbitControls = new OrbitControls(camera, renderer.domElement);
  // 更新控制器
  orbitControls.update();
  orbitControls.addEventListener('change', function () {
    // 输出相机位置
    console.log('camera.position', camera.position);
  });


  /*
  * 用深度网格材质创建一个立方体
  * MeshDepthMaterial 是一种基于深度的材质。
  * (这种材质不常用)
  *
  * 它会根据物体与相机的距离,将物体渲染为灰度颜色:
  *     距离相机近的物体显示为白色。
  *     距离相机远的物体显示为黑色。
  *     中间的物体显示为灰色。
  *
  * MeshDepthMaterial 的特点:
  *     灰度显示:根据深度渲染为黑白灰颜色。
  *     无光照:不受场景中灯光的影响。
  *     简单高效:适合用于深度相关的效果。
  * */
  // 创建 深度网格材质 MeshDepthMaterial
  const depthMaterial = new THREE.MeshDepthMaterial();

  // 创建几何体
  const geometry = new THREE.BoxGeometry(0.5,0.5,0.5);
  // 创建网格对象
  const cube1 = new THREE.Mesh(geometry, depthMaterial);
  cube1.position.set(2, 2, 2);
  scene.add(cube1);




  /*
  * 渲染场景必加代码 (渲染循环)
  * */
  // 渲染循环
  function animate() {
    // 每秒执行60次
    requestAnimationFrame(animate);

    // 旋转立方体动画
    cube1.rotation.x += 0.01;
    cube1.rotation.y += 0.01;

    // 更新控制器
    orbitControls.update();
    // 渲染场景
    renderer.render(scene, camera);
  }

  // WebGL兼容性检查
  if (WebGL.isWebGLAvailable()) {
    animate();
  } else {
    const warning = WebGL.getWebGLErrorMessage();
    container.value.appendChild(warning);
  }

  /**
   * 窗口变化自适应(必加代码)
   */
  const onWindowResize = () => {
    // 获取容器的实际宽高
    const containerWidth = container.value.clientWidth;
    const containerHeight = container.value.clientHeight;
    // 重置渲染器输出画布canvas尺寸
    renderer.setSize(containerWidth, containerHeight);
    // aspect属性 是摄像机视锥体的长宽比,通常设置为,画布的宽/画布的高
    // 全屏情况下:设置 观察范围长宽比aspect,为窗口宽高比
    camera.aspect =containerWidth / containerHeight;
    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
    // 因此如果相机的属性发生了变化,需要执行updateProjectionMatrix ()方法来使得这些属性生效
    camera.updateProjectionMatrix();
  }
  // 监听浏览器窗口大小改变
  window.addEventListener('resize', onWindowResize);

})
</script>
<style>

</style>
<style scoped>
.container {
  height: 100vh;
  box-sizing: border-box;
  /* overflow属性(必填),否则页面自适应时,偶尔会出现滚动条*/
  overflow: hidden;
}
</style>

*案例45 创建一个 标准网格材质(MeshStandardMaterial)的透明立方体

<template>
  <div ref="container" className="container"></div>
</template>

<script setup>
import * as THREE from 'three';
import WebGL from 'three/examples/jsm/capabilities/WebGL.js'
// 引入轨道控制器扩展库OrbitControls.js
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
import {TransformControls} from 'three/examples/jsm/controls/TransformControls.js'
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import {ref, onMounted} from 'vue'

let container = ref(null)

onMounted(() => {
  /*
    * * 创建场景(渲染必加代码)
    */
  // 获取容器的实际宽高
  const containerWidth = container.value.clientWidth;
  const containerHeight = container.value.clientHeight;
  // 创建场景
  const scene = new THREE.Scene();


  /*
  * * 创建摄像机(渲染必加代码)
  * */
  // 创建摄像机(three.js有好几种摄像机,这里用的是透视摄像机)
  // 参数 1:fov视野角度(注意:这个参数如果调整不好,会导致物体的透视效果看起来怪怪的,一般为30)
  //      控制相机能看到的角度范围。
  //      就像你眼睛睁得越大,看到的范围就越广;睁得越小,看到的范围就越窄
  // 参数 2:aspect长宽比,控制相机看到的画面的宽高比。
  //      就像你调整手机屏幕的横屏或竖屏模式,画面的宽高比会变化
  // 参数 3:near近截面,控制相机能看到的最小距离,默认值是0.1
  //      1 表示距离相机 1 个单位以内的物体不会被渲染
  // 参数 4:far远截面,控制相机能看到的最大距离
  //      1000 表示距离相机 1000 个单位以外的物体不会被渲染
  const camera = new THREE.PerspectiveCamera(30, containerWidth / containerHeight, 0.1, 1000);
  // camera.position 和 camera.lookAt 如果不设置可能会导致画面看不到效果
  // 摄像机的位置
  camera.position.set(3.9, 3.9, 3.9);
  // 摄像机聚焦的位置
  camera.lookAt(0, 0, 0);
  // zoom属性可以获取或者设置摄像机的缩放倍数,其默认值为1
  camera.zoom = 1
  // 【注意,在大多数属性发生改变之后,需要调用.updateProjectionMatrix来使得这些改变生效】
  camera.updateProjectionMatrix()


  /*
  * * 创建渲染器(渲染必加代码)
  * */
  // 创建渲染器(three.js有好几种渲染器)
  const renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  // 第三个参数(选填):false代表以较低分辨率渲染
  renderer.setSize(containerWidth, containerHeight );
  // 将渲染器放入文档中
  container.value.appendChild(renderer.domElement);


  /*
  * 创建轨道控制器
  * */
  const orbitControls = new OrbitControls(camera, renderer.domElement);
  // 更新控制器
  orbitControls.update();
  orbitControls.addEventListener('change', function () {
    // 输出相机位置
    console.log('camera.position', camera.position);
  });


  /*
 * 创建环境光
 * MeshLambertMaterial材质的物体,没有光源对象是看不清的,所以要创建环境光
 * */
  // 第一个参数:环境光颜色
  // 第二个参数:光照的强度,缺省值为 1
  const AmbientLight = new THREE.AmbientLight( '#fff',2 ); // soft white light
  scene.add( AmbientLight );


  /*
    * 创建一个 标准网格材质(MeshStandardMaterial)的透明立方体
    *
    * */
  // 新建立方体对象
  const geometry = new THREE.BoxGeometry(1,1,1);

  // 创建材质
  // MeshStandardMaterial是一种基于物理的标准材质
  const material = new THREE.MeshStandardMaterial({
    // 材质颜色
    color: '#2ccdf1',
    // 启用透明
    transparent: true,
    // 设置透明度
    opacity: 0.35,
    // 渲染正面和背面
    side: THREE.DoubleSide,
  });

  // 新建网格(网格包含集合体和作用在几何体上面的材质)
  const cube = new THREE.Mesh(geometry, material);
  // 将网格添加到场景
  scene.add(cube);


  /*
    * 创建平行光
    * 常常用平行光来模拟太阳光
    * */
  // 第一个参数:光的颜色
  // 第二个参数:光照强度
  const DirectionalLight = new THREE.DirectionalLight( '#ffffff',3 );
  scene.add( DirectionalLight );
  // 设置平行光位置
  DirectionalLight.position.set(1, 1.5, 0)
  /// 设置平行光的方向,让平行光照射球体
  // target属性用于设置平行光的目标位置
  //    平行光默认的目标位置为原点 (0,0,0)
  //    值可以是场景中的某个对象
  DirectionalLight.target = cube


  /*
  * 渲染场景必加代码 (渲染循环)
  * */
  // 渲染循环
  function animate() {
    // 每秒执行60次
    requestAnimationFrame(animate);

    // 更新控制器
    orbitControls.update();
    // 渲染场景
    renderer.render(scene, camera);
  }

  // WebGL兼容性检查
  if (WebGL.isWebGLAvailable()) {
    animate();
  } else {
    const warning = WebGL.getWebGLErrorMessage();
    container.value.appendChild(warning);
  }

  /**
   * 窗口变化自适应(必加代码)
   */
  const onWindowResize = () => {
    // 获取容器的实际宽高
    const containerWidth = container.value.clientWidth;
    const containerHeight = container.value.clientHeight;
    // 重置渲染器输出画布canvas尺寸
    renderer.setSize(containerWidth, containerHeight);
    // aspect属性 是摄像机视锥体的长宽比,通常设置为,画布的宽/画布的高
    // 全屏情况下:设置 观察范围长宽比aspect,为窗口宽高比
    camera.aspect =containerWidth / containerHeight;
    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
    // 因此如果相机的属性发生了变化,需要执行updateProjectionMatrix ()方法来使得这些属性生效
    camera.updateProjectionMatrix();
  }
  // 监听浏览器窗口大小改变
  window.addEventListener('resize', onWindowResize);

})
</script>
<style>

</style>
<style scoped>
.container {
  height: 100vh;
  box-sizing: border-box;
  /* overflow属性(必填),否则页面自适应时,偶尔会出现滚动条*/
  overflow: hidden;
}
</style>

*案例46 创建卡通风格材质的物体

<template>
  <div ref="container" className="container"></div>
</template>

<script setup>
import * as THREE from 'three';
import WebGL from 'three/examples/jsm/capabilities/WebGL.js'
// 引入轨道控制器扩展库OrbitControls.js
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
import {TransformControls} from 'three/examples/jsm/controls/TransformControls.js'
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import {ref, onMounted} from 'vue'

let container = ref(null)

onMounted(() => {
  /*
    * * 创建场景(渲染必加代码)
    */
  // 获取容器的实际宽高
  const containerWidth = container.value.clientWidth;
  const containerHeight = container.value.clientHeight;
  // 创建场景
  const scene = new THREE.Scene();


  /*
  * * 创建摄像机(渲染必加代码)
  * */
  // 创建摄像机(three.js有好几种摄像机,这里用的是透视摄像机)
  // 参数 1:fov视野角度(注意:这个参数如果调整不好,会导致物体的透视效果看起来怪怪的,一般为30)
  //      控制相机能看到的角度范围。
  //      就像你眼睛睁得越大,看到的范围就越广;睁得越小,看到的范围就越窄
  // 参数 2:aspect长宽比,控制相机看到的画面的宽高比。
  //      就像你调整手机屏幕的横屏或竖屏模式,画面的宽高比会变化
  // 参数 3:near近截面,控制相机能看到的最小距离,默认值是0.1
  //      1 表示距离相机 1 个单位以内的物体不会被渲染
  // 参数 4:far远截面,控制相机能看到的最大距离
  //      1000 表示距离相机 1000 个单位以外的物体不会被渲染
  const camera = new THREE.PerspectiveCamera(30, containerWidth / containerHeight, 0.1, 1000);
  // camera.position 和 camera.lookAt 如果不设置可能会导致画面看不到效果
  // 摄像机的位置
  camera.position.set(3.9, 3.9, 3.9);
  // 摄像机聚焦的位置
  camera.lookAt(0, 0, 0);
  // zoom属性可以获取或者设置摄像机的缩放倍数,其默认值为1
  camera.zoom = 1
  // 【注意,在大多数属性发生改变之后,需要调用.updateProjectionMatrix来使得这些改变生效】
  camera.updateProjectionMatrix()


  /*
  * * 创建渲染器(渲染必加代码)
  * */
  // 创建渲染器(three.js有好几种渲染器)
  const renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  // 第三个参数(选填):false代表以较低分辨率渲染
  renderer.setSize(containerWidth, containerHeight );
  // 将渲染器放入文档中
  container.value.appendChild(renderer.domElement);


  /*
  * 创建轨道控制器
  * */
  const orbitControls = new OrbitControls(camera, renderer.domElement);
  // 更新控制器
  orbitControls.update();
  orbitControls.addEventListener('change', function () {
    // 输出相机位置
    console.log('camera.position', camera.position);
  });


  /*
  * 创建坐标轴对象(用于辅助创建3D场景)
  * */
  // AxesHelper() 的参数代表坐标轴的线段长度
  // 红色代表x轴,绿色代表y轴,蓝色代表z轴
  const axesHelper = new THREE.AxesHelper(5);
  scene.add(axesHelper);


  /*
 * 创建环境光
 * MeshLambertMaterial材质的物体,没有光源对象是看不清的,所以要创建环境光
 * */
  // 第一个参数:环境光颜色
  // 第二个参数:光照的强度,缺省值为 1
  const AmbientLight = new THREE.AmbientLight( '#fff',1 ); // soft white light
  scene.add( AmbientLight );


  /*
  * * 创建卡通风格材质的物体
  *
  * MeshToonMaterial 是一种特殊的材质,它可以让 3D 物体看起来像卡通风格的画面
  * MeshToonMaterial 是一种基于光照的材质,但它不像普通材质那样平滑过渡,而是将颜色分成几个明显的色块。
  * 这种效果类似于卡通画中的阴影和高光,给人一种手绘的感觉。
  * 在制作卡通风格的游戏或动画时需要用这种材质
  *
  * MeshToonMaterial 的特点:
  *     色块化阴影:将阴影和高光分成明显的色块,而不是平滑过渡。
  *     支持光照:可以根据场景中的灯光调整颜色。
  *     简单易用:只需设置颜色和渐变贴图,就能实现卡通效果。
  * */
  // 创建 MeshToonMaterial 材质
  const material = new THREE.MeshToonMaterial({
    color: '#317fd7', // 设置颜色为绿色
    gradientMap: null, // 渐变贴图(可选)
  });

  // 创建一个立方体和一个球体
  const sphereGeometry = new THREE.SphereGeometry( 0.5, 32, 16 );
  const geometry = new THREE.BoxGeometry(0.8,0.8,0.8);
  // 创建球体网格
  const sphere = new THREE.Mesh( sphereGeometry, material );
  sphere.position.set(1.3,0,0)
  scene.add( sphere );
  // 创建立方体网格
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);


  /*
    * 创建平行光
    * 常常用平行光来模拟太阳光
    * */
  // 第一个参数:光的颜色
  // 第二个参数:光照强度
  const DirectionalLight = new THREE.DirectionalLight( '#ffffff',4 );
  scene.add( DirectionalLight );
  // 设置平行光位置
  // .normalize()确保方向向量长度为1,使光照和阴影计算符合物理规律,避免因向量长度导致的意外结果
  DirectionalLight.position.set(2, 2, 0).normalize()
  /// 设置平行光的方向,让平行光照射球体
  // target属性用于设置平行光的目标位置
  //    平行光默认的目标位置为原点 (0,0,0)
  //    值可以是场景中的某个对象
  DirectionalLight.target = cube


  /*
  * 渲染场景必加代码 (渲染循环)
  * */
  // 渲染循环
  function animate() {
    // 每秒执行60次
    requestAnimationFrame(animate);

    // 更新控制器
    orbitControls.update();
    // 渲染场景
    renderer.render(scene, camera);
  }

  // WebGL兼容性检查
  if (WebGL.isWebGLAvailable()) {
    animate();
  } else {
    const warning = WebGL.getWebGLErrorMessage();
    container.value.appendChild(warning);
  }

  /**
   * 窗口变化自适应(必加代码)
   */
  const onWindowResize = () => {
    // 获取容器的实际宽高
    const containerWidth = container.value.clientWidth;
    const containerHeight = container.value.clientHeight;
    // 重置渲染器输出画布canvas尺寸
    renderer.setSize(containerWidth, containerHeight);
    // aspect属性 是摄像机视锥体的长宽比,通常设置为,画布的宽/画布的高
    // 全屏情况下:设置 观察范围长宽比aspect,为窗口宽高比
    camera.aspect =containerWidth / containerHeight;
    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
    // 因此如果相机的属性发生了变化,需要执行updateProjectionMatrix ()方法来使得这些属性生效
    camera.updateProjectionMatrix();
  }
  // 监听浏览器窗口大小改变
  window.addEventListener('resize', onWindowResize);

})
</script>
<style>

</style>
<style scoped>
.container {
  height: 100vh;
  box-sizing: border-box;
  /* overflow属性(必填),否则页面自适应时,偶尔会出现滚动条*/
  overflow: hidden;
}
</style>

相关文章:

  • linux+KMS+AD域自动激活
  • docker安装ros2 并在windows中显示docker内ubuntu系统窗口并且vscode编程
  • 获取每月最后一个工作日:考虑法定节假日与调休
  • IDEA中查询Maven项目的依赖树
  • 鸿蒙初学者学习手册(HarmonyOSNext_API14)_自定义动画API(@ohos.animator (动画) )
  • RabbitMQ的脑裂(网络分区)问题
  • 推荐一款AI大模型托管平台-OpenWebUI
  • Jenkins 部署在 Mac 并在局域网内通过 ip 访问
  • 【Spring AI】简单使用示例说明
  • SAP 代码扫描工具
  • selenium爬取苏宁易购平台某产品的评论
  • 架构学习第七周--Prometheus
  • Vue 3 中如何注册全局自定义组件:一个 SVG 图标的例子
  • Debezium连接器对比
  • Unity shader glsl着色器特效之 模拟海面海浪效果
  • Python 函数(传递实参)
  • 【工具】飞书个人知识库搭建(附详细步骤)
  • 【Linux探索学习】第二十八弹——信号(下):信号在内核中的处理及信号捕捉详解
  • 理解都远正态分布中指数项的精度矩阵(协方差逆矩阵)
  • Python 3 安装与环境配置完整教程
  • 网站访客qq统计 原理/短视频营销策略
  • 营销网站建设/山西太原百度公司
  • 江苏首天建设集团网站/百度移动应用
  • Django可以做门户网站吗/绍兴seo排名收费
  • 怎么用网站做文案/自己搭建网站需要什么
  • 做旅游网站需要的背景/推广赚钱