javascript - Cómo animar el dibujo de una malla en three.js
(1)
Tengo una malla tipo cinta hecha de una geometría de amortiguación, cuyas caras son invisibles. Estoy usando un sombreador personalizado para esto - gl_FragColor = vec4(1.0,1.0,1.0,0.0)
.
Cuando se desplaza un objeto 3D a lo largo de la cinta, filmo el índice de las caras sobre las que se encuentra y actualizo el sombreado que las forma.
No estoy satisfecho con el efecto ya que resulta en una animación bastante gruesa. Si agrego más caras, recibo un golpe de rendimiento serio.
¿Hubiera alguna forma de actualizar el alfa del fragmento en función de la posición 3DObject sin tener que recurrir a caras enteras?
En una nota al margen: también he intentado recortar la cinta de la vista, en función de las posiciones de píxeles x / z. El efecto es perfecto, el rendimiento es bueno, pero obtengo efectos no deseados cuando la cinta gira bruscamente.
Puede representar solo una parte de su BufferGeometry
configurando drawRange
manera:
mesh.geometry.setDrawRange( startIndex, count );
Para obtener más información y un ejemplo en vivo, vea esta respuesta .
EDITAR - Como se menciona en los comentarios a continuación, otro enfoque es agregar un atributo a su geometría que represente la distancia fraccional que cada vértice está posicionado a lo largo de la geometría. Este enfoque requerirá un ShaderMaterial
personalizado, pero podrá animar suavemente el dibujo de su malla.
Aquí hay un sombreador de vértices y un sombreador de fragmentos de ejemplo
<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>
Aquí se explica cómo agregar un atributo a su BufferGeometry
y crear una instancia del 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 );
Luego, en su ciclo de renderizado, configure la fracción deseada para procesar:
mesh.material.uniforms.fraction.value = 0.5 * ( 1 + Math.cos( t ) );
violín: http://jsfiddle.net/m99aj10b/
three.js r.76