【问题标题】:Line disappear when camera move in three js相机在三个js中移动时线条消失
【发布时间】:2017-09-10 09:45:11
【问题描述】:

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

中也被调用
controls.addEventListener('change', () => {this.redraw()});

但是当我移动相机时,一些线条消失了,当我靠近时,似乎最糟糕,而且看起来没有任何规则,即使我靠近图形,看起来线条消失是随机选择。

有一行

这是如果我稍微移动相机的角度

这是来自图表的一侧:

这是来自其他人的时间:

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

【问题讨论】:

    标签: javascript typescript graph 3d three.js


    【解决方案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) 在一次绘制调用中渲染所有片段显然是一种改进。 (2) 对您的问题的一种可能解释是,当您更新几何的顶点时,您应该调用geometry.computeBoundingSphere()。渲染器在第一次渲染调用时为您调用它,但之后,如果您修改顶点,则边界球体不再正确,您需要对其进行更新。或者,您可以设置mesh.frustumCulled = false;
    【解决方案2】:

    我正在寻找的实际答案在上面来自WestLangley 的评论中。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-16
      • 2016-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-28
      • 2014-08-17
      • 2017-03-14
      相关资源
      最近更新 更多