Laya2自动同步cullingMask方案以及灯光裁剪补丁

本文解决了两个问题,代码在文末

1、Laya的U3D导出工具无法导出摄相机和Light的cullingMask,每次都要手工设置,容易出现编辑器与代码不同步的情况

2、Laya的Light渲染时,没有cullingMask标记,所有光源会对所有对象生效。


最近在将之前做的一个2D项目,换成3D版本。看到Laya2.0说,几乎可以做到U3D和Laya中效果一致,果断就入坑了。毕竟U3D编辑器的稳定性没得说。

一、我的需求如下:

1、一个相机(透视投影)用于渲染桌面

2、一个相机(正交投影)用于渲染手牌。

3、灯光也就需要单独调整。

当我编辑好效果后,第一次加载场景时就傻眼了,所有东西在LAYA中都显示出来了。 我就感觉应该是cullingMask没有同步导致的。

查阅文档后发现,可以通过代码来自行添加。https://ldc2.layabox.com/doc/?nav=zh-ts-4-5-10

编码测试后发现功能是OK的,于是我想了一个办法,为Camera建了一个子对象,通过子对象的名字来标记这个Camera的cullingMask(一开始是想用名字的,但用名字来标记的话,对象通过名字获取就困难了。)

比如,我们的cullingMask是 除了UI层,都需要。 那么子对象名称就是 culling_mask=all|!ui

如果我们的cullingMask是,只要ui和fx层,那么子对象名称就是 culling_mask='ui|fx'

如下图所示,我为摄相机和灯光都添加了culling_mask子对象,这个子对象会在代码中被删除,避免性能损耗。


接下来就发现灯光不对的。 在U3D中,我的手牌单独用了一个灯光,桌面用了一个点光源和一个方向光。

明白是怎么回事后,我就去找Laya.SpotLight,Laya.DirectionLight,Laya.PointLight的cullingMask。不出所料,果然没有这个东西。

于是就着手做这个事情,阅读代码后发现,渲染和相机裁剪都在laya.d3.js这个文件中。

看完灯光相关的代码后,发现LAYA在单光源和多光源管理上做了许多处理,特别是多光源做了Cluster优化。介于对源码不熟悉,怕出错。所以我放弃了光源对物体进行裁剪的想法,转而做了一个折衷的方案。

光源cullingMask方案大概描述如下。

1、摄相机的cullingMask会裁剪掉不属于当前摄相机的物体

2、我们假设当前相机渲染的所有物体都受光

3、根据摄相机的cullingMask进行光源的控制。

这样虽然达不到精细的控制,但总的来说,可以用摄相机对光源分类了。

 

图1为U3D中的效果,图2为LAYA中的效果。


完整代码如下:ExtCullingMask.ts

/**
 * 函数:LAYA 灯光Layer裁剪函数
 * 作者 麒麟子
 * 用法说明
	1、在laya.d3.js中找到Camera.render函数
	2、render函数中,this._prepareCameraToRender();这一行后面添加如下代码
	if(this._scene.lightCullingMask && this._scene.lightCullingMask instanceof Function){this._scene.lightCullingMask(scene,this);}
	3、对想要开启灯光裁剪的场景调用 LightCullingMask.enableLightCullingMask(scene3d)即可

	//注意
	ExtCullingMask并不是针对对象进行,而是对摄相机进行。因此务必保持与摄相机相同。
**/

export default class ExtCullingMask {
	public static enableLightCullingMask(scene: Laya.Scene3D) {
		//var proto = Laya.Scene3D.prototype as any;
		(scene as any).lightCullingMask = function (scene, camera) {
			//灯光处理开始 麒麟子添加
			var allLights = [];
			allLights = allLights.concat(scene._directionLights._elements);
			allLights = allLights.concat(scene._spotLights._elements);
			allLights = allLights.concat(scene._pointLights._elements);
			for (let i = 0; i < allLights.length; ++i) {
				let light = allLights[i];
				for (let layer = 0; layer < 32; ++layer) {
					let layerMask = Math.pow(2,layer);
					light.active = (camera.cullingMask & layerMask) && (light.cullingMask & layerMask);
					if (light.active) {
						break;
					}
				}
			}
			scene._prepareSceneToRender();
			//灯光处理结束 麒麟子添加
		}
	}

	public static disable(scene: Laya.Scene3D) {
		delete (scene as any).lightCullingMask;
	}

	private static _layerMap = {'ui':5}

	public static assignCullingMask(target){
		let layerNodeName = '';
		let prefix = 'culling_mask=';
		for(let i = 0; i < target.numChildren; ++i){
			let child = target.getChildAt(i);
			if(child.name.indexOf(prefix) == 0){
				layerNodeName = child.name.replace(prefix,'');
				child.destroy();
				break;
			}
		}
		if(!layerNodeName){
			return;
		}

		let arr = layerNodeName.split('|');
		this.removeAllLayers(target);
		for(let i = 0; i < arr.length; ++i){
			let layerStr = arr[i] as string;
			if(layerStr == 'all'){
				this.addAllLayers(target);
			}
			else{
				let bRemove = layerStr.indexOf('!') == 0;
				if(bRemove){
					layerStr = layerStr.substr(1);
				}
				let layer = this._layerMap[layerStr];
				if(layer === null || layer === undefined){
					console.log(layerNodeName + ' don not match the rule of layer node.');
					return;
				}
				if(bRemove){
					this.removeLayer(target,layer);
				}
				else{
					this.addLayer(target,layer);
				}
			}
		}
	}

	public static removeAllLayers(target) {
		target.cullingMask = 0;
	}

	public static addAllLayers(target) {
		target.cullingMask = 0x7FFFFFF;
	}

	public static addLayer(target, layer) {
		let mask = target.cullingMask || 0;
		target.cullingMask = mask | Math.pow(2,layer);
	}
	public static removeLayer(target, layer) {
		let mask = target.cullingMask || 0;
		target.cullingMask = mask & (~Math.pow(2,layer));
	}
}

 

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie
应支付0元
点击重新获取
扫码支付

支付成功即可阅读