Before, because a project of the company needed a 3D floor, so I fell into the 3D pit. Behind encapsulates the function of the wall and so on, but through PS to measure the design drawing, to obtain the point data of the wall, I made myself really sick. After the completion of the project, with the improvement of my technical ability, IT suddenly occurred to me why I did not use canvas to draw lines according to the design draft and then obtain the point data on canvas? So I came down to do it myself.

First, the technology used

canvas,vue,three.js

Two, the general effect

The current effect is to draw lines on the canvas, then save the point data, and then generate the wall from the point data in 3D;

Three, implementation,

(1) Canvas part;

Functions of Canvas: Draw lines with mouse and collect data of points at the end of line 2.

<canvas v-show="canvasShow" id="canvas" ref= "canvas" @mousedown="canvsClick($event)" @mousemove="drawMove($event)" @mouseup="drawEnd($event)"></canvas>
Copy the code

parameter

CTX :null, // Store pen lines:[], // store point linesNow:{// sX:0, // mouse point eX:0, // mouse point eX:0, }, isLine :true, // May add models and so on; Currently only 'line' Down:false, // is not the state of the mouse DownCopy the code

Initialize the canvas

Canvas render:function(){var myCanvas = this.$refs.canvas; myCanvas.width = window.innerWidth; myCanvas.height = window.innerHeight; this.ctx = myCanvas.getContext("2d"); },Copy the code

Mouse event that stores point data in this.lines

CanvsClick :function($event){this.Down = true; If (this.isline){this.linesnow.sx = $event.pagex; if(this.isline){this.linesnow.sx = $event.pagex; this.linesNow.sY = $event.pageY; this.linesNow.eX = $event.pageX; this.linesNow.eY = $event.pageY; }}, // drawMove:function(e){if(this.down){this.linesnow. eX = e.pagex; this.linesNow.eY = e.pageY; }else{ return; }}, // drawEnd:function(){this.down = false; // When a line is drawn, store the point data into the Lines array and empty linesNow; // If there is almost no drawing, If (math.abs (this.linesnow.ex - this.linesnow.sx)<5 && math.abs (this.linesnow.ey-this.linesnow.sy)<5){math.abs (this.linesnow.ey-this.linesnow.sy)<5){ }else{ this.lines.push(JSON.parse(JSON.stringify(this.linesNow))); } this.linesNow={ sX:0, sY:0, eX:0, eY:0 }; },Copy the code

Draw lines in the canvas

// Animated :function(){// On canvas if(! this.canvasShow){ return; } // clear the canvas and redraw this.ctx.clearrect (0,0,this.$refs.canvas. Width,this.$refs.canvas. Height); this.drawLines(); / / loop requestAnimationFrame (enclosing animated); }, // drawLines:function(){var _this= this; if(this.Down){ this.drawLine(this.linesNow); } this.lines.map(function(v,i){ _this.drawLine(v); }); }, // drawLine:function(lines){this.ctx.beginPath(); // start path this.ctx.moveto (lines.sx, lines.sy); // Start path this.ctx.moveto (lines.sx, lines.sy); // define the path start point this.ctx.lineto (lines.ex, lines.ey); This.ctx.closepath (); this.ctx.closepath (); this.ctx.stroke(); },Copy the code

(2) The three.js part

Initialize the 3D renderer and related Settings (scene, camera, light)

Render2 :function(){this.renderer = new three. WebGLRenderer({antialias: true}); let renderer = this.renderer; renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0xeeeeee); renderer.shadowMap.enabled = true; Document.getelementbyid ("app").appendChild(renderer.domElement); // Load the base 3D environment this.initCamera(); this.initScene(); this.initLight(); this.initStats(); / / drawBoxs HuaQiang enclosing drawBoxs (); }, // initCamera:function() {this.camera = new three.perspectivecamera (45, Window.innerwidth/window.innerheight, 0.1, 2000); this.camera.position.set(0, 450, 800 ); This. Camera. LookAt (0, 0); }, // initScene:function() {this.scene = new three.scene (); this.scene.background = new THREE.Color( 0xa0a0a0 ); this.scene.fog = new THREE.Fog( 0xa0a0a0, 5, 1600 ); }, // initLight:function() {this.scene.add(new three.ambientlight (0x444444)); this.light = new THREE.DirectionalLight(0xffffff); let light = this.light; light.position.set(0, 200, 100 ); light.castShadow = true; light.shadow.camera.top = 10; light.shadow.camera.bottom = -10; light.shadow.camera.left = -10; light.shadow.camera.right = 10; Light. CastShadow = true; this.scene.add(light); }, // initialize (performance monitor) initStats:function() {this.stats = new stats (); document.body.appendChild(this.stats.dom); },Copy the code

Objects and base scenes (floors, etc.)

DrawBoxs :function(){this.drawbasebg (); var _this = this; this.lines.map(function(v,i){ _this.drawWall(v); })}, DrawWall :function(objs){let lens = math.sqrt (math.pow ((Number(objs.ey) - Number(objs.sy)),2) + Math.pow((Number(objs.eX) - Number(objs.sX)),2) ); // let posx = (objs.ex + objs.sx)/2; let posz = (objs.eY+objs.sY)/2; Let rotate = -math.atan2 ((objs.ey-objs.sy),(objs.ex-objs.sx)); // Let rotate = -math.atan2 ((objs.ey-objs.sy),(objs.ex-objs.sx)); console.log(Math.atan2((objs.eY-objs.sY),(objs.eX-objs.sX))) let box = new THREE.CubeGeometry(lens,this.wallHei,this.wallWid); var material = new THREE.MeshBasicMaterial({color:0xcccccc}); var mesh = new THREE.Mesh(box,material); mesh.position.set(posx,this.wallHei/2,posz); mesh.rotation.y = rotate; this.scene.add(mesh); }, drawBaseBg:function(){var helper = new three.axeshelper (200); this.scene.add(helper); / var/floor mesh = new THREE. Mesh (new THREE. PlaneBufferGeometry (4000, 4000), a new THREE. MeshPhongMaterial ({color: 0xffffff, depthWrite: false } ) ); mesh.rotation.x = - Math.PI / 2; mesh.receiveShadow = true; this.scene.add( mesh ); Var grid = new three. GridHelper(2000, 50, 0x000000, 0x000000); The grid. The material. The opacity = 0.2; grid.material.transparent = true; this.scene.add( grid ); },Copy the code

Loop render 3d scenes

Animate2 :function() {if(this.canvasshow){return; } // Update the performance plugin this.stats.update(); this.renderer.render(this.scene, this.camera); requestAnimationFrame(this.animate2); },Copy the code

(3) Click to generate 3D operation and coordinate transformation

The canvas coordinates are the default (0,0) point in the top left corner. The default width and height of canvas is 300*300.

The coordinates in three.js are related to the camera camera. It’s usually a 3D coordinate up the y axis. (The first one below)

Therefore, when clicking to generate 3D, we need to process the point data we save. Of course, canvas coordinate system can also be processed. (What I take is to process point data) (Since the parameter Settings in my three.js are similar to the point data generated by canvas, I skip the step of point data scaling)

// button to generate 3D; Create3d :function(){var _this = this; let res =this.linesC(this.lines); res.map(function(v,i){ _this.drawWall(v); }); this.animate2(); }, // linesC:function(lines){let res = []; let wWid = window.innerWidth,wHei = window.innerHeight; let _this = this; lines.map(function(v,i){ let obj = { sX:Number(v.sX)-wWid/2, sY:Number(v.sY)-wHei/2, eX:Number(v.eX)-wWid/2, eY:Number(v.eY)-wHei/2, } res.push(obj); }); return res; },Copy the code

conclusion

In fact, I just realized the basic line wall function, relatively low, we will see.

Next time, I plan to add ‘line selection’, ‘line movement’, ‘line deletion’, ‘3D wall integration’ and other functions.

Github address: github.com/baiDog/some…