简体   繁体   English

如何在three.js中动画网格的绘制

[英]How to animate the drawing of a mesh in three.js

I've got a ribbon-like mesh made out of a buffer geometry, the faces of which are invisible.我有一个由缓冲几何体制成的带状网格,其面是不可见的。 I'm using a custom shader for this -- gl_FragColor = vec4(1.0,1.0,1.0,0.0) .我为此使用了自定义着色器 - gl_FragColor = vec4(1.0,1.0,1.0,0.0)

As a 3DObject is moved along the ribbon, I raycast the index of the faces over which it is, and update the shader making them.当 3DObject 沿着功能区移动时,我会对其所在面的索引进行光线投射,并更新生成它们的着色器。

I'm not satisfied with the effect since it results in a pretty chunky animation.我对效果不满意,因为它产生了一个非常矮胖的动画。 If I add more faces, then I get a serious performance hit.如果我添加更多面孔,那么我的性能会受到严重影响。

Would there be any way for me to update the fragment's alpha based on the 3DObject position without having to resort to entire faces?有什么方法可以让我根据 3DObject 位置更新片段的 alpha 而不必求助于整个面部?

On a side note: I've also tried clipping the ribbon from view, based on x/z pixel positions.附带说明:我还尝试根据 x/z 像素位置从视图中剪下色带。 The effect is perfect, the performance is good, but I get undesired effects when the ribbon makes sharp turns.效果完美,性能好,但是当色带急转弯时会出现不良效果。

You can render only part of your BufferGeometry by setting drawRange like so:您可以通过如下设置drawRange来仅渲染BufferGeometry的一部分:

mesh.geometry.setDrawRange( startIndex, count );

For more information and a live example see this answer .有关更多信息和现场示例,请参阅此答案


EDIT - As mentioned in the comments below, another approach is to add an attribute to your geometry which represents the fractional distance each vertex is positioned along the geometry.编辑 - 正如下面的评论中提到的,另一种方法是向几何图形添加一个属性,它表示每个顶点沿几何图形定位的分数距离。 This approach will require a custom ShaderMaterial , but you will be able to smoothly animate the drawing of your mesh.这种方法需要一个自定义的ShaderMaterial ,但您将能够平滑地为您的网格绘制动画。

Here is an example vertex shader and fragment shader这是一个示例顶点着色器和片段着色器

<script id="vertex_shader" type="x-shader/x-vertex">

attribute float distance;

varying float vDistance;
varying vec3 vNormal;
varying vec3 vViewPosition;

void main() {

    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

    vDistance = distance;
    vNormal = normalize( normalMatrix * normal );
    vViewPosition = - mvPosition.xyz;

    gl_Position = projectionMatrix * mvPosition;

}

</script>

<script id="fragment_shader" type="x-shader/x-fragment">

uniform float fraction;

varying float vDistance;
varying vec3 vNormal;
varying vec3 vViewPosition;

void main() {

    if ( vDistance > fraction ) discard;

    vec3 color = vec3( 0.25, 0.5, 1.0 );

    // hack in a fake pointlight at camera location, plus ambient
    vec3 normal = normalize( vNormal );
    vec3 lightDir = normalize( vViewPosition );

    float dotProduct = max( dot( normal, lightDir ), 0.0 ) + 0.2;

    // trick to make the clipped ends appear solid
    gl_FragColor = ( gl_FrontFacing ) ? vec4( color * dotProduct, 1.0 ) : vec4( color, 1.0 );

}

</script>

Here is how to add an attribute to your BufferGeometry and instantiate the material.以下是如何向BufferGeometry添加属性并实例化材质。

// new attribute
var numVertices = geometry.attributes.position.count;
var distance = new Float32Array( numVertices * 1 ); // 1 value per vertex
geometry.addAttribute( 'distance', new THREE.BufferAttribute( distance, 1 ) );

// populate attribute
for ( var i = 0, l = numVertices; i < l; i ++ ) {

    // set new attribute
    distance[ i ] = ( geometry.attributes.position.getY( i ) + 10 ) / 20;

    // wiggle geometry a bit while we're at it
    var x = geometry.attributes.position.getX( i )
    var y = geometry.attributes.position.getY( i );
    geometry.attributes.position.setX( i, x + 2 * Math.sin( y ) );

}

// uniforms
var uniforms = {
    "fraction" : { value: 0 }
};

// material
var material = new THREE.ShaderMaterial( {
    uniforms        : uniforms,
    vertexShader    : document.getElementById( 'vertex_shader' ).textContent,
    fragmentShader  : document.getElementById( 'fragment_shader' ).textContent,
    side: THREE.DoubleSide
} );

// mesh
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

Then, in your render loop, set the desired fraction to render:然后,在您的渲染循环中,设置要渲染的所需分数:

mesh.material.uniforms.fraction.value = 0.5 * ( 1 + Math.cos( t ) );

fiddle: http://jsfiddle.net/m99aj10b/小提琴: http : //jsfiddle.net/m99aj10b/

小提琴快照

three.js r.76三.js r.76

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM