WEB/WebGL

[WebGL] Three.js - 선그리기 자유곡선 관련

AlrepondTech 2017. 11. 14. 00:03
반응형

 

 

=================================

=================================

=================================

 

 

 

출처: 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); }
shareimprove this answer

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

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(); }
shareimprove this answer

 

 

 

=================================

=================================

=================================

 

 

 

출처: 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

I am new to Three.js and I'm trying to implement the technique used in Microsoft Paint for drawing a line segment. I'm trying to get coordinates of a point onMouseDown then extend a line with onMouseMove until onMouseDown. Please help!
 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------

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:

  1. Click anywhere on the page and drag the mouse around to draw a line. The line is drawn on the z plane.
  2. 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.
  3. 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());         }     } }      
shareimprove this answer
 
 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
 
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
    
@user3359133 - see the update. – acarlon Apr 11 '14 at 21:47
    
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 
    
Thanks a lot :-) – user3359133 Apr 14 '14 at 12:46

 

-------------------------------------------
 

=================================

=================================

=================================

 

 

 

반응형