2017-04-14 86 views
0

我正在試着在three.js中呈現d3力圖,我使用帶有照片紋理的標準Line和BoxGeometry。在力圖表更新我叫畫功能,這也叫上當相機在三個j中移動時線會消失

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

,但是當我移動相機,一些線路disapear,當 我更近,似乎最壞的,除了它不看就像有任何規則,即使當我接近圖表時,它看起來像是隨機選擇disapear的線條。

有線是

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

回答

1

我無法得到它的工作使用Line對象,但如果我使用LineSegments並推送所有p頂點到一個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

(1)在一個單一的繪圖調用呈現所有段顯然是一種改進。 (2)對於你的問題可能的解釋是,當你更新幾何的頂點時,你應該調用'geometry.computeBoundingSphere()'。渲染器會在第一次渲染調用中爲您調用它,但在此之後,如果修改了頂點,則邊界球不再正確,您需要更新它。或者,您可以設置'mesh.frustumCulled = false'; – WestLangley

相關問題