Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

更新:2D灯光采用scene和stage共同作用的坐标系统,避免屏幕放缩时光影图覆盖不全 #1730

Merged
merged 1 commit into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions src/layaAir/laya/display/Scene2DSpecial/Light2D/BaseLight2D.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Laya } from "../../../../Laya";
import { ILaya } from "../../../../ILaya";
import { Component } from "../../../components/Component";
import { NodeFlags } from "../../../Const";
import { Event } from "../../../events/Event";
Expand Down Expand Up @@ -388,10 +388,11 @@ export class BaseLight2D extends Component {
protected _onDestroy() { }

/**
* @internal
* @en Response matrix change
* @zh 响应矩阵改变
*/
protected _transformChange() {
_transformChange() {
this._clearScreenCache();
this._needUpdateLightAndShadow = true;
this._needUpdateLightWorldRange = true;
Expand Down Expand Up @@ -522,11 +523,17 @@ export class BaseLight2D extends Component {

/**
* @en Get light scene position
* @zh 获取灯光位置的X坐标值(基于Scene
* @zh 获取灯光位置的X坐标值(基于scene和stage
* @param out
*/
getScenePos(out: Point) {
return this.owner.getScenePos(out);
this.owner.getScenePos(out);
const m = ILaya.stage.transform;
const x = m.a * out.x + m.c * out.y + m.tx;
const y = m.b * out.x + m.d * out.y + m.ty;
out.x = x;
out.y = y;
return out;
}

/**
Expand Down Expand Up @@ -606,36 +613,34 @@ export class BaseLight2D extends Component {
* 设置灯光放缩和旋转
*/
protected _lightScaleAndRotation() {
//获取放缩量(基于Scene
const p = Point.TEMP;
this.owner.getSceneScale(p);
const sx = Math.abs(p.x);
const sy = Math.abs(p.y);
//获取放缩量(基于scene和stage
const m = ILaya.stage.transform;
const p = this.owner.getSceneScale(Point.TEMP);
const sx = Math.abs(p.x * m.getScaleX());
const sy = Math.abs(p.y * m.getScaleY());

//设置灯光放缩
Vector2.TEMP.x = 1 / sx;
Vector2.TEMP.y = 1 / sy;
this.lightScale = Vector2.TEMP;

//设置灯光旋转(基于Scene
//设置灯光旋转(基于scene,stage没有旋转
this.lightRotation = this.owner.getSceneRotation() * Math.PI / 180;
}

/**
* @en Render light texture
* @param scene Scene object
* @zh 渲染灯光贴图
* @param scene 场景对象
*/
renderLightTexture(scene: Scene) {
renderLightTexture() {
//回收资源(每10帧回收一次)
if (Laya.timer.currFrame > this._recoverFC) {
if (ILaya.timer.currFrame > this._recoverFC) {
if (this._needToRecover.length > 0) {
for (let i = this._needToRecover.length - 1; i > -1; i--)
this._needToRecover[i].destroy();
this._needToRecover.length = 0;
}
this._recoverFC = Laya.timer.currFrame + 10;
this._recoverFC = ILaya.timer.currFrame + 10;
}
}

Expand Down
39 changes: 15 additions & 24 deletions src/layaAir/laya/display/Scene2DSpecial/Light2D/FreeformLight2D.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ILaya } from "../../../../ILaya";
import { LayaGL } from "../../../layagl/LayaGL";
import { Color } from "../../../maths/Color";
import { Matrix } from "../../../maths/Matrix";
Expand All @@ -14,7 +15,6 @@ import { Mesh2D } from "../../../resource/Mesh2D";
import { RenderTexture } from "../../../resource/RenderTexture";
import { RenderTexture2D } from "../../../resource/RenderTexture2D";
import { Texture2D } from "../../../resource/Texture2D";
import { Scene } from "../../Scene";
import { Sprite } from "../../Sprite";
import { CommandBuffer2D } from "../RenderCMD2D/CommandBuffer2D";
import { DrawMesh2DCMD } from "../RenderCMD2D/DrawMesh2DCMD";
Expand Down Expand Up @@ -153,14 +153,6 @@ export class FreeformLight2D extends BaseLight2D {
return super.getGlobalPosY() + this._worldCenter.y;
}

/**
* 响应矩阵改变
*/
protected _transformChange() {
if (this._lightPolygon)
super._transformChange();
}

/**
* 计算灯光范围(局部坐标)
*/
Expand Down Expand Up @@ -201,30 +193,31 @@ export class FreeformLight2D extends BaseLight2D {
super._calcWorldRange(screen);
this._lightScaleAndRotation();

const p = Point.TEMP;
this.owner.getScenePos(p);
const px = p.x;
const py = p.y;
this.owner.getSceneScale(p);
const sx = Math.abs(p.x);
const sy = Math.abs(p.y);
const mm = ILaya.stage.transform;
const pp = this.owner.getScenePos(Point.TEMP);
const px = mm.a * pp.x + mm.c * pp.y + mm.tx;
const py = mm.b * pp.x + mm.d * pp.y + mm.ty;
this.owner.getSceneScale(pp);
const sx = Math.abs(pp.x * mm.getScaleX());
const sy = Math.abs(pp.y * mm.getScaleY());

const x = this._localRange.x;
const y = this._localRange.y;
const w = this._localRange.width;
const h = this._localRange.height;
const m = Math.max(w * sx, h * sy) | 0;
const mat = this.owner.getSceneMatrix(this._sceneMatrix);
Matrix.mul(ILaya.stage.transform, mat, mat);
if (mat) {
this._worldCenter.x = mat.a * this._localCenter.x + mat.c * this._localCenter.y;
this._worldCenter.y = mat.b * this._localCenter.x + mat.d * this._localCenter.y;
this._worldCenter.x = mat.a * this._localCenter.x + mat.c * this._localCenter.y + mat.tx;
this._worldCenter.y = mat.b * this._localCenter.x + mat.d * this._localCenter.y + mat.ty;
}
this._worldRange.x = (px - m / 2 + this._worldCenter.x) | 0;
this._worldRange.y = (py - m / 2 + this._worldCenter.y) | 0;
this._worldRange.width = m;
this._worldRange.height = m;
this._lightRange.x = (px + x + this._worldCenter.x) | 0;
this._lightRange.y = (py + y + this._worldCenter.y) | 0;
this._lightRange.x = (px + x + this._localCenter.x) | 0;
this._lightRange.y = (py + y + this._localCenter.y) | 0;
this._lightRange.width = w;
this._lightRange.height = h;

Expand All @@ -239,12 +232,10 @@ export class FreeformLight2D extends BaseLight2D {

/**
* @en Render light texture
* @param scene Scene object
* @zh 渲染灯光贴图
* @param scene 场景对象
*/
renderLightTexture(scene: Scene) {
super.renderLightTexture(scene);
renderLightTexture() {
super.renderLightTexture();
if (this._needUpdateLight) {
this._needUpdateLight = false;
const range = this._getLocalRange();
Expand Down
64 changes: 42 additions & 22 deletions src/layaAir/laya/display/Scene2DSpecial/Light2D/Light2DManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { ILaya } from "../../../../ILaya";
import { Laya } from "../../../../Laya";
import { IElementComponentManager } from "../../../components/IScenceComponentManager";
import { Event } from "../../../events/Event";
import { LayaGL } from "../../../layagl/LayaGL";
import { Color } from "../../../maths/Color";
import { Matrix } from "../../../maths/Matrix";
import { Point } from "../../../maths/Point";
import { Rectangle } from "../../../maths/Rectangle";
import { Vector2 } from "../../../maths/Vector2";
import { Vector3 } from "../../../maths/Vector3";
Expand All @@ -11,6 +15,7 @@ import { ShaderData, ShaderDataType } from "../../../RenderDriver/DriverDesign/R
import { IndexFormat } from "../../../RenderEngine/RenderEnum/IndexFormat";
import { RenderTargetFormat } from "../../../RenderEngine/RenderEnum/RenderTargetFormat";
import { WrapMode } from "../../../RenderEngine/RenderEnum/WrapMode";
import { Shader3D } from "../../../RenderEngine/RenderShader/Shader3D";
import { Context } from "../../../renders/Context";
import { Mesh2D, VertexMesh2D } from "../../../resource/Mesh2D";
import { RenderTexture2D } from "../../../resource/RenderTexture2D";
Expand All @@ -26,9 +31,6 @@ import { LightLine2D } from "./LightLine2D";
import { LightOccluder2DCore } from "./LightOccluder2DCore";
import { Occluder2DAgent } from "./Occluder2DAgent";
import { LightAndShadow } from "./Shader/LightAndShadow";
import { Matrix } from "../../../maths/Matrix";
import { Point } from "../../../maths/Point";
import { Shader3D } from "../../../RenderEngine/RenderShader/Shader3D";

/**
* 生成2D光影图的渲染流程
Expand Down Expand Up @@ -91,7 +93,8 @@ export class Light2DManager implements IElementComponentManager, ILight2DManager

private _sceneInv0: Vector3 = new Vector3(); //Scene逆矩阵上半部分
private _sceneInv1: Vector3 = new Vector3(); //Scene逆矩阵下半部分
private _stageMatrixInv: Matrix = new Matrix(); //Stage逆矩阵
private _stageMat0: Vector3 = new Vector3();
private _stageMat1: Vector3 = new Vector3();
private _lightScenePos: Point = new Point(); //灯光基于Scene的位置

private _recoverFC: number = 0; //回收资源帧序号
Expand All @@ -104,16 +107,22 @@ export class Light2DManager implements IElementComponentManager, ILight2DManager

private _tempRange: Rectangle = new Rectangle();

static LIGHTANDSHADOW_SCENEINV_0: number;
static LIGHTANDSHADOW_SCENEINV_1: number;
static LIGHTANDSHADOW_SCENE_INV_0: number;
static LIGHTANDSHADOW_SCENE_INV_1: number;
static LIGHTANDSHADOW_STAGE_MAT_0: number;
static LIGHTANDSHADOW_STAGE_MAT_1: number;
static __init__() {
if (!Scene.scene2DUniformMap)
Scene.scene2DUniformMap = LayaGL.renderDeviceFactory.createGlobalUniformMap('Sprite2DGlobal');
const scene2DUniformMap = Scene.scene2DUniformMap;
this.LIGHTANDSHADOW_SCENEINV_0 = Shader3D.propertyNameToID('u_LightAndShadow2DSceneInv0');
this.LIGHTANDSHADOW_SCENEINV_1 = Shader3D.propertyNameToID('u_LightAndShadow2DSceneInv1');
scene2DUniformMap.addShaderUniform(this.LIGHTANDSHADOW_SCENEINV_0, 'u_LightAndShadow2DSceneInv0', ShaderDataType.Vector3);
scene2DUniformMap.addShaderUniform(this.LIGHTANDSHADOW_SCENEINV_1, 'u_LightAndShadow2DSceneInv1', ShaderDataType.Vector3);
this.LIGHTANDSHADOW_SCENE_INV_0 = Shader3D.propertyNameToID('u_LightAndShadow2DSceneInv0');
this.LIGHTANDSHADOW_SCENE_INV_1 = Shader3D.propertyNameToID('u_LightAndShadow2DSceneInv1');
this.LIGHTANDSHADOW_STAGE_MAT_0 = Shader3D.propertyNameToID('u_LightAndShadow2DStageMat0');
this.LIGHTANDSHADOW_STAGE_MAT_1 = Shader3D.propertyNameToID('u_LightAndShadow2DStageMat1');
scene2DUniformMap.addShaderUniform(this.LIGHTANDSHADOW_SCENE_INV_0, 'u_LightAndShadow2DSceneInv0', ShaderDataType.Vector3);
scene2DUniformMap.addShaderUniform(this.LIGHTANDSHADOW_SCENE_INV_1, 'u_LightAndShadow2DSceneInv1', ShaderDataType.Vector3);
scene2DUniformMap.addShaderUniform(this.LIGHTANDSHADOW_STAGE_MAT_0, 'u_LightAndShadow2DStageMat0', ShaderDataType.Vector3);
scene2DUniformMap.addShaderUniform(this.LIGHTANDSHADOW_STAGE_MAT_1, 'u_LightAndShadow2DStageMat1', ShaderDataType.Vector3);
}

constructor(scene: Scene) {
Expand All @@ -123,8 +132,8 @@ export class Light2DManager implements IElementComponentManager, ILight2DManager
this._screenPrev = new Vector2();
this._screenSchmitt = new Rectangle();
this._screenSchmittChange = false;

this.occluderAgent = new Occluder2DAgent(this);
ILaya.stage.on(Event.RESIZE, this, this._onScreenResize);

this._PCF = [
new Vector2(0, 0),
Expand All @@ -143,25 +152,36 @@ export class Light2DManager implements IElementComponentManager, ILight2DManager
];
}

/**
* 响应屏幕尺寸改变
*/
private _onScreenResize() {
this._lights.forEach(light => light._transformChange());
this._occluders.forEach(occluder => occluder._transformChange());
}

/**
* 场景矩阵发生变化
* @param context
*/
private _sceneTransformChange(context: Context) {
if (context._drawingToTexture) { //drawToTexture时,Scene的Matrix置空
this._sceneInv0.set(1, 0, 0);
this._sceneInv1.set(0, 1, 0);
let mat = ILaya.stage.transform; //获取Stage的矩阵
this._stageMat0.set(mat.a, mat.c, mat.tx);
this._stageMat1.set(mat.b, mat.d, mat.ty);
if (context._drawingToTexture) {
this._sceneInv0.set(mat.a, mat.c, mat.tx);
this._sceneInv1.set(mat.b, mat.d, mat.ty);
} else {
const mat = this._scene.getGlobalMatrixInv(); //获取Scene的Global逆矩阵
Laya.stage.transform.copyTo(this._stageMatrixInv).invert(); //获取Stage的逆矩阵
Matrix.mul(this._stageMatrixInv, mat, mat); //矩阵相乘(因为Scene的Global矩阵没有包含Stage的矩阵,所以需要补全)
mat = this._scene.getGlobalMatrixInv(); //获取Scene的Global逆矩阵
this._sceneInv0.set(mat.a, mat.c, mat.tx);
this._sceneInv1.set(mat.b, mat.d, mat.ty);
}

const shaderData = this._scene.sceneShaderData; //上传给着色器
shaderData.setVector3(Light2DManager.LIGHTANDSHADOW_SCENEINV_0, this._sceneInv0);
shaderData.setVector3(Light2DManager.LIGHTANDSHADOW_SCENEINV_1, this._sceneInv1);
shaderData.setVector3(Light2DManager.LIGHTANDSHADOW_SCENE_INV_0, this._sceneInv0);
shaderData.setVector3(Light2DManager.LIGHTANDSHADOW_SCENE_INV_1, this._sceneInv1);
shaderData.setVector3(Light2DManager.LIGHTANDSHADOW_STAGE_MAT_0, this._stageMat0);
shaderData.setVector3(Light2DManager.LIGHTANDSHADOW_STAGE_MAT_1, this._stageMat1);
}

/**
Expand Down Expand Up @@ -747,13 +767,13 @@ export class Light2DManager implements IElementComponentManager, ILight2DManager
*/
private _recoverResource() {
//回收资源(每10帧回收一次)
if (Laya.timer.currFrame > this._recoverFC) {
if (ILaya.timer.currFrame > this._recoverFC) {
if (this._needToRecover.length > 0) {
for (let i = this._needToRecover.length - 1; i > -1; i--)
this._needToRecover[i].destroy();
this._needToRecover.length = 0;
}
this._recoverFC = Laya.timer.currFrame + 10;
this._recoverFC = ILaya.timer.currFrame + 10;
}
}

Expand Down Expand Up @@ -858,7 +878,7 @@ export class Light2DManager implements IElementComponentManager, ILight2DManager
const material = renderRes.material[j];
const materialShadow = renderRes.materialShadow[j];
light.getScenePos(this._lightScenePos); //获取基于Scene的位置
light.renderLightTexture(this._scene); //按需更新灯光贴图
light.renderLightTexture(); //按需更新灯光贴图
if (!screenChange) {
lightChange = _isLightUpdate(light);
occluderChange = _isOccluderUpdate(layer, j);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ILaya } from "../../../../ILaya";
import { Matrix } from "../../../maths/Matrix";
import { Point } from "../../../maths/Point";
import { Rectangle } from "../../../maths/Rectangle";
Expand Down Expand Up @@ -623,20 +624,22 @@ export class LightOccluder2DCore {
let py = this._y;
let sx = this._scaleX;
let sy = this._scaleY;
const p = Point.TEMP;
if (this._owner) {
this._owner.getScenePos(p);
px = p.x;
py = p.y;
this._owner.getSceneScale(p);
sx = Math.abs(p.x);
sy = Math.abs(p.y);
const mm = ILaya.stage.transform;
const pp = this._owner.getScenePos(Point.TEMP);
px = mm.a * pp.x + mm.c * pp.y + mm.tx;
py = mm.b * pp.x + mm.d * pp.y + mm.ty;
this._owner.getSceneScale(pp);
sx = Math.abs(pp.x * mm.getScaleX());
sy = Math.abs(pp.y * mm.getScaleY());
}

const globalPoly = this._globalPolygon.points;
const polygon = this._occluderPolygon.points;
const len = polygon.length / 2 | 0;
const m = this._owner ? this._owner.getSceneMatrix(this._sceneMatrix) : this._transform;
let m = this._owner ? this._owner.getSceneMatrix(this._sceneMatrix) : this._transform;
Matrix.mul(ILaya.stage.transform, m, this._sceneMatrix); //加上stage变换
m = this._sceneMatrix;
if (m) {
for (let i = 0; i < len; i++) {
const x = polygon[i * 2 + 0];
Expand Down
21 changes: 10 additions & 11 deletions src/layaAir/laya/display/Scene2DSpecial/Light2D/SpotLight2D.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ILaya } from "../../../../ILaya";
import { LayaGL } from "../../../layagl/LayaGL";
import { Color } from "../../../maths/Color";
import { Matrix } from "../../../maths/Matrix";
Expand Down Expand Up @@ -202,13 +203,13 @@ export class SpotLight2D extends BaseLight2D {
super._calcWorldRange(screen);
this._lightScaleAndRotation();

const p = Point.TEMP;
this.owner.getScenePos(p);
const px = p.x;
const py = p.y;
this.owner.getSceneScale(p);
const sx = Math.abs(p.x);
const sy = Math.abs(p.y);
const mm = ILaya.stage.transform;
const pp = this.owner.getScenePos(Point.TEMP);
const px = mm.a * pp.x + mm.c * pp.y + mm.tx;
const py = mm.b * pp.x + mm.d * pp.y + mm.ty;
this.owner.getSceneScale(pp);
const sx = Math.abs(pp.x * mm.getScaleX());
const sy = Math.abs(pp.y * mm.getScaleY());

const x = this._localRange.x;
const y = this._localRange.y;
Expand All @@ -227,12 +228,10 @@ export class SpotLight2D extends BaseLight2D {

/**
* @en Render light texture
* @param scene Scene object
* @zh 渲染灯光贴图
* @param scene 场景对象
*/
renderLightTexture(scene: Scene) {
super.renderLightTexture(scene);
renderLightTexture() {
super.renderLightTexture();
if (this._needUpdateLight) {
this._needUpdateLight = false;
const range = this._getLocalRange();
Expand Down
Loading