Three.js-效果合成(EffectComposer)

目录

1. 效果合成器(EffectComposer)

1.1 构造函数

EffectComposer( renderer : WebGLRenderer, renderTarget : WebGLRenderTarget )

1.2 属性

.passes : Array

.readBuffer : WebGLRenderTarget

.renderer : WebGLRenderer

.renderToScreen : Boolean

.writeBuffer : WebGLRenderTarget

1.3 方法

2. 使用内置效果合成器

3. 使用shaderPass实现自定义合成效果


1. 效果合成器(EffectComposer)

用于在three.js中实现后期处理效果。该类管理了产生最终视觉效果的后期处理过程链。 后期处理过程根据它们添加/插入的顺序来执行,最后一个过程会被自动渲染到屏幕上。

例如淡入淡出效果crossfade:

小故障效果(glitch) :

虚幻光晕效果: 

除此之外,Three官方还提供许多已定义的后期效果,供用户使用,例如抗锯齿、上帝光线等。 

1.1 构造函数

EffectComposer( renderer : WebGLRenderer, renderTarget : WebGLRenderTarget )

renderer -- 用于渲染场景的渲染器。
renderTarget -- (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。

1.2 属性

.passes : Array

一个用于表示后期处理过程链(包含顺序)的数组。

.readBuffer : WebGLRenderTarget

内部读缓冲区的引用。过程一般从该缓冲区读取先前的渲染结果。

.renderer : WebGLRenderer

内部渲染器的引用。

.renderToScreen : Boolean

最终过程是否被渲染到屏幕(默认帧缓冲区)。

.writeBuffer : WebGLRenderTarget

内部写缓冲区的引用。过程常将它们的渲染结果写入该缓冲区。

1.3 方法

.addPass ( pass : Pass ) : undefined

pass -- 将被添加到过程链的过程

将传入的过程添加到过程链。

.insertPass ( pass : Pass, index : Integer ) : undefined

pass -- 将被插入到过程链的过程。
index -- 定义过程链中过程应插入的位置。

将传入的过程插入到过程链中所给定的索引处。

.isLastEnabledPass ( passIndex : Integer ) : Boolean

passIndex -- 被用于检查的过程

如果给定索引的过程在过程链中是最后一个启用的过程,则返回true。 由EffectComposer所使用,来决定哪一个过程应当被渲染到屏幕上。

.removePass ( pass : Pass ) : undefined

pass -- The pass to remove from the pass chain.

Removes the given pass from the pass chain.

.render ( deltaTime : Float ) : undefined

deltaTime -- The delta time value.

执行所有启用的后期处理过程,来产生最终的帧,

.reset ( renderTarget : WebGLRenderTarget ) : undefined

renderTarget -- (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。

重置所有EffectComposer的内部状态。

.setPixelRatio ( pixelRatio : Float ) : undefined

pixelRatio -- 设备像素比

设置设备的像素比。该值通常被用于HiDPI设备,以阻止模糊的输出。 因此,该方法语义类似于WebGLRenderer.setPixelRatio()。

.setSize ( width : Integer, height : Integer ) : undefined

width -- EffectComposer的宽度。
height -- EffectComposer的高度。

考虑设备像素比,重新设置内部渲染缓冲和过程的大小为(width, height)。 因此,该方法语义类似于WebGLRenderer.setSize()。

.swapBuffers () : undefined

交换内部的读/写缓冲。

2. 使用内置效果合成器

1)导入three框架自带效果

// three框架本身自带效果
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
import { SSAARenderPass } from "three/examples/jsm/postprocessing/SSAARenderPass";
import { GlitchPass } from "three/examples/jsm/postprocessing/GlitchPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";

2)实例化合成效果并设置效果窗口尺寸

// 合成效果
const effectComposer = new EffectComposer(renderer);
effectComposer.setSize(window.innerWidth, window.innerHeight);

3) 添加渲染通道

const renderPass = new RenderPass(scene, camera);
effectComposer.addPass(renderPass);

4)添加效果

// 点效果
const dotScreenPass = new DotScreenPass();
dotScreenPass.enabled = false;
effectComposer.addPass(dotScreenPass);

// // 抗锯齿
const smaaPass = new SMAAPass();
effectComposer.addPass(smaaPass);

// // 发光效果
const unrealBloomPass = new UnrealBloomPass();
effectComposer.addPass(unrealBloomPass);
unrealBloomPass.strength = 1;
unrealBloomPass.radius = 0;
unrealBloomPass.threshold = 1;
// // 屏幕闪烁效果
const glitchPass = new GlitchPass();
effectComposer.addPass(glitchPass)

5)将effectComposer挂载至生命函数中

function animate(t) {
  controls.update();
  const time = clock.getElapsedTime();
  requestAnimationFrame(animate);
  //挂载效果合成器
  effectComposer.render();
}

animate();

6)实现效果:

未添加效果前:

添加效果后:

3. 使用shaderPass实现自定义合成效果

1)导入所需效果

import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";

2)设置合成效果

// 合成效果
const effectComposer = new EffectComposer(renderer);
effectComposer.setSize(window.innerWidth, window.innerHeight);

// 添加渲染通道
const renderPass = new RenderPass(scene, camera);
effectComposer.addPass(renderPass);

// 点效果
const dotScreenPass = new DotScreenPass();
dotScreenPass.enabled = false;
effectComposer.addPass(dotScreenPass);

// 抗锯齿
const smaaPass = new SMAAPass();
effectComposer.addPass(smaaPass);

// 发光效果
const unrealBloomPass = new UnrealBloomPass();
effectComposer.addPass(unrealBloomPass);
unrealBloomPass.strength = 1;
unrealBloomPass.radius = 0;
unrealBloomPass.threshold = 1;

3)编写着色器渲染通道

//定义颜色参数
const colorParams = {
  r: 0,
  g: 0,
  b: 0,
};
// 着色器写渲染通道
const shaderPass = new ShaderPass({
  uniforms: {
    tDiffuse: {
      value: null,
    },
    uColor: {
      value: new THREE.Color(colorParams.r, colorParams.g, colorParams.b),
    },
  },
  vertexShader: `
      varying vec2 vUv;
      void main(){
        vUv = uv;
        gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
      }
    `,
  fragmentShader: `
      varying vec2 vUv;
      uniform sampler2D tDiffuse;
      uniform vec3 uColor;
      void main(){
        vec4 color = texture2D(tDiffuse,vUv);
        // gl_FragColor = vec4(vUv,0.0,1.0);
        color.xyz+=uColor;
        gl_FragColor = color;
      }
    `,
});

effectComposer.addPass(shaderPass);

4)编写法相纹理着色器渲染通道

const techPass = new ShaderPass({
  uniforms: {
    tDiffuse: {
      value: null,
    },
    uNormalMap: {
      value: null,
    },
    uTime: {
      value: 0,
    },
  },
  vertexShader: `
    varying vec2 vUv;
    void main(){
      vUv = uv;
      gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
    }
  `,
  fragmentShader: `
    varying vec2 vUv;
    uniform sampler2D tDiffuse;
    uniform sampler2D uNormalMap;
    uniform float uTime;
    void main(){

      //通过时间和uv控制场景的摆动
      vec2 newUv = vUv;
      newUv += sin(newUv.x*10.0+uTime*0.5)*0.03;

      vec4 color = texture2D(tDiffuse,newUv);
      // gl_FragColor = vec4(vUv,0.0,1.0);
      vec4 normalColor = texture2D(uNormalMap,vUv);
      // 设置光线的角度
      vec3 lightDirection = normalize(vec3(-5,5,2)) ;
      //设置亮度效果
      float lightness = clamp(dot(normalColor.xyz,lightDirection),0.0,1.0) ;//前置函数
      color.xyz+=lightness;
      gl_FragColor = color;
    }
  `,
});
techPass.material.uniforms.uNormalMap.value = normalTexture;
effectComposer.addPass(techPass);

5)在声明函数中挂载effectComposer

const clock = new THREE.Clock();
function animate(t) {
  controls.update();
  const time = clock.getElapsedTime();
  requestAnimationFrame(animate);
  // 使用渲染器渲染相机看这个场景的内容渲染出来
  // renderer.render(scene, camera);
  techPass.material.uniforms.uTime.value = time;
  effectComposer.render();
}

animate();

6)实现效果:

 7)全部源码: 

main.js:

import * as THREE from "three";

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as dat from "dat.gui";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

// 导入后期效果合成器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";

// three框架本身自带效果
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";

// 目标:后期处理

//创建gui对象
const gui = new dat.GUI();

// console.log(THREE);
// 初始化场景
const scene = new THREE.Scene();

// 创建透视相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerHeight / window.innerHeight,
  1,
  50
);
// 设置相机位置
// object3d具有position,属性是1个3维的向量
camera.position.set(0, 0, 3);
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
//   更新摄像机的投影矩阵
camera.updateProjectionMatrix();
scene.add(camera);

// 加入辅助轴,帮助我们查看3维坐标轴
// const axesHelper = new THREE.AxesHelper(5);
// scene.add(axesHelper);

// 加载纹理

// 创建纹理加载器对象
const textureLoader = new THREE.TextureLoader();

// 添加环境纹理
const cubeTextureLoader = new THREE.CubeTextureLoader();
const envMapTexture = cubeTextureLoader.load([
  "textures/environmentMaps/0/px.jpg",
  "textures/environmentMaps/0/nx.jpg",
  "textures/environmentMaps/0/py.jpg",
  "textures/environmentMaps/0/ny.jpg",
  "textures/environmentMaps/0/pz.jpg",
  "textures/environmentMaps/0/nz.jpg",
]);
scene.background = envMapTexture;
scene.environment = envMapTexture;

const directionLight = new THREE.DirectionalLight("#ffffff", 1);
directionLight.castShadow = true;
directionLight.position.set(0, 0, 200);
scene.add(directionLight);

// 模型加载
const gltfLoader = new GLTFLoader();
gltfLoader.load("./models/DamagedHelmet/glTF/DamagedHelmet.gltf", (gltf) => {
  console.log(gltf);
  // scene.add(gltf.scene)
  const mesh = gltf.scene.children[0];

  scene.add(mesh);
});

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;

// 合成效果
const effectComposer = new EffectComposer(renderer);
effectComposer.setSize(window.innerWidth, window.innerHeight);

// 添加渲染通道
const renderPass = new RenderPass(scene, camera);
effectComposer.addPass(renderPass);

// 点效果
const dotScreenPass = new DotScreenPass();
dotScreenPass.enabled = false;
effectComposer.addPass(dotScreenPass);

// 抗锯齿
const smaaPass = new SMAAPass();
effectComposer.addPass(smaaPass);

// 发光效果
const unrealBloomPass = new UnrealBloomPass();
effectComposer.addPass(unrealBloomPass);
unrealBloomPass.strength = 1;
unrealBloomPass.radius = 0;
unrealBloomPass.threshold = 1;

//设置色调映射
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;


gui.add(renderer, "toneMappingExposure").min(0).max(2).step(0.01);
gui.add(unrealBloomPass, "strength").min(0).max(2).step(0.01);
gui.add(unrealBloomPass, "radius").min(0).max(2).step(0.01);
gui.add(unrealBloomPass, "threshold").min(0).max(2).step(0.01);

//定义颜色参数
const colorParams = {
  r: 0,
  g: 0,
  b: 0,
};
// 着色器写渲染通道
const shaderPass = new ShaderPass({
  uniforms: {
    tDiffuse: {
      value: null,
    },
    uColor: {
      value: new THREE.Color(colorParams.r, colorParams.g, colorParams.b),
    },
  },
  vertexShader: `
      varying vec2 vUv;
      void main(){
        vUv = uv;
        gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
      }
    `,
  fragmentShader: `
      varying vec2 vUv;
      uniform sampler2D tDiffuse;
      uniform vec3 uColor;
      void main(){
        vec4 color = texture2D(tDiffuse,vUv);
        // gl_FragColor = vec4(vUv,0.0,1.0);
        color.xyz+=uColor;
        gl_FragColor = color;
      }
    `,
});

effectComposer.addPass(shaderPass);

gui
  .add(colorParams, "r")
  .min(-1)
  .max(1)
  .step(0.01)
  .onChange((value) => {
    shaderPass.uniforms.uColor.value.r = value;
  });
gui
  .add(colorParams, "g")
  .min(-1)
  .max(1)
  .step(0.01)
  .onChange((value) => {
    shaderPass.uniforms.uColor.value.g = value;
  });
gui
  .add(colorParams, "b")
  .min(-1)
  .max(1)
  .step(0.01)
  .onChange((value) => {
    shaderPass.uniforms.uColor.value.b = value;
  });
// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
  //   console.log("resize");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  //   更新摄像机的投影矩阵
  camera.updateProjectionMatrix();

  //   更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  //   设置渲染器的像素比例
  renderer.setPixelRatio(window.devicePixelRatio);

  effectComposer.setSize(window.innerWidth, window.innerHeight);
  effectComposer.setPixelRatio(window.devicePixelRatio);
});

//添加法相纹理
const normalTexture = textureLoader.load("./textures/interfaceNormalMap.png");

const techPass = new ShaderPass({
  uniforms: {
    tDiffuse: {
      value: null,
    },
    uNormalMap: {
      value: null,
    },
    uTime: {
      value: 0,
    },
  },
  vertexShader: `
    varying vec2 vUv;
    void main(){
      vUv = uv;
      gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
    }
  `,
  fragmentShader: `
    varying vec2 vUv;
    uniform sampler2D tDiffuse;
    uniform sampler2D uNormalMap;
    uniform float uTime;
    void main(){

      //通过时间和uv控制场景的摆动
      vec2 newUv = vUv;
      newUv += sin(newUv.x*10.0+uTime*0.5)*0.03;

      vec4 color = texture2D(tDiffuse,newUv);
      // gl_FragColor = vec4(vUv,0.0,1.0);
      vec4 normalColor = texture2D(uNormalMap,vUv);
      // 设置光线的角度
      vec3 lightDirection = normalize(vec3(-5,5,2)) ;
      //设置亮度效果
      float lightness = clamp(dot(normalColor.xyz,lightDirection),0.0,1.0) ;//前置函数
      color.xyz+=lightness;
      gl_FragColor = color;
    }
  `,
});
techPass.material.uniforms.uNormalMap.value = normalTexture;
effectComposer.addPass(techPass);

// 将渲染器添加到body
document.body.appendChild(renderer.domElement);

// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼
controls.enableDamping = true;
// 设置自动旋转
// controls.autoRotate = true;

const clock = new THREE.Clock();
function animate(t) {
  controls.update();
  const time = clock.getElapsedTime();
  requestAnimationFrame(animate);
  // 使用渲染器渲染相机看这个场景的内容渲染出来
  // renderer.render(scene, camera);
  techPass.material.uniforms.uTime.value = time;
  effectComposer.render();
}

animate();

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HM-hhxx!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值