使用three.js动态绘制一条直线

28
这是我想要实现的(一个可修改的多边形,红色圆圈表示顶点),我希望能够动态地构建多边形。

输入图像描述

初始化几何图形时

var geometry = new THREE.Geometry();

geometry.vertices.push(point);
geometry.vertices.push(point);

var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({}));

第一次点击有效,可以在1和2之间绘制一条直线,但是当第二次点击时不会添加第三条线到数组中。WebGL似乎需要缓冲点。

如果我像这样预定义顶点,则可以绘制两条线(第三次点击)

var geometry = new THREE.Geometry();

for (var i = 0; i < 4; i++) {
    geometry.vertices.push(point);
}

var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({}));

但这不是一个好的解决方案,因为我不知道用户想添加多少个顶点,把大数字赋给它也是无意义的,因为我还需要多次循环。

有没有其他方法可以解决这个问题?

3个回答

48
使用BufferGeometrysetDrawRange()方法,您可以轻松地动画化一条线或增加渲染的点数。但是,您需要设置最大点数。
const MAX_POINTS = 500;

// geometry
const geometry = new THREE.BufferGeometry();

// attributes
const positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

// drawcalls
drawCount = 2; // draw the first 2 points, only
geometry.setDrawRange( 0, drawCount );

// material
const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );

// line
line = new THREE.Line( geometry,  material );
scene.add( line );


如果您想在第一次渲染后更改呈现的点数,请执行以下操作:
line.geometry.setDrawRange( 0, newValue );

如果您想在第一次渲染后更改位置数据值,则可以设置needsUpdate标志,如下所示:
line.geometry.attributes.position.needsUpdate = true; // required after the first render

这里有一个动态线条的示例,你可以根据自己的需求进行调整。

three.js r.147


MAX_POINTS = 500; 的意思是,如果用户创建的点超过了500个,程序就会崩溃,对吗?最好的情况是我不需要预定义要添加多少个点。虽然你的解决方案比我的更好,因为 BufferGeometry 更节省内存,并且使用更少的绘制调用。 - user3960875
@WestLangley 这个能否改用LineDashedMaterial?我想做类似的但是带虚线,如果可行我会开一个问题。 - Neil
@Neil 是的。您需要添加一个额外的几何属性 lineDistance 来适应 LineDashedMaterial - WestLangley
我不会一开始就分配500个点,然后担心是否足够... 相反,我会将其分成更小的BufferGeometry块,比如每个100个点。一旦你用完了所有的100个点,你就为另外100个点和另一个线段添加另一个BufferGeometry。这样,你可以不断地添加新的点而没有任何限制。 - Pete
这个代码示例如何回答问题?OP正在寻找用户交互。该代码仅显示如何渲染一条线;而不是绘制和编辑。代朋友询问!! - user5161995
显示剩余2条评论

13

实时绘制一条线

这里有一个更新的代码片段,我优化了user3325025的示例代码;在这种情况下,没有必要在渲染时更新线的所有点。只需要在onMouseMove(更新线的末端)和onMouseDown(绘制新点)时更新即可:

// update line
function updateLine() {
  positions[count * 3 - 3] = mouse.x;
  positions[count * 3 - 2] = mouse.y;
  positions[count * 3 - 1] = mouse.z;
  line.geometry.attributes.position.needsUpdate = true;
}

// mouse move handler
function onMouseMove(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  mouse.z = 0;
  mouse.unproject(camera);
  if( count !== 0 ){
    updateLine();
  }
}

// add point
function addPoint(event){
  positions[count * 3 + 0] = mouse.x;
  positions[count * 3 + 1] = mouse.y;
  positions[count * 3 + 2] = mouse.z;
  count++;
  line.geometry.setDrawRange(0, count);
  updateLine();
}

8

我更新了这个代码片段,加入了鼠标事件和向量数组,如果你想要手写涂鸦的话。

https://jsfiddle.net/w67tzfhx/40/

function onMouseDown(evt) {

    if(evt.which == 3) return;


    var x = ( event.clientX / window.innerWidth ) * 2 - 1;
    var y =  - ( event.clientY / window.innerHeight ) * 2 + 1;

    // do not register if right mouse button is pressed.

    var vNow = new THREE.Vector3(x, y, 0);
    vNow.unproject(camera);
    console.log(vNow.x + " " + vNow.y+  " " + vNow.z); 
    splineArray.push(vNow);

    document.addEventListener("mousemove",onMouseMove,false);
    document.addEventListener("mouseup",onMouseUp,false);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接