=================================
=================================
=================================
출처: https://stackoverflow.com/questions/31399856/drawing-a-line-with-three-js-dynamically
This is what I'd like to achieve (a modifiable polygon where the red circles are vertices) and I'd like to build the polygon dynamically.
When initiating the geometry as
var geometry = new THREE.Geometry(); geometry.vertices.push(point); geometry.vertices.push(point); var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({}));
it works well until the second click, it builds a straight line between 1 and 2 but does not add a third line when it's pushed to the array. WebGL seems to require buffered points.
When I predefine vertices like this I can draw two lines (third click)
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({}));
but this is not a good solution as I don't know how many vertices does the user want to add and it's pointless to assign it a big number as I have to loop it multiple times.
Is there any way around it?
----------------------------------------------------------------------------------------------------------------------------------------------------------------
You can animate a line -- or increase the number of points rendered -- very easily using BufferGeometry
and the setDrawRange()
method. You do need to set a maximum number of points, however.
var MAX_POINTS = 500; // geometry var geometry = new THREE.BufferGeometry(); // attributes var positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); // draw range drawCount = 2; // draw the first 2 points, only geometry.setDrawRange( 0, drawCount ); // material var material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); // line line = new THREE.Line( geometry, material ); scene.add( line );
You set the position data using a pattern like this one:
var positions = line.geometry.attributes.position.array; var x = y = z = index = 0; for ( var i = 0, l = MAX_POINTS; i < l; i ++ ) { positions[ index ++ ] = x; positions[ index ++ ] = y; positions[ index ++ ] = z; x += ( Math.random() - 0.5 ) * 30; y += ( Math.random() - 0.5 ) * 30; z += ( Math.random() - 0.5 ) * 30; }
If you want to change the number of points rendered after the first render, do this:
line.geometry.setDrawRange( 0, newValue );
If you want to change the position data values after the first render, you set the needsUpdate
flag like so:
line.geometry.attributes.position.needsUpdate = true; // required after the first render
Here is a fiddle showing an animated line which you can adapt to your use case.
EDIT: See this answer for a technique that you may like better -- especially if the line consists of only a few points.
three.js r.84
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
I updated the fiddle with mouse events and a vector array if you want to scribble freehand.
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); }
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Draw a line in real time
Here an updated fiddle where I optimized the code from user3325025 his example; In this case there is absolutely no need to update all the points of the line on render. Update is only needed onMouseMove
(updating end of line) and onMouseDown
(drawing new point):
// 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(); }
=================================
=================================
=================================
출처: https://stackoverflow.com/questions/22941632/how-to-draw-a-line-segment-at-run-time-using-three-js
How to draw a line segment at run time using three.js
three.js is mainly for drawing in 3D. If you want to copy a 2D drawing application like paint then using the 2D canvas will probably be easier: canvas.getContext("2d");
.
I will assume that you do want to draw in three.js. In which case I have put together this example. Follow these steps:
- Click anywhere on the page and drag the mouse around to draw a line. The line is drawn on the z plane.
- Click the Shapes button and notice how one shape is closer in and the other further, that is because one is above the z plane and the other behind.
- Click the Rotate button, this will cause the camera to zoom out and rotate around the axes. Notice that when you pass through the z plane all your drawing is on that plane.
Have a look at the code, the main parts are:
You need to project the mouse click coordinates onto the plane. This is done with this function:
function get3dPointZAxis(event) { var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); projector.unprojectVector( vector, camera ); var dir = vector.sub( camera.position ).normalize(); var distance = - camera.position.z / dir.z; var pos = camera.position.clone().add( dir.multiplyScalar( distance ) ); return pos; }
Then draw the line from previous to this point:
geometry.vertices.push(lastPoint); geometry.vertices.push(pos); var line = new THREE.Line(geometry, material); scene.add(line);
Note that when you get close to passing through the z plane while rotating, the projection to Z is very far off and you go out of bounds, to prevent this the following check is done:
if( Math.abs(lastPoint.x - pos.x) < 500 && Math.abs(lastPoint.y - pos.y) < 500 && Math.abs(lastPoint.z - pos.z) < 500 )
For reference, I found information for projecting the mouse coordinate here (SO answer) and here(three.js sample).
Update
To draw a line from the mousedown position to the mouseup position see this demo. The code changes are to instead just do the draw between points on mouse up.
function stopDraw(event) { if( lastPoint ) { var pos = get3dPointZAxis(event); var material = new THREE.LineBasicMaterial({ color: 0x0000ff }); var geometry = new THREE.Geometry(); if( Math.abs(lastPoint.x - pos.x) < 2000 && Math.abs(lastPoint.y - pos.y) < 2000 && Math.abs(lastPoint.z - pos.z) < 2000 ) { geometry.vertices.push(lastPoint); geometry.vertices.push(pos); var line = new THREE.Line(geometry, material); scene.add(line); lastPoint = pos; } else { console.debug(lastPoint.x.toString() + ':' + lastPoint.y.toString() + ':' + lastPoint.z.toString() + ':' + pos.x.toString() + ':' + pos.y.toString() + ':' + pos.z.toString()); } } }
Thanks a lot! The example gave a lot of idea. I was looking for drawing a straight line. The example gives effect of using a pen/pencil in Paint and not a line. Could u tell me how I can transform the above code to accomplish drawing a straight line from mouse down till mouse up event. Thanks in advance. – user3359133Apr 11 '14 at 13:52
|
|||
|
|||
|
okay! Now I see. Thanks a ton! One doubt remains, that is, how to implement this code in the x-y plane? I know it is trivial, but I'm unable to get the result :( – user3359133 Apr 13 '14 at 17:11
|
||
|
@user3359133 The line will be drawn at z=0 which is the xy plane. If you mean how do you do this with just 2D then you should use the html 5 Canvas and not three.js. You would then use
canvas.getContext("2d"); and LineTo . See html5canvastutorials.com/tutorials/html5-canvas-lines and html5canvastutorials.com/tutorials/html5-canvas-line-caps and tutorialspoint.com/html5/canvas_drawing_lines.htm. – acarlon Apr 13 '14 at 21:23 |
||
|
=================================
=================================
=================================
'WEB > WebGL' 카테고리의 다른 글
[WebGL] Three.js - GUI 관련 텍스트입력 TextEdit 슬라이드 등등(canvas, css3d 다른것들도 응용링크) (0) | 2017.12.13 |
---|---|
[WebGL] Three.js - 마우스 위치, 이벤트 관련 (0) | 2017.11.14 |
[WebGL] WebGL FBO(Frame Buffer Object) 관련 (0) | 2017.11.13 |
[WebGL] Three.js - Three FBO(Frame Buffer Object) 관련 (0) | 2017.11.13 |
[WebGL] Three.js - Texture 로드, HREE.TextureLoader(), THREE.ImageUtils.loadTexture 관련 (0) | 2017.11.06 |