Laya2 autosync cullingMask scheme and light clipping patch

This article solves two issues, the code at the end

1. Laya's U3D export tool can't export the cullingMask of the camera and Light. It needs to be set up manually every time, which makes it easy for the editor to be out of sync with the code.

2. Laya's Light rendering has no cullingMask tag, all light sources will work on all objects.

Recently, I switched a previous 2D project to a 3D version.Seeing Laya2.0, you can almost achieve the same effect in U3D and Laya, and you're decisively in the hole.After all, there's nothing to say about the stability of the U3D editor.

1. My needs are as follows:

1. A camera (perspective projection) to render the desktop

2. A camera (orthogonal projection) is used to render hand cards.

3. Light also needs to be adjusted separately.

When I edited the effect, I was foolish the first time I loaded the scene, everything was shown in LAYA.I feel like cullingMask was not synchronized.

After consulting the document, you can add it on your own through code.

The encoding test found that the function was OK, so I came up with a way to build a child object for Camera and mark the cullingMask of Camera with the name of the child object (initially you wanted to use a name, but if you marked it with a name, it would be difficult to get the object by name.)

For example, our cullingMask is required in addition to the UI layer.Then the child object name is culling_mask=all|!ui

If our cullingMask is, as long as the UI and FX layers are present, then the child object name is culling_mask='ui|fx'

As shown in the image below, I added culling_mask subobject to both the camera and the light, which is deleted from the code to avoid performance degradation.

Next, I noticed that the light was wrong.In U3D, I use a single light for my hand, a point light source and a directional light for my desktop.

Once I understand what's going on, I go to Laya.SpotLight, Laya.DirectionLight, and cullingMask of Laya.PointLight.Unexpectedly, there is no such thing.

So I started doing this, and after reading the code, I found that both rendering and camera clipping are in the file laya.d3.js.

After looking at the code related to lighting, we found that LAYA has done a lot of work on single and multiple light source management, especially Cluster optimization for multiple light sources.In between not familiar with the source code, afraid of error.So I gave up the idea of clipping objects with light sources and made a compromise.

The cullingMask scheme of the light source is roughly described below.

1. The cullingMask of the camera will clip off objects that are not part of the current camera

2. We assume that all objects rendered by the current camera are illuminated

3. Control the light source according to the cullingMask of the camera.

Although fine control is not achieved, in general, the light sources can be classified using the camera.


Figure 1 shows the effect in U3D and Figure 2 shows the effect in LAYA.

The complete code is as follows:ExtCullingMask.ts

 * Function: LAYA Light Layer Clipping Function
 * Author Kirinzi
 * Usage Description
	1,Camera.render function found in laya.d3.js
	2,render Function, this._prepareCameraToRender(); add the following code after this line
	if(this._scene.lightCullingMask && this._scene.lightCullingMask instanceof Function){this._scene.lightCullingMask(scene,this);}
	3,Call LightCullingMask.enableLightCullingMask(scene3d) for the scene you want to turn on light clipping

	//Be careful
	ExtCullingMask Not for the object, but for the camera.So make sure to be the same as the camera.

export default class ExtCullingMask {
	public static enableLightCullingMask(scene: Laya.Scene3D) {
		//var proto = Laya.Scene3D.prototype as any;
		(scene as any).lightCullingMask = function (scene, camera) {
			//Lighting started to add Kirin
			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); = (camera.cullingMask & layerMask) && (light.cullingMask & layerMask);
					if ( {
			//Lighting End Kirin Add

	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( == 0){
				layerNodeName =,'');

		let arr = layerNodeName.split('|');
		for(let i = 0; i < arr.length; ++i){
			let layerStr = arr[i] as string;
			if(layerStr == 'all'){
				let bRemove = layerStr.indexOf('!') == 0;
					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.');

	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));


229 original articles published, 542 awarded, 118,000 visits+
His message board follow

Tags: encoding

Posted on Fri, 10 Jan 2020 19:49:28 -0500 by dizel247