当相机在三个js中移动时线消失

时间:2017-04-14 06:25:55

标签: javascript typescript graph 3d three.js

我正在尝试在three.js中渲染d3力图,我正在使用带有照片纹理的标准Line和BoxGeometry。在强制图更新时,我调用绘制函数,该函数也在

中调用

controls.addEventListener('change', () => {this.redraw()});

但是当我移动相机时,有些线条消失了 我更接近,看起来最糟糕,除了它看起来没有任何规则, 即使我接近图形,它看起来像是随意选择消失的线条。

有线是

enter image description here

这就是我将镜头移动了一点角度

enter image description here

这是图表的一侧:

enter image description here

这是来自其他人的时间:

enter image description here

I tried to scale down units

And also frustum = false

整个代码:

import {
    WebGLRenderer,
    Scene,
    PerspectiveCamera,
    Texture,
    MeshBasicMaterial,
    SphereGeometry,
    Mesh,
    Geometry,
    Vector3,
    LineBasicMaterial,
    Line,
    LineSegments,
    BoxGeometry,
    TextureLoader
} from 'three';

import * as three from 'three';

import { ViewModel, Link, Node } from './Model';
import { event } from 'd3-selection';
import * as selection from 'd3-selection';
import { drag } from 'd3-drag';

// Old module syntax
declare function require(name:String);

let OrbitControls = require('./../../../node_modules/three-orbit-controls/index')(three);

interface IView {
    render():void;
}

class ViewNode {
    public vector:Vector3;
    public mesh:Mesh;
    public node:Node;
}

export class Full3DView implements IView {
    private canvas: Element;

    private renderer: WebGLRenderer;

    private scene: Scene;

    private lineMaterial: LineBasicMaterial;

    private camera: PerspectiveCamera;

    private controls: any;

    private nodes:ViewNode[] = [];

    private lines:Geometry[] = [];

    constructor(private model:ViewModel) {
        this.canvas = document.querySelector('#view3d2');
        this.model.onChange(() => {this.render()});
    }

    render(): void {
        this.buildScene();
        this.model.simulation.on('tick', () => this.redraw());
        this.model.linkForce.distance(40);
        this.model.collideForce.radius(30);
    }

    private buildScene() {
        this.scene = new Scene();
        this.camera = new PerspectiveCamera( 90, window.innerWidth/window.innerHeight, 1, 20000 );

        this.renderer = new WebGLRenderer();
        this.renderer.setSize( this.canvas.clientWidth, this.canvas.clientHeight );
        this.canvas.appendChild( this.renderer.domElement );

        this.controls = new OrbitControls( this.camera, this.renderer.domElement);
        this.controls.addEventListener('change', () => {this.redraw()});

        this.lineMaterial = new LineBasicMaterial({ color: 0xccff00, linewidth: 3});

        let vectorIndex:Map<String, Vector3> = new Map();
        let textureLoader = new TextureLoader();

        this.model.nodes.forEach((node:Node) => {
            this.buildNode(vectorIndex, textureLoader, node);
        });

        this.model.links.forEach((link:Link) => {
            this.buildEdge(vectorIndex, link);
        });

        this.camera.position.z = 5000;
    }

    private buildNode(vectorIndex:Map<String, Vector3>, textureLoader:TextureLoader, node:Node) {
        let material = new MeshBasicMaterial();
        let geometry = new BoxGeometry( 30, 30, 30);
        let mesh = new Mesh( geometry, material );

        mesh.lookAt(this.camera.position);

        this.scene.add( mesh );

        mesh.position.set(node.x, node.y, 0);

        mesh.rotation.x += 1;

        vectorIndex.set(node.index, mesh.position);

        this.nodes.push({
            vector: mesh.position,
            mesh: mesh,
            node: node
        });

        textureLoader.load('/data/images/' + node.id + '.jpg', (texture:Texture) => {
            material.map = texture;
            material.needsUpdate = true;
        });
    }

    private buildEdge(vectorIndex:Map<String, Vector3>, link:Link) {
        let geometry = new Geometry();

        geometry.vertices.push(
       vectorIndex.get(link.source.index).copy(vectorIndex.get(link.source.index).setZ(0)),
            vectorIndex.get(link.target.index).copy(vectorIndex.get(link.target.index).setZ(0))
        );

        geometry.computeLineDistances();

        this.lines.push(geometry);

        let line = new Line(geometry, this.lineMaterial);
        this.scene.add(line);
    }

    private redraw() {
        this.nodes.forEach((node:ViewNode) => {
            node.vector.setX(node.node.x * 10);
            node.vector.setY(node.node.y * 10);
            node.mesh.lookAt(this.camera.position);
            node.mesh.frustumCulled = false;
        });

        this.lines.forEach((line:Geometry) => {
            line.verticesNeedUpdate = true;
        });

        this.renderer.render(this.scene, this.camera)
    }
}

2 个答案:

答案 0 :(得分:1)

我无法使用Line对象进行操作,但如果我使用LineSegments并将所有顶点对推到一个Geometry,则效果很好。

所以在函数buildScene中我使用而不是

this.lineMaterial = new LineBasicMaterial({ color: 0xccff00, linewidth: 3});

this.linesGeometry = new Geometry();
this.scene.add(new LineSegments(this.linesGeometry, new LineBasicMaterial({ color: 0xccff00, linewidth: 3})));

然后buildEdge的内容是

this.linesGeometry.vertices.push(
    vectorIndex.get(link.source.index).copy(vectorIndex.get(link.source.index).setZ(0)),
    vectorIndex.get(link.target.index).copy(vectorIndex.get(link.target.index).setZ(0))
);

并且在redraw函数中我只是做

this.linesGeometry.verticesNeedUpdate = true;

而不是

this.lines.forEach((line:Geometry) => {
    line.verticesNeedUpdate = true;
});

答案 1 :(得分:0)

我正在寻找的实际答案在上面enter image description here的评论中。

对该问题的一种可能解释是,更新几何图形的顶点时,应调用geometry.computeBoundingSphere()。渲染器在第一个渲染调用中为您调用它,但是之后,如果您修改顶点,则边界球不再正确,您需要对其进行更新。另外,您可以设置mesh.frustumCulled = false;