threejs边缘暗角shader

本文介绍如何利用Three.js中的特效合成器处理三维模型的边缘暗角及锯齿问题,通过添加FXAA抗锯齿效果提升渲染质量,并实现动态调整以适应不同窗口尺寸。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


效果

在这里插入图片描述

引入库

import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader'

shader

let DarkMaskShader = {
  uniforms: {
    tDiffuse: {
      value: null
    },
    maskColor: {
      value: new THREE.Color(0x000000)
    },
    maskAlpha: {
      value: 1.0
    },
    markRadius: {
      value: 0.15
    },
    smoothSize: {
      value: 0.5
    }
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
    	vUv = uv;
    	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
  `,
  fragmentShader: `
    uniform float maskAlpha;
    uniform vec3 maskColor;
    uniform float markRadius;
    uniform float smoothSize;
    uniform sampler2D tDiffuse;
    varying vec2 vUv;
    float sdfCircle(vec2 coord, vec2 center, float radius) {
    	vec2 offset = coord - center;
    	return sqrt((offset.x * offset.x) + (offset.y * offset.y)) - radius;
    },
    void main() {
    	vec4 texel = texture2D( tDiffuse, vUv );
       float sdfValue = sdfCircle(vUv, vec2(0.5, 0.5), markRadius);
    	if (sdfValue < 0.0){
     		gl_FragColor = texel;
    	}else{
    		float a = smoothstep(0.0, smoothSize, sdfValue);
       	gl_FragColor = mix(texel, vec4(maskColor, maskAlpha), a);
    	}
    }
  `
}

窗口监测里添加

function onWindowResize() {
  camera.aspect = document.getElementById('threecanvas').offsetWidth / document.getElementById('threecanvas').offsetHeight
  camera.updateProjectionMatrix()
  /*********************************************************************/
  // 暗角范围
  composer.setSize(document.getElementById('threecanvas').offsetWidth, document.getElementById('threecanvas').offsetHeight) // 暗角
  renderer.setSize(document.getElementById('threecanvas').offsetWidth, document.getElementById('threecanvas').offsetHeight)
}

添加效果合成器

function initEffectComposer() {
  // 处理模型闪烁问题【优化展示网格闪烁】
  const parameters = { format: THREE.RGBFormat }
  const size = renderer.getDrawingBufferSize(new THREE.Vector2())
  const renderTarget = new THREE.WebGLMultisampleRenderTarget(size.width, size.height, parameters)
  /******************************************边缘暗角****************************************/
  renderScene = new RenderPass(scene, camera)
  renderScene.clear = true
  const effectDarkMask = new ShaderPass(DarkMaskShader)
  composeraj = new EffectComposer(renderer, renderTarget)
  composeraj.addPass(renderScene)
  composeraj.addPass(effectDarkMask)// 开启圆形暗角,需要处理模型边缘失真
}

处理模型边缘锯齿

添加特效合成器后,会出现模型边缘锯齿
推荐使用 FXAA 处理
具体请到:

// 效果合成器,shader渲染使用
function initEffectComposer() {
  // 处理模型闪烁问题【优化展示网格闪烁】
  const parameters = { format: THREE.RGBFormat }
  const size = renderer.getDrawingBufferSize(new THREE.Vector2())
  const renderTarget = new THREE.WebGLMultisampleRenderTarget(size.width, size.height, parameters)
  /******************************************边缘暗角****************************************/
  renderScene = new RenderPass(scene, camera)
  renderScene.clear = true
  const effectDarkMask = new ShaderPass(DarkMaskShader)
  composeraj = new EffectComposer(renderer, renderTarget)
  composeraj.addPass(renderScene)
  composeraj.addPass(effectDarkMask)// 开启圆形暗角,需要处理模型边缘失真
  /*********************************************特效锯齿处理****************************************/
  // 增加fxaashader处理模型边缘锯齿,开启EffectComposer后才能生效【开启特效合成之后的展示优化】
  var FXAAShaderPass = new ShaderPass(FXAAShader)
  const pixelRatio = renderer.getPixelRatio()
  const width = document.getElementById('threecanvas').offsetWidth
  const height = document.getElementById('threecanvas').offsetHeight
  FXAAShaderPass.uniforms['resolution'].value.set(1 / (width * pixelRatio), 1 / (height * pixelRatio))
  FXAAShaderPass.renderToScreen = true
  composeraj.addPass(FXAAShaderPass)
}

渲染

渲染部分,如果添加了特效合成器,则要把传统的渲染方式替换为特效的通道

// 渲染
function render() {
  update()
  requestAnimationFrame(render)// 执行一个动画.并在动画执行后重新渲染
  // 传统渲染器,如果使用shader着色器,则注掉这个,增加效果合成器,增加通道渲染 // renderer.render(scene, camera)
  composeraj.render()
}

后续

这一部分特效也是参考了大部分其他知乎、博客、简书等等…
话说,找一个特效真难,搜到的好的特效后边都是两个字,买断 &T~T&,都拿去作商业用途了,如果一个小白从头开始,跟着three官网做一些基础的三维物体或基础场景还是可以的,那些进阶的东西,特效、动效什么的,真的是难找的要死,现在学个东西,自学还真是难啊,高级一点的接触都接触不到,像我这样的,自己扣一扣底层代码,然后往上一步一个坑真的难的一批,各种搜索,找一找成型的源码,自己对照着底层,硬理解,难搞。 想速成的话…多花钱,想按部就班的搞一搞,吃的透就要从简到繁,从底层到显示…一步一坑,从three进去,到webgl,再看OpenGL,对照底层封装three上的缺陷,然后完善,形成一套自己的基础引擎。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值