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

查看所有标签

猜你喜欢:

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

Clean Code

Clean Code

Robert C. Martin / Prentice Hall / 2008-8-11 / USD 49.99

Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code......一起来看看 《Clean Code》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

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

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具