threejs-效果合成器(EffectComposer)

news2024/11/20 14:44:33

文章目录

  • 前言
  • EffectComposer 使用流程
    • 场景初始化:自转的地球
    • 创建THREE.EffectComposer
    • 添加后期处理通道并更新渲染
  • EffectComposer 使用示例
    • 示例一:FilmPass 添加电视效果
    • 示例二:OutlinePass 添加闪烁效果
  • 总结


前言

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 添加闪烁效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/428332.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python的基础

这是我自己学习Python的三个星期的小总结&#xff0c;内容包含了规范、数据类型、函数、类和捕捉异常&#xff0c;做了一个简单的梳理&#xff0c;希望可以帮助到和我一样开始学习Python的小伙伴&#xff0c;也希望多多支持&#xff0c;相互进步&#xff0c;下面步入正题。 基…

记一次 .NET某医疗器械清洗系统 卡死分析

一&#xff1a;背景 1. 讲故事 前段时间协助训练营里的一位朋友分析了一个程序卡死的问题&#xff0c;回过头来看这个案例比较经典&#xff0c;这篇稍微整理一下供后来者少踩坑吧。 二&#xff1a;WinDbg 分析 1. 为什么会卡死 因为是窗体程序&#xff0c;理所当然就是看主…

MySQL全局锁、表级锁、行级锁介绍演示(详细)

目录 介绍 分类 1、全局锁 1.1介绍 1.2场景 1.3语法 1.4演示 2、表级锁 2.1介绍 2.2分类 2.3语法 2.4演示 3、行级锁 3.1介绍 3.2分类 3.3场景 介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;…

linux下搭建Hbase分布式数据库

文章目录Hbase概念1.安装Hbase1.jdk的配置2.安装hbase2.启动和操作1.启动服务2 **web-ui访问地址:http://node01:16010/master-status**3.简单的操作1.连接 HBase2.帮助命令3.创建一张表 create a table4.使用查看表是否存在5.describe 查看表描述6.put命令插入数据到表7. scan…

jmeter插件的安装

前言 jmeter常用的插件有很多&#xff0c;本身安装的jmeter是没有安装插件的工具&#xff0c;需要下载一个jar包&#xff0c;通过插件安装工具去安装jmeter插件plugins-manager.jar这个jar包就是用来安装jmeter插件的jar把这个jar包下载后放到jmeter的lib/ext目录下重启jmeter…

C++语法(16)---- 多态

https://blog.csdn.net/m0_63488627/article/details/130106690?spm1001.2014.3001.5501https://blog.csdn.net/m0_63488627/article/details/130106690?spm1001.2014.3001.5501 目录 1. 多态的概念 2.多态的实现 1.虚函数 2.多态条件 得到的多态条件 特殊条件 3.虚函…

Socks5代理和IP代理

Socks5代理和IP代理是常用的网络代理服务&#xff0c;它们为用户提供了匿名访问和保护隐私的功能。在本文中&#xff0c;我们将介绍这两种代理的基本概念和工作原理&#xff0c;并展示如何编写一个简单的代理服务器。 一、什么是Socks5代理和IP代理&#xff1f; Socks5代理…

[操作系统安全]SetUID与Capability权能

问题一、解释“passwd”, “sudo” , “ping”等命令为什么需要 setuid位&#xff0c;去掉s位试运行&#xff0c;添加权能试运行。 1、为什么需要setuid位&#xff1a; 首先明确setuid的作用是&#xff1a;执行该设置后&#xff0c;文件执行时将以文件拥有者的身份执行&#xf…

C++【栈队列(3种)反向迭代器】

文章目录一、容器适配器二、栈&#xff08;一&#xff09;栈定义&#xff08;二&#xff09;栈使用接口&#xff08;三&#xff09;栈模拟实现(1) 栈模拟实现解析(2) 栈模拟实现代码(3) 栈模拟结果三、队列&#xff08;一&#xff09;普通队列&#xff08;1&#xff09;普通队列…

4、浅谈Makefile文件及其简单的使用知识

文章目录1、什么是Makefile&#xff1f;&#xff08;1&#xff09;makefile关系到了整个工程的编译规则。&#xff08;2&#xff09;makefile带来的好处就是——“自动化编译”&#xff08;3&#xff09;make是一个命令工具&#xff0c;是一个解释makefile中指令的命令工具2、为…

[FREERTOS]队列

1.什么是队列 队列也称消息队列&#xff0c;是一种常用于任务间通信的数据结构&#xff0c;队列可以在任务之间&#xff0c;中断和任务之间传递信息 2.传递信息为什么不用全局变量呢&#xff1f; 确实全局变量依然可以传递信息&#xff0c;但是如果全局变量改变的很频繁&#x…

网工必知—什么是堡垒机?-CCIE

什么是堡垒机&#xff1f; 网络工程师一定听过或用过所谓的“堡垒机”&#xff0c;那么堡垒机到底是什么呢&#xff1f; 堡垒机是一种跳板机制&#xff08;Jump Server&#xff09;&#xff0c;在一个特定的网络环境下&#xff0c;为了保障网络和数据不受来自外部和内部用户的…

flink 1.16 在centos安装 部署踩的坑

报错: 1 RESOURCES_DOWNLOAD_DIR : 这个错误是修改了 conf目录下 的 master 或 workers 等信息造成的. 2 修改了这个信息可能会造成输入密码的问题. 3 Could not connect to BlobServer at address localhost/127.0.0.1:39203 这个端口还会变化,这种问题可能是因为conf下的…

Python将Word文件中的内容写入Excel文件

在日常办公中我们经常需要将word文件中的数据写入Excel中&#xff0c;如果是手动一个一个进行复制粘贴&#xff0c;那将会非常的耗时且繁琐&#xff01; 遇到这种问题我们首先想到就是利用编程解决&#xff0c;今天我分享一个word转excel的小方法&#xff01; 首先我有一个wo…

常见漏洞扫描工具AWVS、AppScan、Nessus的使用

HVV笔记——常见漏洞扫描工具AWVS、AppScan、Nessus的使用1 AWVS1.1 安装部署1.2 激活1.3 登录1.4 扫描web应用程序1.4.1 需要账户密码登录的扫描1.4.2 利用录制登录序列脚本扫描1.4.3 利用定制cookie扫描1.5 扫描报告分析1.5.1 AWVS报告类型1.5.2 最常用的报告类型&#xff1a…

Microchip的10M以太网解决方案

&#xff08;以下所有图片均来源于Microchip官网&#xff09; 一 为什么需要10M车载以太网 目前车载百兆以太网&#xff08;100Base-T1&#xff09;和千兆以太网&#xff08;1000Base-T1&#xff09;技术较为成熟&#xff0c;但如果直接用100Base-T1/1000Base-T1来替代目前被广…

anaconda 创建虚拟环境 基本命令操作

下载好之后直接打开 anaconda prpmpt : 此时直接输入 &#xff1a;activate 不加环境名是直接进入到base环境中的 必须先进入到base环境中再使用后边的命令 &#xff1a; activate 直接进入base环境&#xff1a;如图&#xff1a;conda create -n 名字 python3.7 创建虚拟…

善用Embedding,我们来给文本分分类

你好&#xff0c;我是徐文浩。 上一讲里我们看到大模型的确有效。在进行情感分析的时候&#xff0c;我们通过OpenAI的API拿到的Embedding&#xff0c;比T5-base这样单机可以运行的小模型&#xff0c;效果还是好很多的。 不过&#xff0c;我们之前选用的问题的确有点太简单了。…

springboot服务端接口外网远程调试,并实现HTTP服务监听 - 内网穿透

文章目录前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统2.2 创建隧道映射本地端口2.3 测试公网地址3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址4. …

segment anything paper笔记

demo主页&#xff08;包含paper, demo, dataset&#xff09; 通过demo可以看到一个酷炫的效果&#xff0c;鼠标放在任何物体上都能实时分割出来。 segment anything宣传的是一个类似BERT的基础类模型&#xff0c;可以在下游任务中不需要再训练&#xff0c;直接用的效果。 而且…