我想做个3D编辑器(一) 画线成墙

栏目: 后端 · 发布时间: 5年前

内容简介:之前,因为公司一个项目需要3D的楼层,于是入了3D的坑。后面封装了墙的函数等等,但是通过PS去量设计图,获取墙的点数据,把我自己搞的真的恶心了。项目完成后,随着自己技术能力的提升,突然间想到为啥,我不用canvas照着设计稿画线,然后获取canvas上面的点数据?于是诞生了我这个标题!!!canvas,vue,three.js

之前,因为公司一个项目需要3D的楼层,于是入了3D的坑。后面封装了墙的函数等等,但是通过PS去量设计图,获取墙的点数据,把我自己搞的真的恶心了。项目完成后,随着自己技术能力的提升,突然间想到为啥,我不用canvas照着设计稿画线,然后获取canvas上面的点数据?于是诞生了我这个标题!!!

一、使用到的技术

canvas,vue,three.js

二、大概效果

我想做个3D编辑器(一) 画线成墙 我想做个3D编辑器(一) 画线成墙

目前的效果,在画布中画线,然后保存点数据,再在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。

我想做个3D编辑器(一) 画线成墙

three.js 中的坐标和camera相机有关。一般是y轴向上的3D坐标。(下图第一个)

我想做个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编辑器(一) 画线成墙》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Internet与WWW程序设计教程(第三版)

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程序设计教程(第三版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试