内容简介:之前,因为公司一个项目需要3D的楼层,于是入了3D的坑。后面封装了墙的函数等等,但是通过PS去量设计图,获取墙的点数据,把我自己搞的真的恶心了。项目完成后,随着自己技术能力的提升,突然间想到为啥,我不用canvas照着设计稿画线,然后获取canvas上面的点数据?于是诞生了我这个标题!!!canvas,vue,three.js
之前,因为公司一个项目需要3D的楼层,于是入了3D的坑。后面封装了墙的函数等等,但是通过PS去量设计图,获取墙的点数据,把我自己搞的真的恶心了。项目完成后,随着自己技术能力的提升,突然间想到为啥,我不用canvas照着设计稿画线,然后获取canvas上面的点数据?于是诞生了我这个标题!!!
一、使用到的技术
canvas,vue,three.js
二、大概效果
目前的效果,在画布中画线,然后保存点数据,再在3D中通过点数据生成墙;
三、实现
(1)canvas部分;
canvas部分的功能:鼠标画线,采集线2端的点数据。
<canvas v-show="canvasShow" id="canvas" ref= "canvas" @mousedown="canvsClick($event)" @mousemove="drawMove($event)" @mouseup="drawEnd($event)"></canvas>复制代码
参数
ctx:null, //储存画笔 lines:[], //储存点 linesNow:{ //当前线(正在画的) sX:0, //鼠标按下点的横坐标 sY:0, //鼠标按下点的纵坐标 eX:0, //鼠标松开点的横坐标 eY:0 //鼠标松开点的纵坐标 }, isLine :true, //后面可能会添加模型等等;目前只有‘线’ Down:false, //是不是鼠标按下的状态 复制代码
初始化canvas
//canvas渲染 初始化canvas render:function(){ var myCanvas = this.$refs.canvas; myCanvas.width = window.innerWidth; myCanvas.height = window.innerHeight; this.ctx = myCanvas.getContext("2d"); }, 复制代码
鼠标事件,在this.lines中储存点数据
//鼠标按下 canvsClick:function($event){ this.Down = true; //假设默认是画线的状态 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; //一条线画完,将点数据存入 lines数组,清空linesNow; //如果几乎没画, 不添加点(初始点和结束点距离太近) if(Math.abs(this.linesNow.eX-this.linesNow.sX)<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 }; }, 复制代码
绘制canvas中的线条
//循环渲染(鼠标画线的动画) animated:function(){ //在canvas环境下 if(!this.canvasShow){ return; } //清除画布,重绘 this.ctx.clearRect(0,0,this.$refs.canvas.width,this.$refs.canvas.height); this.drawLines(); //循环 requestAnimationFrame(this.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();//开始路径 this.ctx.moveTo(lines.sX,lines.sY);//定义路径起始点 this.ctx.lineTo(lines.eX,lines.eY);//路径的去向 this.ctx.closePath(); this.ctx.stroke(); },复制代码
(2)three.js部分
初始化3d渲染器及相关设置(场景,相机,光)
//初始换3D渲染器 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); //加载3D基础环境 this.initCamera(); this.initScene(); this.initLight(); this.initStats(); //drawBoxs画墙 this.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,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); }, //初始化(性能监测) initStats:function() { this.stats = new Stats(); document.body.appendChild(this.stats.dom); }, 复制代码
物体及基础场景(地板等)
drawBoxs:function(){ //基础3D环境 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)); 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 mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 4000, 4000 ), 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 ); grid.material.opacity = 0.2; grid.material.transparent = true; this.scene.add( grid ); },复制代码
循环渲染3d场景
//循环渲染3D animate2:function() { if(this.canvasShow){ return; } //更新性能插件 this.stats.update(); this.renderer.render(this.scene, this.camera); requestAnimationFrame(this.animate2); }, 复制代码
(3)点击生成3D操作,及坐标转化
canvas的坐标是以左上角为默认(0,0)点。同时canvas宽高默认300*300。
three.js 中的坐标和camera相机有关。一般是y轴向上的3D坐标。(下图第一个)
于是,在点击生成3D的时候需要对我们存的点数据进行处理。当然也可以对canvas坐标系进行处理。(我采取的是处理点数据)(由于,我three.js内的参数设置的和canvas生成的点的数据差不多,于是我就省略了一步点数据缩放的步骤)
//按钮,生成3d;(同时启动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; }, 复制代码
总结
其实,我这次只是实现了基础的线生成墙的功能,比较low,大家将就看。
下次,我准备把‘线的选中’,‘线的移动’,‘线的删除’,‘3D墙的集成’等功能加进去。
github地址:https://github.com/baiDog/something/blob/master/pages/2019_3/2019_3_19.html
以上所述就是小编给大家介绍的《我想做个3D编辑器(一) 画线成墙》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 我做编辑器这些年:钉钉文档编辑器的前世今生
- 有爱编辑器 1.7.1 发布,mysql 编辑器 GUI
- 小书匠编辑器 6.0.0 发布,好用的 Markdown 编辑器
- 小书匠编辑器 6.0.0 发布,好用的 Markdown 编辑器
- 10个最佳富文本编辑器
- 在线代码编辑器利器-codeMirror
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Internet与WWW程序设计教程(第三版)
戴特尔 / 电子工业出版社 / 2005-8 / 95.00元
《Internet与WWW程序设计教程》(第3版)以大量生动、实用的示例讲述了如何编写多层的、客户/服务器的、数据密集的、基于Web的应用程序,介绍了如何使用XHTML、JavaScript、DHTML、Flash和XML建立客户端应用程序,也介绍了如何使用Web服务器(IIS、PWS和Apache)、数据库(SQL、MySQL、DBI和ADO)、ASP、Perl、CGI、Python、PHP、J......一起来看看 《Internet与WWW程序设计教程(第三版)》 这本书的介绍吧!