• 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框架自带效果

    1. // three框架本身自带效果
    2. import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
    3. import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass";
    4. import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
    5. import { SSAARenderPass } from "three/examples/jsm/postprocessing/SSAARenderPass";
    6. import { GlitchPass } from "three/examples/jsm/postprocessing/GlitchPass";
    7. import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
    8. import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";

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

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

    3) 添加渲染通道

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

    4)添加效果

    1. // 点效果
    2. const dotScreenPass = new DotScreenPass();
    3. dotScreenPass.enabled = false;
    4. effectComposer.addPass(dotScreenPass);
    5. // // 抗锯齿
    6. const smaaPass = new SMAAPass();
    7. effectComposer.addPass(smaaPass);
    8. // // 发光效果
    9. const unrealBloomPass = new UnrealBloomPass();
    10. effectComposer.addPass(unrealBloomPass);
    11. unrealBloomPass.strength = 1;
    12. unrealBloomPass.radius = 0;
    13. unrealBloomPass.threshold = 1;
    14. // // 屏幕闪烁效果
    15. const glitchPass = new GlitchPass();
    16. effectComposer.addPass(glitchPass)

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

    1. function animate(t) {
    2. controls.update();
    3. const time = clock.getElapsedTime();
    4. requestAnimationFrame(animate);
    5. //挂载效果合成器
    6. effectComposer.render();
    7. }
    8. animate();

    6)实现效果:

    未添加效果前:

    添加效果后:

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

    1)导入所需效果

    1. import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
    2. import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass";
    3. import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
    4. import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
    5. import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";

    2)设置合成效果

    1. // 合成效果
    2. const effectComposer = new EffectComposer(renderer);
    3. effectComposer.setSize(window.innerWidth, window.innerHeight);
    4. // 添加渲染通道
    5. const renderPass = new RenderPass(scene, camera);
    6. effectComposer.addPass(renderPass);
    7. // 点效果
    8. const dotScreenPass = new DotScreenPass();
    9. dotScreenPass.enabled = false;
    10. effectComposer.addPass(dotScreenPass);
    11. // 抗锯齿
    12. const smaaPass = new SMAAPass();
    13. effectComposer.addPass(smaaPass);
    14. // 发光效果
    15. const unrealBloomPass = new UnrealBloomPass();
    16. effectComposer.addPass(unrealBloomPass);
    17. unrealBloomPass.strength = 1;
    18. unrealBloomPass.radius = 0;
    19. unrealBloomPass.threshold = 1;

    3)编写着色器渲染通道

    1. //定义颜色参数
    2. const colorParams = {
    3. r: 0,
    4. g: 0,
    5. b: 0,
    6. };
    7. // 着色器写渲染通道
    8. const shaderPass = new ShaderPass({
    9. uniforms: {
    10. tDiffuse: {
    11. value: null,
    12. },
    13. uColor: {
    14. value: new THREE.Color(colorParams.r, colorParams.g, colorParams.b),
    15. },
    16. },
    17. vertexShader: `
    18. varying vec2 vUv;
    19. void main(){
    20. vUv = uv;
    21. gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
    22. }
    23. `,
    24. fragmentShader: `
    25. varying vec2 vUv;
    26. uniform sampler2D tDiffuse;
    27. uniform vec3 uColor;
    28. void main(){
    29. vec4 color = texture2D(tDiffuse,vUv);
    30. // gl_FragColor = vec4(vUv,0.0,1.0);
    31. color.xyz+=uColor;
    32. gl_FragColor = color;
    33. }
    34. `,
    35. });
    36. effectComposer.addPass(shaderPass);

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

    1. const techPass = new ShaderPass({
    2. uniforms: {
    3. tDiffuse: {
    4. value: null,
    5. },
    6. uNormalMap: {
    7. value: null,
    8. },
    9. uTime: {
    10. value: 0,
    11. },
    12. },
    13. vertexShader: `
    14. varying vec2 vUv;
    15. void main(){
    16. vUv = uv;
    17. gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
    18. }
    19. `,
    20. fragmentShader: `
    21. varying vec2 vUv;
    22. uniform sampler2D tDiffuse;
    23. uniform sampler2D uNormalMap;
    24. uniform float uTime;
    25. void main(){
    26. //通过时间和uv控制场景的摆动
    27. vec2 newUv = vUv;
    28. newUv += sin(newUv.x*10.0+uTime*0.5)*0.03;
    29. vec4 color = texture2D(tDiffuse,newUv);
    30. // gl_FragColor = vec4(vUv,0.0,1.0);
    31. vec4 normalColor = texture2D(uNormalMap,vUv);
    32. // 设置光线的角度
    33. vec3 lightDirection = normalize(vec3(-5,5,2)) ;
    34. //设置亮度效果
    35. float lightness = clamp(dot(normalColor.xyz,lightDirection),0.0,1.0) ;//前置函数
    36. color.xyz+=lightness;
    37. gl_FragColor = color;
    38. }
    39. `,
    40. });
    41. techPass.material.uniforms.uNormalMap.value = normalTexture;
    42. effectComposer.addPass(techPass);

    5)在声明函数中挂载effectComposer

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

    6)实现效果:

     7)全部源码: 

    main.js:

    1. import * as THREE from "three";
    2. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
    3. import gsap from "gsap";
    4. import * as dat from "dat.gui";
    5. import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
    6. import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
    7. // 导入后期效果合成器
    8. import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
    9. // three框架本身自带效果
    10. import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
    11. import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass";
    12. import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
    13. import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
    14. import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";
    15. // 目标:后期处理
    16. //创建gui对象
    17. const gui = new dat.GUI();
    18. // console.log(THREE);
    19. // 初始化场景
    20. const scene = new THREE.Scene();
    21. // 创建透视相机
    22. const camera = new THREE.PerspectiveCamera(
    23. 75,
    24. window.innerHeight / window.innerHeight,
    25. 1,
    26. 50
    27. );
    28. // 设置相机位置
    29. // object3d具有position,属性是1个3维的向量
    30. camera.position.set(0, 0, 3);
    31. // 更新摄像头
    32. camera.aspect = window.innerWidth / window.innerHeight;
    33. // 更新摄像机的投影矩阵
    34. camera.updateProjectionMatrix();
    35. scene.add(camera);
    36. // 加入辅助轴,帮助我们查看3维坐标轴
    37. // const axesHelper = new THREE.AxesHelper(5);
    38. // scene.add(axesHelper);
    39. // 加载纹理
    40. // 创建纹理加载器对象
    41. const textureLoader = new THREE.TextureLoader();
    42. // 添加环境纹理
    43. const cubeTextureLoader = new THREE.CubeTextureLoader();
    44. const envMapTexture = cubeTextureLoader.load([
    45. "textures/environmentMaps/0/px.jpg",
    46. "textures/environmentMaps/0/nx.jpg",
    47. "textures/environmentMaps/0/py.jpg",
    48. "textures/environmentMaps/0/ny.jpg",
    49. "textures/environmentMaps/0/pz.jpg",
    50. "textures/environmentMaps/0/nz.jpg",
    51. ]);
    52. scene.background = envMapTexture;
    53. scene.environment = envMapTexture;
    54. const directionLight = new THREE.DirectionalLight("#ffffff", 1);
    55. directionLight.castShadow = true;
    56. directionLight.position.set(0, 0, 200);
    57. scene.add(directionLight);
    58. // 模型加载
    59. const gltfLoader = new GLTFLoader();
    60. gltfLoader.load("./models/DamagedHelmet/glTF/DamagedHelmet.gltf", (gltf) => {
    61. console.log(gltf);
    62. // scene.add(gltf.scene)
    63. const mesh = gltf.scene.children[0];
    64. scene.add(mesh);
    65. });
    66. // 初始化渲染器
    67. const renderer = new THREE.WebGLRenderer();
    68. // 设置渲染尺寸大小
    69. renderer.setSize(window.innerWidth, window.innerHeight);
    70. renderer.shadowMap.enabled = true;
    71. // 合成效果
    72. const effectComposer = new EffectComposer(renderer);
    73. effectComposer.setSize(window.innerWidth, window.innerHeight);
    74. // 添加渲染通道
    75. const renderPass = new RenderPass(scene, camera);
    76. effectComposer.addPass(renderPass);
    77. // 点效果
    78. const dotScreenPass = new DotScreenPass();
    79. dotScreenPass.enabled = false;
    80. effectComposer.addPass(dotScreenPass);
    81. // 抗锯齿
    82. const smaaPass = new SMAAPass();
    83. effectComposer.addPass(smaaPass);
    84. // 发光效果
    85. const unrealBloomPass = new UnrealBloomPass();
    86. effectComposer.addPass(unrealBloomPass);
    87. unrealBloomPass.strength = 1;
    88. unrealBloomPass.radius = 0;
    89. unrealBloomPass.threshold = 1;
    90. //设置色调映射
    91. renderer.toneMapping = THREE.ACESFilmicToneMapping;
    92. renderer.toneMappingExposure = 1;
    93. gui.add(renderer, "toneMappingExposure").min(0).max(2).step(0.01);
    94. gui.add(unrealBloomPass, "strength").min(0).max(2).step(0.01);
    95. gui.add(unrealBloomPass, "radius").min(0).max(2).step(0.01);
    96. gui.add(unrealBloomPass, "threshold").min(0).max(2).step(0.01);
    97. //定义颜色参数
    98. const colorParams = {
    99. r: 0,
    100. g: 0,
    101. b: 0,
    102. };
    103. // 着色器写渲染通道
    104. const shaderPass = new ShaderPass({
    105. uniforms: {
    106. tDiffuse: {
    107. value: null,
    108. },
    109. uColor: {
    110. value: new THREE.Color(colorParams.r, colorParams.g, colorParams.b),
    111. },
    112. },
    113. vertexShader: `
    114. varying vec2 vUv;
    115. void main(){
    116. vUv = uv;
    117. gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
    118. }
    119. `,
    120. fragmentShader: `
    121. varying vec2 vUv;
    122. uniform sampler2D tDiffuse;
    123. uniform vec3 uColor;
    124. void main(){
    125. vec4 color = texture2D(tDiffuse,vUv);
    126. // gl_FragColor = vec4(vUv,0.0,1.0);
    127. color.xyz+=uColor;
    128. gl_FragColor = color;
    129. }
    130. `,
    131. });
    132. effectComposer.addPass(shaderPass);
    133. gui
    134. .add(colorParams, "r")
    135. .min(-1)
    136. .max(1)
    137. .step(0.01)
    138. .onChange((value) => {
    139. shaderPass.uniforms.uColor.value.r = value;
    140. });
    141. gui
    142. .add(colorParams, "g")
    143. .min(-1)
    144. .max(1)
    145. .step(0.01)
    146. .onChange((value) => {
    147. shaderPass.uniforms.uColor.value.g = value;
    148. });
    149. gui
    150. .add(colorParams, "b")
    151. .min(-1)
    152. .max(1)
    153. .step(0.01)
    154. .onChange((value) => {
    155. shaderPass.uniforms.uColor.value.b = value;
    156. });
    157. // 监听屏幕大小改变的变化,设置渲染的尺寸
    158. window.addEventListener("resize", () => {
    159. // console.log("resize");
    160. // 更新摄像头
    161. camera.aspect = window.innerWidth / window.innerHeight;
    162. // 更新摄像机的投影矩阵
    163. camera.updateProjectionMatrix();
    164. // 更新渲染器
    165. renderer.setSize(window.innerWidth, window.innerHeight);
    166. // 设置渲染器的像素比例
    167. renderer.setPixelRatio(window.devicePixelRatio);
    168. effectComposer.setSize(window.innerWidth, window.innerHeight);
    169. effectComposer.setPixelRatio(window.devicePixelRatio);
    170. });
    171. //添加法相纹理
    172. const normalTexture = textureLoader.load("./textures/interfaceNormalMap.png");
    173. const techPass = new ShaderPass({
    174. uniforms: {
    175. tDiffuse: {
    176. value: null,
    177. },
    178. uNormalMap: {
    179. value: null,
    180. },
    181. uTime: {
    182. value: 0,
    183. },
    184. },
    185. vertexShader: `
    186. varying vec2 vUv;
    187. void main(){
    188. vUv = uv;
    189. gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
    190. }
    191. `,
    192. fragmentShader: `
    193. varying vec2 vUv;
    194. uniform sampler2D tDiffuse;
    195. uniform sampler2D uNormalMap;
    196. uniform float uTime;
    197. void main(){
    198. //通过时间和uv控制场景的摆动
    199. vec2 newUv = vUv;
    200. newUv += sin(newUv.x*10.0+uTime*0.5)*0.03;
    201. vec4 color = texture2D(tDiffuse,newUv);
    202. // gl_FragColor = vec4(vUv,0.0,1.0);
    203. vec4 normalColor = texture2D(uNormalMap,vUv);
    204. // 设置光线的角度
    205. vec3 lightDirection = normalize(vec3(-5,5,2)) ;
    206. //设置亮度效果
    207. float lightness = clamp(dot(normalColor.xyz,lightDirection),0.0,1.0) ;//前置函数
    208. color.xyz+=lightness;
    209. gl_FragColor = color;
    210. }
    211. `,
    212. });
    213. techPass.material.uniforms.uNormalMap.value = normalTexture;
    214. effectComposer.addPass(techPass);
    215. // 将渲染器添加到body
    216. document.body.appendChild(renderer.domElement);
    217. // 初始化控制器
    218. const controls = new OrbitControls(camera, renderer.domElement);
    219. // 设置控制器阻尼
    220. controls.enableDamping = true;
    221. // 设置自动旋转
    222. // controls.autoRotate = true;
    223. const clock = new THREE.Clock();
    224. function animate(t) {
    225. controls.update();
    226. const time = clock.getElapsedTime();
    227. requestAnimationFrame(animate);
    228. // 使用渲染器渲染相机看这个场景的内容渲染出来
    229. // renderer.render(scene, camera);
    230. techPass.material.uniforms.uTime.value = time;
    231. effectComposer.render();
    232. }
    233. animate();

  • 相关阅读:
    Java msyql批量插入 十万条数据
    Python调试指南
    【MySQL从0到1】第六篇:内置函数
    【刷题笔记9.25】LeetCode:环形链表
    yarn节点属性及调度
    玩转springboot之springboot配置文件
    Java学习day01:数据类型、运算符、分支结构
    Go实战学习笔记-1.Go安装、介绍及Go Playground介绍和运行hello world
    Redis真没那么难,这份大佬实战笔记也太可了,吹爆
    java 1.8 图片转base64 和base64转图片Demo
  • 原文地址:https://blog.csdn.net/damadashen/article/details/126023046