threejs-效果合成器(EffectComposer)


前言

threejs中的效果合成器 EffectComposer 可以在场景渲染完毕后再增加一些特效,如:让场景再某些情况下变得更加模糊或者更加鲜艳,增加滤镜或者闪烁效果,使用扫描线添加老旧电视屏幕上的效果等等。本文介绍 EffectComposer的基本使用,并使用 OutlinePass 这个通道为地球添加闪烁效果


EffectComposer 使用流程

场景初始化:自转的地球

在正式使用效果合成器前,首先创建一个基本场景作为对比,在场景中通过贴图添加一个旋转的地球

在这里插入图片描述

import { useRef, useEffect, useCallback, useState } from 'react'
import * as THREE from 'three'
import OrbitControls from 'three-orbitcontrols';
import Earth from '../../assets/textures/earth/Earth.png'
import EarthNormal from '../../assets/textures/earth/EarthNormal.png'
import EarthSpec from '../../assets/textures/earth/EarthSpec.png'
import './index.scss'

const View = () => {
  const page = useRef(); // useRef不会导致重新渲染

  /**
   * 场景、相机、渲染器作为threejs的基本结构,需要在页面进入时渲染完毕
   */
  const scene = useRef(new THREE.Scene()).current; //场景
  const camera = useRef(new THREE.PerspectiveCamera()).current; //摄像机(透视投影)
  const render = useRef(new THREE.WebGLRenderer()).current; //渲染器
  const controls = new OrbitControls(camera, render.domElement);//创建控件对象
  const timer = useRef(null) // 定义定时器

  const earthRef = useRef()

  useEffect(() => {
    page.current.appendChild(render.domElement);
    init();
    initLight();
    addEarth();
    renderScene();
  }, [])

  // 初始化场景
  const init = useCallback(() => {
    render.setSize(page.current.offsetWidth, page.current.offsetHeight); // 渲染器设置尺寸
    // 设置背景颜色
    render.setClearColor(new THREE.Color(0x000000)); // 设置背景颜色和透明度
    render.shadowMap.enabled = true; // 渲染器允许渲染阴影⭐

    /**
     * 设置摄像机的属性
     */
    camera.aspect = (page.current.offsetWidth / page.current.offsetHeight) // 摄像机设置屏幕宽高比
    camera.fov = 45; // 摄像机的视角
    camera.near = 0.01; // 近面距离
    camera.far = 1001; // 远面距离
    camera.position.set(30, 40, 30) // 设置摄像机在threejs坐标系中的位置
    camera.lookAt(0, 0, 0) // 摄像机的指向
    camera.updateProjectionMatrix(); // 更新摄像机投影矩阵,在任何参数被改变以后必须被调用
  }, [render, scene])

  // 初始化环境光
  const initLight = () => {
    const ambientLight = new THREE.AmbientLight(0x343434) // 基本光源

    const spotLight = new THREE.SpotLight(0xFFFFFF); // 聚光灯
    spotLight.position.set(-10, 30, 40);
    spotLight.castShadow = true; // 只有该属性为true时,该点光源允许产生阴影,并且下列属性可用
    spotLight.shadow.mapSize.width = 2048;
    spotLight.shadow.mapSize.height = 2048;
    spotLight.shadow.camera.fov = 15;
    spotLight.castShadow = true;
    spotLight.decay = 2;
    spotLight.penumbra = 0.05;

    scene.add(ambientLight, spotLight); // 向场景中添加光源
  }

  // 添加地球
  function addEarth() {
    const textureLoader = new THREE.TextureLoader();
    const planetMaterial = new THREE.MeshPhongMaterial({
      map: textureLoader.load(Earth),
      normalMap: textureLoader.load(EarthNormal),
      specularMap: textureLoader.load(EarthSpec),
      specular: new THREE.Color(0x4444aa),
      normalScale: new THREE.Vector2(6, 6),
      shininess: 0.5
    });

    earthRef.current = new THREE.Mesh(new THREE.SphereGeometry(15, 40, 40), planetMaterial);
    scene.add(earthRef.current);
  }

  // 渲染器执行渲染
  const renderScene = useCallback(() => {
    console.log('renderScene')
    timer.current = window.requestAnimationFrame(() => renderScene())
    controls.update();
    earthRef.current.rotation.y += 0.001; 
    render.render(scene, camera);
  }, [render])

  return (

    <div className='page' ref={page} />

  )
};

export default View

创建THREE.EffectComposer

首先要创建一个 THREE.EffectComposer 对象,传入的参数是WebGLRenderer:

EffectComposer( renderer : WebGLRenderer, renderTarget : WebGLRenderTarget )

  • renderer – 用于渲染场景的渲染器。
  • renderTarget – (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。
  const renderer = new THREE.WebGLRenderer();
  const composer = new THREE.EffectComposer(renderer);

添加后期处理通道并更新渲染

  • RenderPass: 渲染场景,但是不会添加至屏幕上
  • FilmPass:添加扫描线。可以设置添加到屏幕
  • addPass():将通道添加至组合器中
  const renderPass = new THREE.RenderPass(scene, camera);
  const effectFilm = new THREE.FilmPass(0.8, 0.325, 256, false);
  effectFilm.renderToScreen = true;

  const composer = new THREE.EffectComposer(renderer);
  
  composer.addPass(renderPass);
  composer.addPass(effectFilm);

在场景进行render时,使用 composer 而不是 renderer 进行渲染:

  const renderScene = useCallback(() => {
    console.log('renderScene')
    const delta = clock.current.getDelta();
    window.requestAnimationFrame(() => renderScene())
    controls.update();
    earthRef.current.rotation.y += 0.001; 
    // render.render(scene,camera);
    composer.current.render(delta);
  }, [render])

EffectComposer 使用示例

示例一:FilmPass 添加电视效果

在这里插入图片描述

修改后代码如下👇

import { useRef, useEffect, useCallback, useState } from 'react'
import * as THREE from 'three'
import OrbitControls from 'three-orbitcontrols';
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";

//后处理通道包
import {RenderPass} from "three/examples/jsm/postprocessing/RenderPass.js";
import {FilmPass} from "three/examples/jsm/postprocessing/FilmPass.js";

import Earth from '../../assets/textures/earth/Earth.png'
import EarthNormal from '../../assets/textures/earth/EarthNormal.png'
import EarthSpec from '../../assets/textures/earth/EarthSpec.png'
import './index.scss'

const View = () => {
  const page = useRef(); // useRef不会导致重新渲染

  /**
   * 场景、相机、渲染器作为threejs的基本结构,需要在页面进入时渲染完毕
   */
  const scene = useRef(new THREE.Scene()).current; //场景
  const camera = useRef(new THREE.PerspectiveCamera()).current; //摄像机(透视投影)
  const render = useRef(new THREE.WebGLRenderer()).current; //渲染器
  const composer = useRef(); //渲染器
  const controls = new OrbitControls(camera, render.domElement);//创建控件对象
  const clock = useRef(new THREE.Clock());

  const earthRef = useRef()

  useEffect(() => {
    page.current.appendChild(render.domElement);
    init();
    initLight();
    addEarth();
    renderScene();
  }, [])

  // 初始化场景
  const init = useCallback(() => {
    render.setSize(page.current.offsetWidth, page.current.offsetHeight); // 渲染器设置尺寸
    // 设置背景颜色
    render.shadowMap.enabled = true;
    render.shadowMapSoft = true;
    render.shadowMap.type = THREE.PCFSoftShadowMap;

    render.setClearColor(new THREE.Color(0x000000)); // 设置背景颜色和透明度
    render.shadowMap.enabled = true; // 渲染器允许渲染阴影⭐
    
    // 配置通道
    const renderPass = new RenderPass(scene, camera);
    const effectFilm = new FilmPass(0.8, 0.325, 256, false);
    effectFilm.renderToScreen = true;
    
    composer.current = new EffectComposer(render);
    composer.current.addPass(renderPass);
    composer.current.addPass(effectFilm);

    /**
     * 设置摄像机的属性
     */
    camera.aspect = (page.current.offsetWidth / page.current.offsetHeight) // 摄像机设置屏幕宽高比
    camera.fov = 45; // 摄像机的视角
    camera.near = 0.1; // 近面距离
    camera.far = 1001; // 远面距离
    camera.position.set(-30, 40, 30) // 设置摄像机在threejs坐标系中的位置
    camera.lookAt(0, 0, 0) // 摄像机的指向
    camera.updateProjectionMatrix(); // 更新摄像机投影矩阵,在任何参数被改变以后必须被调用
  }, [render, scene])

  // 初始化环境光
  const initLight = () => {
    const ambientLight = new THREE.AmbientLight(0x343434) // 基本光源

    const spotLight = new THREE.SpotLight(0xFFFFFF); // 聚光灯
    spotLight.position.set(-10, 30, 40);
    spotLight.castShadow = true; // 只有该属性为true时,该点光源允许产生阴影,并且下列属性可用
    spotLight.shadow.mapSize.width = 2048;
    spotLight.shadow.mapSize.height = 2048;
    spotLight.shadow.camera.fov = 15;
    spotLight.castShadow = true;
    spotLight.decay = 2;
    spotLight.penumbra = 0.05;

    scene.add(ambientLight, spotLight); // 向场景中添加光源
  }

  // 添加地球
  function addEarth() {
    const textureLoader = new THREE.TextureLoader();
    const planetMaterial = new THREE.MeshPhongMaterial({
      map: textureLoader.load(Earth),
      normalMap: textureLoader.load(EarthNormal),
      specularMap: textureLoader.load(EarthSpec),
      specular: new THREE.Color(0x4444aa),
      normalScale: new THREE.Vector2(6, 6),
      shininess: 0.5
    });

    earthRef.current = new THREE.Mesh(new THREE.SphereGeometry(15, 40, 40), planetMaterial);
    scene.add(earthRef.current);
  }


  // 渲染器执行渲染
  const renderScene = useCallback(() => {
    console.log('renderScene')
    const delta = clock.current.getDelta();
    window.requestAnimationFrame(() => renderScene())
    controls.update();
    earthRef.current.rotation.y += 0.001; 
    // render.render(scene,camera);
    composer.current.render(delta);
  }, [render])

  return (

    <div className='page' ref={page} />

  )
};

export default View



示例二:OutlinePass 添加闪烁效果

在这里插入图片描述

import { useRef, useEffect, useCallback, useState } from 'react'
import * as THREE from 'three'
import OrbitControls from 'three-orbitcontrols';
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";

//后处理通道包
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";

import Earth from '../../assets/textures/earth/Earth.png'
import EarthNormal from '../../assets/textures/earth/EarthNormal.png'
import EarthSpec from '../../assets/textures/earth/EarthSpec.png'
import './index.scss'

const View = () => {
  const page = useRef(); // useRef不会导致重新渲染

  /**
   * 场景、相机、渲染器作为threejs的基本结构,需要在页面进入时渲染完毕
   */
  const scene = useRef(new THREE.Scene()).current; //场景
  const camera = useRef(new THREE.PerspectiveCamera()).current; //摄像机(透视投影)
  const render = useRef(new THREE.WebGLRenderer()).current; //渲染器
  const composer = useRef(); //渲染器
  const controls = new OrbitControls(camera, render.domElement);//创建控件对象
  const clock = useRef(new THREE.Clock());

  const earthRef = useRef()

  useEffect(() => {
    page.current.appendChild(render.domElement);
    addEarth();
    init();
    initLight();
    renderScene();
  }, [])

  // 初始化场景
  const init = useCallback(() => {
    render.setSize(page.current.offsetWidth, page.current.offsetHeight); // 渲染器设置尺寸
    // 设置背景颜色
    render.shadowMap.enabled = true;
    render.shadowMapSoft = true;
    render.shadowMap.type = THREE.PCFSoftShadowMap;

    render.setClearColor(new THREE.Color(0x000000)); // 设置背景颜色和透明度
    render.shadowMap.enabled = true; // 渲染器允许渲染阴影⭐


    // OutLine
    const outlinePass = new OutlinePass(
      new THREE.Vector2(window.innerWidth, window.innerHeight),
      scene,
      camera,
      [earthRef.current]);
    const renderPass = new RenderPass(scene, camera);


    outlinePass.edgeStrength = 2; // 边缘强度
    outlinePass.edgeGlow = 2; // 光晕强度
    outlinePass.edgeThickness = 3; // 光晕尺寸
    outlinePass.pulsePeriod = 1;// 闪烁频率
    outlinePass.visibleEdgeColor.set('red'); // 光晕颜色

    composer.current = new EffectComposer(render);
    composer.current.addPass(renderPass);
    composer.current.addPass(outlinePass);


    /**
     * 设置摄像机的属性
     */
    camera.aspect = (page.current.offsetWidth / page.current.offsetHeight) // 摄像机设置屏幕宽高比
    camera.fov = 45; // 摄像机的视角
    camera.near = 0.1; // 近面距离
    camera.far = 1001; // 远面距离
    camera.position.set(-30, 40, 30) // 设置摄像机在threejs坐标系中的位置
    camera.lookAt(0, 0, 0) // 摄像机的指向
    camera.updateProjectionMatrix(); // 更新摄像机投影矩阵,在任何参数被改变以后必须被调用
  }, [render, scene])

  // 初始化环境光
  const initLight = () => {
    const ambientLight = new THREE.AmbientLight(0x343434) // 基本光源

    const spotLight = new THREE.SpotLight(0xFFFFFF); // 聚光灯
    spotLight.position.set(-10, 30, 40);
    spotLight.castShadow = true; // 只有该属性为true时,该点光源允许产生阴影,并且下列属性可用
    spotLight.shadow.mapSize.width = 2048;
    spotLight.shadow.mapSize.height = 2048;
    spotLight.shadow.camera.fov = 15;
    spotLight.castShadow = true;
    spotLight.decay = 2;
    spotLight.penumbra = 0.05;

    scene.add(ambientLight, spotLight); // 向场景中添加光源
  }

  // 添加地球
  function addEarth() {
    const textureLoader = new THREE.TextureLoader();
    const planetMaterial = new THREE.MeshPhongMaterial({
      map: textureLoader.load(Earth),
      normalMap: textureLoader.load(EarthNormal),
      specularMap: textureLoader.load(EarthSpec),
      specular: new THREE.Color(0x4444aa),
      normalScale: new THREE.Vector2(6, 6),
      shininess: 0.5
    });

    earthRef.current = new THREE.Mesh(new THREE.SphereGeometry(15, 40, 40), planetMaterial);
    scene.add(earthRef.current);



  // 渲染器执行渲染
  const renderScene = useCallback(() => {
    console.log('renderScene')
    const delta = clock.current.getDelta();
    window.requestAnimationFrame(() => renderScene())
    controls.update();
    earthRef.current.rotation.y += 0.001;
    render.autoClear = false;
    render.clear();
    // render.render(scene,camera);
    composer.current.render(delta);
  }, [render])

  return (

    <div className='page' ref={page} />

  )
};

export default View



总结

EffectComposer 使用流程

  • 场景初始化:自转的地球
  • 创建THREE.EffectComposer
  • 添加后期处理通道并更新渲染

EffectComposer 使用示例

  • 示例一:FilmPass 添加电视效果
  • 示例二:OutlinePass 添加闪烁效果
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 小程序 threejs-miniprogram 可以通过改变物体的位置实现平移操作。 在 threejs-miniprogram 中,可以使用 Vector3 对象来表示物体的位置,Vector3 是三维空间中的一个点,可以包含 x、y、z 三个坐标。通过改变 Vector3 对象的坐标值,即可实现物体的平移。 具体实现步骤如下: 1. 首先,通过创建一个 Vector3 对象表示需要平移的物体的当前位置。例如,可以使用如下代码创建一个初始位置为 (0, 0, 0) 的 Vector3 对象: ```javascript var position = new THREE.Vector3(0, 0, 0); ``` 2. 接下来,根据需求确定平移的距离和方向,并将其添加到 Vector3 对象的坐标值上。例如,如果需要在 x 方向上平移 10 个单位,可以使用如下代码: ```javascript position.x += 10; ``` 可以根据需要在其他坐标轴上进行相应的平移操作。 3. 最后,将改变后的 Vector3 对象赋值给物体的位置属性,即可实现物体的平移。例如,可以使用如下代码将改变后的位置赋值给物体的 position 属性: ```javascript object.position.copy(position); ``` 其中,object 为需要平移的物体对象。 通过以上步骤可以实现小程序 threejs-miniprogram 中物体的平移操作。可以根据具体需求修改平移的距离和方向,从而实现不同的平移效果。 ### 回答2: threejs-miniprogram 是一款基于小程序的三维渲染库,能够在小程序中实现三维模型的展示和交互。要实现平移功能,可以按照以下步骤进行操作。 首先,在合适的位置引入 threejs-miniprogram 库,并创建一个 canvas 组件,作为渲染的画布。 然后,在小程序中定义一个相机、一个场景和一个渲染器。相机用于控制视角,场景用于存放物体,渲染器用于将场景中的物体渲染到画布上。 接下来,创建一个物体,可以是一个几何体或者一个模型。将该物体添加到场景中。 在实现平移功能时,可以通过监听鼠标或触摸事件,获取用户的输入信息。根据用户的操作,改变物体在场景中的位置。 例如,可以通过监测鼠标移动事件,获取鼠标的位置差异,并将物体的位置与鼠标位置差异相加,从而实现物体的平移效果。需要注意的是,物体的位置变化需要实时更新,并且平移的距离应与屏幕上的实际距离有一个合适的映射关系,以确保平移的实际效果符合用户的期望。 最后,更新场景中的物体位置,并将场景渲染到画布上,以展示平移后的效果。 通过以上步骤,就可以在小程序中使用 threejs-miniprogram 实现平移功能。需要根据实际需求,调整代码中的参数和细节,以适应具体的项目。 ### 回答3: 在使用threejs-miniprogram进行小程序开发时,我们可以通过平移操作来改变物体的位置。平移操作可以让物体在三维空间中沿着指定的方向移动一定的距离。 在threejs-miniprogram中,我们可以通过调整物体的位置属性来实现平移。首先,我们需要创建一个平移向量,它包含了物体在各个轴上的平移距离。然后,我们可以通过将这个平移向量与物体的位置属性相加,来实现平移操作。 举个例子,假设我们有一个立方体,它的初始位置是(0, 0, 0)。如果我们想将立方体沿着x轴方向平移3个单位,我们可以创建一个平移向量(3, 0, 0),然后将这个平移向量与立方体的位置属性相加,即可实现平移操作。 具体的代码如下所示: ```javascript var cube = new THREE.Mesh(geometry, material); // 创建立方体 var translateVector = new THREE.Vector3(3, 0, 0); // 创建平移向量 cube.position.add(translateVector); // 平移操作,将平移向量与立方体的位置属性相加 ``` 这样,立方体就会沿着x轴方向平移3个单位。 需要注意的是,在进行平移操作时,我们需要将平移向量与物体的位置属性相加,而不是简单地将平移向量赋值给物体的位置属性。这样才能在每次平移操作后保留之前的平移信息。 所以,在使用threejs-miniprogram平移物体时,我们只需要创建平移向量,并将其与物体的位置属性相加即可。这样就能实现物体的平移操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值