PointsMesh.js 3.9 KB
import graphicGL from '../../util/graphicGL';
import verticesSortMixin from '../../util/geometry/verticesSortMixin';
import * as echarts from 'echarts/lib/echarts';
import glmatrix from 'claygl/src/dep/glmatrix';
var vec4 = glmatrix.vec4;

import sdfSpriteGLSL from './sdfSprite.glsl.js';
graphicGL.Shader.import(sdfSpriteGLSL);

var PointsMesh = graphicGL.Mesh.extend(function () {
    var geometry = new graphicGL.Geometry({
        dynamic: true,
        attributes: {
            color: new graphicGL.Geometry.Attribute('color', 'float', 4, 'COLOR'),
            position: new graphicGL.Geometry.Attribute('position', 'float', 3, 'POSITION'),
            size: new graphicGL.Geometry.Attribute('size', 'float', 1),
            prevPosition: new graphicGL.Geometry.Attribute('prevPosition', 'float', 3),
            prevSize: new graphicGL.Geometry.Attribute('prevSize', 'float', 1)
        }
    });
    Object.assign(geometry, verticesSortMixin);

    var material = new graphicGL.Material({
        shader: graphicGL.createShader('ecgl.sdfSprite'),
        transparent: true,
        depthMask: false
    });
    material.enableTexture('sprite');
    material.define('both', 'VERTEX_COLOR');
    material.define('both', 'VERTEX_SIZE');

    var sdfTexture = new graphicGL.Texture2D({
        image: document.createElement('canvas'),
        flipY: false
    });

    material.set('sprite', sdfTexture);

    // Custom pick methods.
    geometry.pick = this._pick.bind(this);

    return {
        geometry: geometry,
        material: material,
        mode: graphicGL.Mesh.POINTS,

        sizeScale: 1
    };
}, {

    _pick: function (x, y, renderer, camera, renderable, out) {
        var positionNDC = this._positionNDC;
        if (!positionNDC) {
            return;
        }

        var viewport = renderer.viewport;
        var ndcScaleX = 2 / viewport.width;
        var ndcScaleY = 2 / viewport.height;
        // From near to far. indices have been sorted.
        for (var i = this.geometry.vertexCount - 1; i >= 0; i--) {
            var idx;
            if (!this.geometry.indices) {
                idx = i;
            }
            else {
                idx = this.geometry.indices[i];
            }

            var cx = positionNDC[idx * 2];
            var cy = positionNDC[idx * 2 + 1];

            var size = this.geometry.attributes.size.get(idx) / this.sizeScale;
            var halfSize = size / 2;

            if (
                x > (cx - halfSize * ndcScaleX) && x < (cx + halfSize * ndcScaleX)
                && y > (cy - halfSize * ndcScaleY) && y < (cy + halfSize * ndcScaleY)
            ) {
                var point = new graphicGL.Vector3();
                var pointWorld = new graphicGL.Vector3();
                this.geometry.attributes.position.get(idx, point.array);
                graphicGL.Vector3.transformMat4(pointWorld, point, this.worldTransform);
                out.push({
                    vertexIndex: idx,
                    point: point,
                    pointWorld: pointWorld,
                    target: this,
                    distance: pointWorld.distance(camera.getWorldPosition())
                });
            }
        }
    },

    updateNDCPosition: function (worldViewProjection, is2D, api) {
        var positionNDC = this._positionNDC;
        var geometry = this.geometry;
        if (!positionNDC || positionNDC.length / 2 !== geometry.vertexCount) {
            positionNDC = this._positionNDC = new Float32Array(geometry.vertexCount * 2);
        }

        var pos = vec4.create();
        for (var i = 0; i < geometry.vertexCount; i++) {
            geometry.attributes.position.get(i, pos);
            pos[3] = 1;
            vec4.transformMat4(pos, pos, worldViewProjection.array);
            vec4.scale(pos, pos, 1 / pos[3]);

            positionNDC[i * 2] = pos[0];
            positionNDC[i * 2 + 1] = pos[1];
        }
    }
});

export default PointsMesh;