使用动画蒙皮网格获得轮廓效果的最佳方法

Best method to get Outline effect with animated skinned mesh

使用动画蒙皮网格获得轮廓效果的最佳方法是什么?

模型暂停在特定姿势的示例:https://jsfiddle.net/Eketol/uev9o0qp/

composer = new THREE.EffectComposer( renderer );
renderPass = new THREE.RenderPass(scene, camera);
renderPass.setSize(window.innerWidth, window.innerHeight);
composer.addPass(renderPass);

outlinePass = new THREE.OutlinePass( new THREE.Vector2( this.viewWidth, this.viewHeight ), scene, camera );
outlinePass.visibleEdgeColor.set( 0xff0000 );
outlinePass.hiddenEdgeColor.set( 0xffff00 );
outlinePass.edgeGlow = 0;
outlinePass.edgeThickness = 0.3; // Default is 1.
outlinePass.edgeStrength = 3; // Default is 3.
outlinePass.setSize(window.innerWidth, window.innerHeight);
composer.addPass(outlinePass);

动画模型的另一个例子:https://jsfiddle.net/Eketol/4xcd365w/

据我了解,这是由于图形卡中进行了转换,因此代码没有顶点位置的参考。 此问题也影响到 raycaster。

我已经阅读了多次尝试和实验。他们中的一些人使用发光material,其他人使用两个甚至三个网格实例和多个渲染通道来完成轮廓(例如:http://jsfiddle.net/Nv7Up/)。

使用发光的缺点material:

使用多个网格的缺点:

问题:

  1. 是否可以使当前的 ThreeJS Outline 效果与动画 SkinnedMesh 一起正常工作?
  2. 如果转换后的顶点信息在显卡上,轮廓着色器是否可以 直接从中获取顶点信息或渲染图像?
  3. 如果以上方法不可行,是否有一种方法可以将 SkinnedMesh 变换应用于顶点,以便着色器具有正确的姿势信息?

Is it possible to get the current ThreeJS Outline effect working properly with animated SkinnedMesh?

是的,但是需要增强内部顶点着色器。我在这个更新的 fiddle 中添加了相应的着色器块(morphtarget_pars_vertexskinbase_vertexskinning_pars_vertexbegin_vertexmorphtarget_vertexskinning_vertex, project_vertex).

https://jsfiddle.net/35vrtm42/

但请注意,马动画是基于变形目标的。

有了这个增强功能,您只需告诉 OutlinePass 启用相应的动画类型。对于fiddle,有必要这样做。

outlinePass.depthMaterial.morphTargets = true;
outlinePass.prepareMaskMaterial.morphTargets = true;

如果您的模型使用骨骼动画,只需将 morphTargets 属性 替换为 skinning

three.js R112

在 OutlinePass.js v121 (6-Okt-2020) L38 中,缺少蒙皮参数:

    this.depthMaterial = new THREE.MeshDepthMaterial();
    this.depthMaterial.side = THREE.DoubleSide;
    this.depthMaterial.depthPacking = THREE.RGBADepthPacking;
    this.depthMaterial.blending = THREE.NoBlending;

    this.prepareMaskMaterial = this.getPrepareMaskMaterial();
    this.prepareMaskMaterial.side = THREE.DoubleSide;
    this.prepareMaskMaterial.fragmentShader = replaceDepthToViewZ( this.prepareMaskMaterial.fragmentShader, this.renderCamera );

其实应该是这样的

 this.depthMaterial = new THREE.MeshDepthMaterial();
    this.depthMaterial.side = THREE.DoubleSide;
    this.depthMaterial.depthPacking = THREE.RGBADepthPacking;
    this.depthMaterial.blending = THREE.NoBlending;
    this.depthMaterial.skinning = true; // <-------

    this.prepareMaskMaterial = this.getPrepareMaskMaterial();
    this.prepareMaskMaterial.side = THREE.DoubleSide;
    this.prepareMaskMaterial.fragmentShader = replaceDepthToViewZ( this.prepareMaskMaterial.fragmentShader, this.renderCamera );
    this.prepareMaskMaterial.skinning = true;   // <-----