如何在three.js中动画网格的绘制 [英] How to animate the drawing of a mesh in three.js

查看:60
本文介绍了如何在three.js中动画网格的绘制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由缓冲几何体制成的带状网格,其面是不可见的.我为此使用了自定义着色器 -- gl_FragColor = vec4(1.0,1.0,1.0,0.0).

当一个 3DObject 沿着功能区移动时,我会对其所在面的索引进行光线投射,并更新制作它们的着色器.

我对效果不满意,因为它产生了一个非常矮胖的动画.如果我添加更多面孔,那么我的性能会受到严重影响.

有什么方法可以让我根据 3DObject 位置更新片段的 alpha 而不必求助于整个面部?

附带说明:我还尝试根据 x/z 像素位置从视图中剪下色带.效果完美,性能好,但丝带急转弯时出现不良效果.

解决方案

通过像这样设置 drawRange,您可以只渲染 BufferGeometry 的一部分:

mesh.geometry.setDrawRange( startIndex, count );

有关详细信息和现场示例,请参阅

three.js r.76

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).

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.

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?

On a side note: I've also tried clipping the ribbon from view, based on x/z pixel positions. 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:

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.

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.

// 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/

three.js r.76

这篇关于如何在three.js中动画网格的绘制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆