【Threejs】轮廓线、边框线、选中效果实现的N种方法以及性能评估 对于模型较小,面数较少,机器性能很好的情况下,用哪种方法都可以。
但是对于压缩后glb还有100m、200m,几百万面,机器配置又一般的情况下,对于效果和性能,就需要作出选择了。
备注:① example里https://jsfiddle.net开头的链接,需要VPN,能访问国外网络,才能打开;
②所有的性能评估,我是以 机器配置:CPU i5-4460 3.20GHz 、内存 8.00 GB、显卡 NVIDIA GeForce GTX 745 (4096MB) 上 运行压缩后100M 面数150w面左右的glb,在chrome上运行测试的。
OutlinePass
example https://threejs.org/examples/?q=outline#webgl_postprocessing_outline
优点 :效果非常赞,可设置 边线大小,光晕,边缘浓度,呼吸闪烁等等效果
缺点 :性能消耗double
主要代码片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 COPY import {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer.js' ;import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js' ;import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js' ;import {OutlinePass} from 'three/examples/jsm/postprocessing/OutlinePass.js' ;import {FXAAShader} from 'three/examples/jsm/shaders/FXAAShader.js' ;const size = renderer.getSize(new THREE.Vector2());const _pixelRatio = renderer.getPixelRatio();const _width = size.width;const _height = size.height;const renderTarget = new THREE.WebGLRenderTarget( _width * _pixelRatio, _height * _pixelRatio, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, encoding: THREE.sRGBEncoding } ); renderTarget.texture.name = "EffectComposer.rt1" ; composer = new EffectComposer(renderer, renderTarget); const renderPass = new RenderPass(scene, camera);composer.addPass(renderPass); outlinePass = new OutlinePass(new THREE.Vector2(window .innerWidth, window .innerHeight), scene, camera); composer.addPass(outlinePass); effectFXAA = new ShaderPass(FXAAShader); effectFXAA.uniforms['resolution' ].value.set(1 / window .innerWidth, 1 / window .innerHeight); composer.addPass(effectFXAA); outlinePass.visibleEdgeColor.set(outlineColor[0 ]); outlinePass.hiddenEdgeColor.set(outlineColor[1 ]); outlinePass.edgeStrength = Number (10.0 ); outlinePass.edgeGlow = Number (1 ); outlinePass.edgeThickness = Number (1.0 ); outlinePass.pulsePeriod = Number (1.8 ); outlinePass.usePatternTexture = false ; outlinePass.downSampleRatio = 2 ; outlinePass.clear = true ; renderer.render(scene, camera); composer.render();
EdgesGeometry
example https://jsfiddle.net/tgcf1u84/3/
https://threejs.org/examples/?q=help#webgl_helpers
优点 :效果还行;性能比OutlinePass,要好一点,但是差距不是很大,大概5-10fps的样子;代码实现简单;
缺点 :性能消耗较大,效果一般,线框的宽度不能大于1(官方是这样解释的:由于OpenGL Core Profile 与 大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。)
主要代码片段
1 2 3 4 5 6 7 8 9 COPY var edgeMaterial = new THREE.LineBasicMaterial( { color : 0xff0000 , linewidth : 5 ,} );object.traverse( function ( child ) { if ( child.isMesh ) { var edges = new THREE.EdgesGeometry( child.geometry, 45 ); var line = new THREE.LineSegments( edges, edgeMaterial ); child.add( line ); } } );
EdgesGeometry + LineSegments2
example https://jsfiddle.net/5qv4Lmog/1/
https://jsfiddle.net/2sx3fuLo/17/
优点 :效果还行;线框宽度可大于1;性能比EdgesGeometry,要差一点,但是差距不是很大;
缺点 :性能消耗较大,效果一般,不能在traverse时,直接add,否则会导致无尽的递归行为;
主要代码片段
1 2 3 4 5 6 7 8 9 10 11 12 13 COPY edgeMaterial = new LineMaterial( { color : 0xff0000 , linewidth : 5 } ); const meshes = [];object.traverse( function ( child ) { if ( child.isMesh ) meshes.push( child ); } ); for ( let mesh of meshes ) { var edges = new THREE.EdgesGeometry( mesh.geometry, 45 ); var wideEdges = new LineSegmentsGeometry().fromEdgesGeometry( edges ); var line = new LineSegments2( wideEdges, edgeMaterial ); mesh.add( line ); }
OutlineEffect
example https://threejs.org/examples/?q=toon#webgl_materials_variations_toon (官方案例,单个scene)
https://jsfiddle.net/cwayd9v5/6/(多个scene,模拟实现特定对象出现边框线的效果)
优点 :效果还行;性能也OK,代码实现很简单;
缺点 :对于结构复杂的模型,不能实现特定对象出现边框线的功能效果(https://stackoverflow.com/questions/59997603/outline-effect-to-target-object/59998722#59998722 这个帖子上思路,能实现我提供的第二个效果,但是对于结构复杂模型,业务功能稍微复杂一些的,就不适用了);
主要代码片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 COPY import { OutlineEffect } from './jsm/effects/OutlineEffect.js' ;let effect;effect = new THREE.OutlineEffect(renderer,{ defaultThickness: 0.015 , defaultColor: [0.2 ,0.2 ,1 ], efaultAlpha: 0.9 , }); effect.render( scene, camera );
绘制一个对象两次;一次轮廓颜色对象,一次正常对象
example https://jsfiddle.net/a4x0fwo7/47/
优点 :效果还行;性能一般;
缺点 :对于结构复杂的模型,会消耗较大的内存和性能;
主要代码片段
https://jsfiddle.net/a4x0fwo7/47/ 看这个链接里的源码
参考文章 :https://blog.mozvr.com/cartoon-outline-effect/
法线延伸
example https://omarshehata.github.io/csb-l01dp/
优点 :效果还行;
缺点 :
主要代码片段
https://github.com/OmarShehata/webgl-outlines 看这个链接里的源码
参考文章 :https://omar-shehata.medium.com/how-to-render-outlines-in-webgl-8253c14724f9
https://github.com/OmarShehata/webgl-outlines
BoxHelper
example https://jsfiddle.net/maco6fqt/12/
https://threejs.org/examples/?q=box#webgl_helpers (官方案例)
优点 :性能最好
缺点 :效果比较差(这种效果只能算上选中效果,和边框线,轮廓线没关系)
主要代码片段
1 2 COPY const box:any = new THREE.BoxHelper( object, '#00ffff' ); object.attach(box);
Donate