BufferGeometry创建粒子z-index

时间:2017-11-14 07:48:12

标签: javascript three.js glsl webgl

我用三个BufferGeometry创建了两个粒子,我想点击每个粒子显示相应的图像。

但是当我点击粒子时,图像被显示出来,另一个粒子覆盖了它。

我想知道如何让粒子脱离层次结构的控制,并使点击的粒子始终位于顶部。

代码:`

var scene, camera, renderer,controls;
var points;
var shaderMaterial;

var particleCount = 2;

function init () {
      scene = new THREE.Scene();

      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.x = 15;
      camera.position.y = 16;
      camera.position.z = 35;
      camera.lookAt(scene.position);

      renderer = new THREE.WebGLRenderer();

      renderer.setClearColor(0x000000, 1.0);

      renderer.setSize(window.innerWidth, window.innerHeight);

      var light = new THREE.AmbientLight( 0xcccccc );

      scene.add(light);

      document.body.appendChild(renderer.domElement);

      createParticles();

      createGrid();

      render();

      document.querySelector('canvas').addEventListener( 'click', interactive, false );

  }

function createParticles () {
    var geometry = new THREE.BufferGeometry();
    var positions = new Float32Array( particleCount * 3 );
    var sizes = new Float32Array( particleCount );
    var pop = new Float32Array( particleCount);

     for (var i = 0, i3 = 0; i < particleCount; i ++, i3 += 3) {
         positions[i3 + 0] = i* 10;
         positions[i3 + 1] = 0.1;
         positions[i3 + 2] = 1;

         sizes[i] = 15;
         pop[i] = 0.0;
     }

    geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    geometry.addAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );
    geometry.addAttribute( 'pop', new THREE.BufferAttribute( pop, 1 ) );

    shaderMaterial = new THREE.ShaderMaterial({
        uniforms: {
            'u_time': {type: 'f', value: 1.0},
            'u_texture_0':   { value: new THREE.TextureLoader().load('https://avatars2.githubusercontent.com/u/5829050?s=256&v=4') }},
        vertexShader:   document.getElementById( 'vs' ).textContent,
        fragmentShader: document.getElementById( 'fs' ).textContent,
        // blending:       THREE.AdditiveBlending,
        depthTest:      false,
        transparent:    true
    });
    shaderMaterial.uniforms['u_texture_0'].value.flipY = false;

    points = new THREE.Points(geometry, shaderMaterial);

    scene.add(points);

}
var raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = 5;

var touch = new THREE.Vector2();
var intersects, INTERSECTED;
var beforeIndex;

function interactive (event) {
    touch.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    touch.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    points.geometry.computeBoundingSphere();
    camera.updateMatrixWorld();
    var vector = new THREE.Vector3(touch.x, touch.y, 0.5 ).unproject(camera);
    raycaster.set(camera.position, vector.sub(camera.position ).normalize());
    
    raycaster.setFromCamera( touch, camera );

    intersects = raycaster.intersectObject(points);
    if ( intersects.length > 0 ) {
        if ( INTERSECTED != intersects[ 0 ].index ) {
            INTERSECTED = intersects[ 0 ].index;
            if (beforeIndex != INTERSECTED) {
                points.geometry.attributes.pop.array[ beforeIndex ] = 0.0;
            }
            points.geometry.attributes.pop.array[ INTERSECTED ] = 1.0;

            beforeIndex = INTERSECTED;

        }
    }

    points.geometry.attributes.size.needsUpdate = true;
    points.geometry.attributes.pop.needsUpdate = true;
}
    
function createGrid () {
    var helper = new THREE.GridHelper( 100, 20, 0x303030, 0x303030 );
    scene.add( helper );
}
 function render () {

    renderer.render(scene, camera);

    requestAnimationFrame(render);
}
  
init();
* {
      margin: 0;
      padding: 0;
  }
  html, body {
      width: 100%;
      height: 100%;
      background: #000;
  }
  canvas {
      display: block;
  }
<script src="https://threejs.org/build/three.js"></script>
<script id="fs" type="x-shader/x-fragment">
    precision highp float;
    uniform sampler2D u_texture_0;
    uniform float u_time;
    varying float u_pop;

    void main () {
    vec2 uv = gl_PointCoord.xy;
    vec4 rval = texture2D(u_texture_0,uv);

    vec2 posToCenter = (uv - vec2(.5, .5)) * 2.0;
    float distanceToCenter = length(posToCenter);
    float fadeOpacity = 1. - smoothstep(0.8, 1., distanceToCenter);
    float opacity = (1. - step(0.8, distanceToCenter)) + fadeOpacity;

    vec3 bgColor = mix(vec3(255., 255., 255.), vec3(252., 222., 184.), distanceToCenter) / 255.;

    vec4 color = vec4(mix(bgColor, rval.rgb, u_pop), 1.);
    color.a = opacity;

    gl_FragColor = color;
}
</script>
<script type="x-shader/x-vertex" id="vs">
    attribute float size;
    attribute float pop;

    varying float u_pop;
    void main() {
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        gl_PointSize = size * ( 300.0 / -mvPosition.z );
        gl_Position = projectionMatrix * mvPosition;

        u_pop = pop;
    }
</script>

`

1 个答案:

答案 0 :(得分:2)

您对3D的工作方式存在误解,因此您使用了错误的概念和术语。 3D中没有“Z-Index”。有Z-buffer or Depth-buffer(两个名称,相同的东西),它反映了从渲染的角度(相机,虚拟观察者)的物距。自然,深度缓冲的深度测试的目的是防止最近的对象在最接近的对象前面渲染(这也允许通过防止看不见的像素来优化)。

此外,前景显示的背景不受任何层次结构的控制(除非引擎故意实现此类功能),对象只是按照提供的顺序进行渲染。如果禁用深度测试,则最新渲染的对象将显示在所有先前渲染的对象之前。在3D场景中,层次结构与转换相关,而不是显示顺序(除非对象以场景的层次结构顺序呈现而不进行深度测试)。

要以强大的方式实现您想要的效果,您必须禁用深度目标并手动控制渲染精灵的顺序,以确保必须处于“前”的那个,是最后渲染的精灵。 。这是一个非常低级的操作,除非Three.JS允许你控制(我怀疑),你可能不得不改变你的策略,或者实现你自己的WebGL引擎。