十四、Three场景物体增加描边

        项目的场景中需要点击建筑物产生描边的效果,看着很是不错,本期就来给大家讲解一下怎么来实现。本次使用的是threejs138版本,在vue3+vite+ant的项目中使用。

下面来看看实现的效果。房子建筑有了明显的描边效果。

实现步骤

  • 增加composer.js

注意的点:

1. FXAAShader主要解决composer.render后锯齿的问题。

2. outlinePass 可以写成多个,也可以写成变量传递。

3. outlinePass.hiddenEdgeColor默认是白色,可以不写。

import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass';
import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader.js'
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader';
import scene from '../scene';
import camera from '../camera';
import renderer from '../renderer';
import * as THREE from 'three';

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

  const composer = new EffectComposer(renderer.renderer)
  composer.renderToScreen = false
  composer.addPass(new RenderPass(scene, camera))
  // 着色器
  let shaderPass = new ShaderPass(new THREE.ShaderMaterial({
    uniforms: {
      baseTexture: { value: null },
      bloomTexture: { value: composer.renderTarget2.texture },
      tDiffuse: {
        value: null
      }
    },
    vertexShader:'\t\t\tvarying vec2 vUv;\n' +
                      '\n' +
                      '\t\t\tvoid main() {\n' +
                      '\n' +
                      '\t\t\t\tvUv = uv;\n' +
                        '\n' +
                        '\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n' +
                      '\n' +
                      '\t\t\t}',
    fragmentShader:'\t\t\tuniform sampler2D baseTexture;\n' +
                          '\t\t\tuniform sampler2D bloomTexture;\n' +
                          '\n' +
                          '\t\t\tvarying vec2 vUv;\n' +
                          '\n' +
                          '\t\t\tvoid main() {\n' +
                          '\n' +
                          '\t\t\t\tgl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );\n' +
                          '\n' +
                        '\t\t\t}',
    defines: {}
  }), 'baseTexture')

  shaderPass.renderToScreen = false
  shaderPass.needsSwap = true
  //将创建的通道添加到EffectComposer(效果组合器)对象中
  effectComposer.addPass(shaderPass)

  // 创建阴影效果
  const effectFXAA = new ShaderPass(FXAAShader);
  effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
  effectComposer.addPass(effectFXAA);

  const effectColorSpaceConversion = new ShaderPass(GammaCorrectionShader)
  // effectColorSpaceConversion.renderToScreen = true;
  effectComposer.addPass(effectColorSpaceConversion)

  // 创建高亮边框
  const outlineParams = {
    edgeStrength: 2.0,
    edgeGlow: 1.0,
    edgeThickness: 1,
    pulsePeriod: 0,
    rotate: false,
    usePatternTexture: {
      wrapS: THREE.RepeatWrapping,
      wrapT: THREE.RepeatWrapping,
    },
  };
  const outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera);
  outlinePass.edgeStrength = Number(outlineParams.edgeStrength);
  outlinePass.edgeGlow = Number(outlineParams.edgeGlow);
  outlinePass.edgeThickness = Number(outlineParams.edgeThickness);
  outlinePass.pulsePeriod = Number(outlineParams.pulsePeriod);
  outlinePass.renderToScreen = false;
  outlinePass.usePatternTexture = false;
  outlinePass.visibleEdgeColor.set('#3875ff');
  outlinePass.hiddenEdgeColor.set('white');

  //创建效果组合器对象,可以在该对象上添加后期处理通道,通过配置该对象,使它可以渲染我们的场景,并应用额外的后期处理步骤,在render循环中,使用EffectComposer渲染场景、应用通道,并输出结果。
  effectComposer.addPass(outlinePass)
  effectComposer.render()              

export default {composer,effectComposer,outlinePass};

  • 在animate里面重复调用,以下着重注意的点有三点。
  1. Composer.composer的引入位置必须是在renderer.render()之后。否则不能出来效果。
  2. Composer.effectComposer的位置必须是在最后,否则合成器不能展示成功。
  3. glowMaterialList 里面的值是需要发光的物体名称,可以通过mitt或者vuex或者watch监听等方法来同步监听。
import camera from './camera';
import renderer from './renderer';
import controls from './controls';
import scene from './scene';
import { TWEEN } from 'three/examples/jsm/libs/tween.module.min';
import composer from './modify/composer';
import * as THREE from 'three';
var materials ={
  scene:null,
}
var glowMaterialList=['Cylinder022']

function animate() {
  controls.update();
  TWEEN.update();

  // 使用渲染器渲染相机看这个场景的内容渲染出来
  renderer.renderer.render(scene, camera);
  
  // 将不需要处理辉光的材质进行存储备份
  scene.traverse((v) => {
      // 备份一份场景背景然后清空
  if (v instanceof THREE.Scene) {
    materials.scene = v.background
    v.background = null
  }
  if (!glowMaterialList.includes(v.name) && v.isMesh) {
      // 备份当前材质内容
    materials[v.uuid] = v.material
    // 将不需要辉光的材质设置为黑色
    v.material = new THREE.MeshBasicMaterial({ color: 'black' })
  }
  })
  if (composer.composer) { composer.composer.render() }
  scene.traverse((v) => {
    if (materials[v.uuid]) {
      v.material = materials[v.uuid]
      delete materials[v.uuid]
    }
    if (v instanceof THREE.Scene) {
      v.background = materials.scene
      delete materials.scene
    }
  })
  if (composer.effectComposer) { composer.effectComposer.render() }

  requestAnimationFrame(animate);
}

export default animate;

  • resize的时候增加适应屏幕
import camera from "./camera";
import rendererModule from "./renderer";
import composer from './modify/composer';
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
//   更新摄像机的投影矩阵
camera.updateProjectionMatrix();

// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
  //   console.log("resize");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  //   更新摄像机的投影矩阵
  camera.updateProjectionMatrix();

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

});

四、在点击时候调用composer.outlinPass方法

注意的点有:

  1. selectedObjects是一个数组mesh,里面可以包含多个物体。
  2. 如果只想选一个,那么一定要记得清空。
  3. 所有的相同材质的物体都会描边。            

import composer from '../modify/composer';

  // 事件的监听
  window.addEventListener("click", (event) => {
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);
    camera.updateMatrixWorld(true)

    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObject(scene);
    if (intersects.length > 0) {
      // console.log(intersects)
  //点击房屋
      let target = intersects[0].object;
      if (selectedObject !== target) {
        composer.outlinePass.selectedObjects = [target]
      }
    } else if (selectedObject) {
      selectedObject = null;
    }
  });

以上就是实现物体描边的步骤,只需要调节composer.js里面outlineParams的参数就可以调节到你需要的描边的颜色、粗细等参数,还有是否闪烁,闪烁的交替颜色等,如果还有不懂的可以联系我哦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

arguments_zd

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

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

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

打赏作者

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

抵扣说明:

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

余额充值