From a6c536ec38c4d34780204f56b1c47e15bddb99c0 Mon Sep 17 00:00:00 2001 From: cary <39078800+caryliu1999@users.noreply.github.com> Date: Mon, 17 Aug 2020 23:08:59 +0800 Subject: [PATCH] Move global data of scene to pipeline. (#7109) * Move global data of scene to pipeline. * fix some code judgments. * fix pipeline save error * refine skybox and fog info * fix planer shadow * fix fog error * delete setter of skybox and fog --- .../core/pipeline/forward/forward-pipeline.ts | 62 ++++- cocos/core/pipeline/forward/forward-stage.ts | 2 +- cocos/core/pipeline/forward/scene-culling.ts | 10 +- cocos/core/pipeline/render-pipeline.ts | 2 + cocos/core/pipeline/render-view.ts | 20 +- cocos/core/renderer/scene/ambient.ts | 79 ++++-- cocos/core/renderer/scene/fog.ts | 248 ++++++++++++------ cocos/core/renderer/scene/planar-shadows.ts | 147 ++++++++--- cocos/core/renderer/scene/render-scene.ts | 37 +-- cocos/core/renderer/scene/skybox.ts | 143 +++++++--- cocos/core/root.ts | 8 +- cocos/core/scene-graph/scene.ts | 13 - .../builtin-forward.rpp | 116 ++++++-- tests/general/sealed-global-variables.json | 2 +- 14 files changed, 649 insertions(+), 240 deletions(-) diff --git a/cocos/core/pipeline/forward/forward-pipeline.ts b/cocos/core/pipeline/forward/forward-pipeline.ts index 27427bcb44e..406a535aad2 100644 --- a/cocos/core/pipeline/forward/forward-pipeline.ts +++ b/cocos/core/pipeline/forward/forward-pipeline.ts @@ -17,8 +17,12 @@ import { GFXColorAttachment, GFXDepthStencilAttachment, GFXRenderPass, GFXLoadOp import { SKYBOX_FLAG } from '../../renderer'; import { legacyCC } from '../../global-exports'; import { RenderView } from '../render-view'; -import { Mat4, Vec3, Vec2, Vec4 } from '../../math'; +import { Mat4, Vec3, Vec4} from '../../math'; import { GFXFeature } from '../../gfx/device'; +import { Fog } from '../../renderer/scene/fog'; +import { Ambient } from '../../renderer/scene/ambient'; +import { Skybox } from '../../renderer/scene/skybox'; +import { PlanarShadows } from '../../renderer/scene/planar-shadows'; import { ShadowInfo } from '../../renderer/scene/shadowInfo'; const matShadowView = new Mat4(); @@ -53,19 +57,50 @@ export class ForwardPipeline extends RenderPipeline { return this._fpScale; } + /** + * @en Get shadow UBO. + * @zh 获取阴影UBO。 + */ get shadowUBO (): Float32Array { return this._shadowUBO; } @property({ type: [RenderTextureConfig], + displayOrder: 2, }) protected renderTextures: RenderTextureConfig[] = []; + @property({ type: [MaterialConfig], + displayOrder: 3, }) protected materials: MaterialConfig[] = []; + @property({ + type: Fog, + displayOrder: 7, + visible: true, + }) + public fog: Fog = new Fog(); + @property({ + type: Ambient, + displayOrder: 4, + visible: true, + }) + public ambient: Ambient = new Ambient(); + @property({ + type: Skybox, + displayOrder: 5, + visible: true, + }) + public skybox: Skybox = new Skybox(); + @property({ + type: PlanarShadows, + displayOrder: 6, + visible: true, + }) + public planarShadows: PlanarShadows = new PlanarShadows(); /** * @en The list for render objects, only available after the scene culling of the current frame. * @zh 渲染对象数组,仅在当前帧的场景剔除完成后有效。 @@ -97,7 +132,7 @@ export class ForwardPipeline extends RenderPipeline { public activate (): boolean { this._globalDescriptorSetLayout = globalDescriptorSetLayout; this._localDescriptorSetLayout = localDescriptorSetLayout; - + this._macros = {}; const uiFlow = new UIFlow(); uiFlow.initialize(UIFlow.initInfo); this._flows.push(uiFlow); @@ -111,6 +146,11 @@ export class ForwardPipeline extends RenderPipeline { return false; } + this.ambient.activate(); + this.fog.activate(); + this.skybox.activate(); + this.planarShadows.activate(); + return true; } @@ -229,8 +269,8 @@ export class ForwardPipeline extends RenderPipeline { const scene = camera.scene!; const mainLight = scene.mainLight; - const ambient = scene.ambient; - const fog = scene.fog; + const ambient = this.ambient; + const fog = this.fog; const fv = this._globalUBO; const device = this.device; @@ -296,17 +336,17 @@ export class ForwardPipeline extends RenderPipeline { Vec4.toArray(fv, Vec4.ZERO, UBOGlobal.MAIN_LIT_COLOR_OFFSET); } - const skyColor = ambient.skyColor; + const skyColor = ambient.colorArray; if (this._isHDR) { skyColor[3] = ambient.skyIllum * this._fpScale; } else { skyColor[3] = ambient.skyIllum * exposure; } fv.set(skyColor, UBOGlobal.AMBIENT_SKY_OFFSET); - fv.set(ambient.groundAlbedo, UBOGlobal.AMBIENT_GROUND_OFFSET); + fv.set(ambient.albedoArray, UBOGlobal.AMBIENT_GROUND_OFFSET); if (fog.enabled) { - fv.set(fog.fogColor, UBOGlobal.GLOBAL_FOG_COLOR_OFFSET); + fv.set(fog.colorArray, UBOGlobal.GLOBAL_FOG_COLOR_OFFSET); fv[UBOGlobal.GLOBAL_FOG_BASE_OFFSET] = fog.fogStart; fv[UBOGlobal.GLOBAL_FOG_BASE_OFFSET + 1] = fog.fogEnd; @@ -319,15 +359,15 @@ export class ForwardPipeline extends RenderPipeline { } private destroyUBOs () { - this._descriptorSet.getBuffer(UBOGlobal.BLOCK.binding).destroy(); - this._descriptorSet.getBuffer(UBOShadow.BLOCK.binding).destroy(); + if (this._descriptorSet) { + this._descriptorSet.getBuffer(UBOGlobal.BLOCK.binding).destroy(); + this._descriptorSet.getBuffer(UBOShadow.BLOCK.binding).destroy(); + } } public destroy () { this.destroyUBOs(); - this._descriptorSet.destroy(); - const rpIter = this._renderPasses.values(); let rpRes = rpIter.next(); while (!rpRes.done) { diff --git a/cocos/core/pipeline/forward/forward-stage.ts b/cocos/core/pipeline/forward/forward-stage.ts index 219fa6d70ba..40438486415 100644 --- a/cocos/core/pipeline/forward/forward-stage.ts +++ b/cocos/core/pipeline/forward/forward-stage.ts @@ -183,7 +183,7 @@ export class ForwardStage extends RenderStage { this._instancedQueue.recordCommandBuffer(device, renderPass, cmdBuff); this._batchedQueue.recordCommandBuffer(device, renderPass, cmdBuff); this._additiveLightQueue.recordCommandBuffer(device, renderPass, cmdBuff); - camera.scene!.planarShadows.recordCommandBuffer(device, renderPass, cmdBuff); + pipeline.planarShadows.enabled && pipeline.planarShadows.recordCommandBuffer(device, renderPass, cmdBuff); this._renderQueues[1].recordCommandBuffer(device, renderPass, cmdBuff); cmdBuff.endRenderPass(); diff --git a/cocos/core/pipeline/forward/scene-culling.ts b/cocos/core/pipeline/forward/scene-culling.ts index 37d19d58372..d49385ae106 100644 --- a/cocos/core/pipeline/forward/scene-culling.ts +++ b/cocos/core/pipeline/forward/scene-culling.ts @@ -48,16 +48,16 @@ export function sceneCulling (pipeline: ForwardPipeline, view: RenderView) { shadowPool.freeArray(shadowObjects); shadowObjects.length = 0; const mainLight = scene.mainLight; - const planarShadows = scene.planarShadows; + const planarShadows = pipeline.planarShadows; if (mainLight) { mainLight.update(); - if (planarShadows.enabled && mainLight.node!.hasChangedFlags) { + if (planarShadows.enabled) { planarShadows.updateDirLight(mainLight); } } - if (scene.skybox.enabled && (camera.clearFlag & SKYBOX_FLAG)) { - renderObjects.push(getRenderObject(scene.skybox, camera)); + if (pipeline.skybox.enabled && pipeline.skybox.model && (camera.clearFlag & SKYBOX_FLAG)) { + renderObjects.push(getRenderObject(pipeline.skybox.model, camera)); } const models = scene.models; @@ -100,6 +100,6 @@ export function sceneCulling (pipeline: ForwardPipeline, view: RenderView) { } if (planarShadows.enabled) { - planarShadows.updateShadowList(camera.frustum, stamp, (camera.visibility & Layers.BitMask.DEFAULT) !== 0); + planarShadows.updateShadowList(scene, camera.frustum, stamp, (camera.visibility & Layers.BitMask.DEFAULT) !== 0); } } diff --git a/cocos/core/pipeline/render-pipeline.ts b/cocos/core/pipeline/render-pipeline.ts index fe435026e4a..758c29266be 100644 --- a/cocos/core/pipeline/render-pipeline.ts +++ b/cocos/core/pipeline/render-pipeline.ts @@ -193,3 +193,5 @@ export abstract class RenderPipeline extends Asset { return super.destroy(); } } + +legacyCC.RenderPipeline = RenderPipeline; diff --git a/cocos/core/pipeline/render-view.ts b/cocos/core/pipeline/render-view.ts index c950967d0a3..f17825408e9 100644 --- a/cocos/core/pipeline/render-view.ts +++ b/cocos/core/pipeline/render-view.ts @@ -171,13 +171,13 @@ export class RenderView { * @param flows The names of all [[RenderFlow]]s */ public setExecuteFlows (flows: string[] | undefined) { - this.flows.length = 0; + this._flows.length = 0; const pipeline = legacyCC.director.root.pipeline; const pipelineFlows = pipeline.flows; if (flows && flows.length === 1 && flows[0] === 'UIFlow') { for (let i = 0; i < pipelineFlows.length; i++) { if (pipelineFlows[i].name === 'UIFlow') { - this.flows.push(pipelineFlows[i]); + this._flows.push(pipelineFlows[i]); break; } } @@ -186,7 +186,21 @@ export class RenderView { for (let i = 0; i < pipelineFlows.length; ++i) { const f = pipelineFlows[i]; if (f.tag === RenderFlowTag.SCENE || (flows && flows.indexOf(f.name) !== -1)) { - this.flows.push(f); + this._flows.push(f); + } + } + } + + public onGlobalPipelineStateChanged () { + const pipeline = legacyCC.director.root.pipeline; + const pipelineFlows = pipeline.flows; + for (let i = 0; i < this._flows.length; ++i) { + const flow = this._flows[i]; + for (let j = 0; j < pipelineFlows.length; j++) { + if (pipelineFlows[i].name === flow.name) { + this._flows[i] = pipelineFlows[i]; + break; + } } } } diff --git a/cocos/core/renderer/scene/ambient.ts b/cocos/core/renderer/scene/ambient.ts index 1e6f270a13b..1bf71d9e47e 100644 --- a/cocos/core/renderer/scene/ambient.ts +++ b/cocos/core/renderer/scene/ambient.ts @@ -1,49 +1,98 @@ -import { RenderScene } from './render-scene'; +import { property, ccclass } from '../../data/class-decorator'; +import { Color, Vec3 } from '../../math'; +import { EDITOR } from 'internal:constants'; +@ccclass('cc.Ambient') export class Ambient { public static SUN_ILLUM = 65000.0; public static SKY_ILLUM = 20000.0; + get colorArray () { + return this._colorArray; + } + + get albedoArray () { + return this._albedoArray; + } + + /** + * @en Enable ambient + * @zh 是否开启环境光 + */ set enabled (val) { + if (this._enabled === val) { + return; + } this._enabled = val; + this.activate(); } get enabled () { return this._enabled; } - - get skyColor (): Float32Array { + /** + * @en Sky color + * @zh 天空颜色 + */ + get skyColor (): Color { return this._skyColor; } - set skyColor (color: Float32Array) { + set skyColor (color: Color) { this._skyColor = color; + Color.toArray(this._colorArray, this._skyColor); } - set skyIllum (illum: number) { - this._skyIllum = illum; - } - + /** + * @en Sky illuminance + * @zh 天空亮度 + */ get skyIllum (): number { return this._skyIllum; } - get groundAlbedo (): Float32Array { + set skyIllum (illum: number) { + this._skyIllum = illum; + } + + /** + * @en Ground color + * @zh 地面颜色 + */ + get groundAlbedo (): Color { return this._groundAlbedo; } - set groundAlbedo (color: Float32Array) { + set groundAlbedo (color: Color) { this._groundAlbedo = color; + Vec3.toArray(this._albedoArray, this._groundAlbedo); } protected _enabled = true; - protected _skyColor = Float32Array.from([0.2, 0.5, 0.8, 1.0]); + @property({ + type: Color, + visible: true, + }) + protected _skyColor = new Color(51, 128, 204, 1.0); + @property({ + visible: true, + }) protected _skyIllum: number = Ambient.SKY_ILLUM; - protected _groundAlbedo = Float32Array.from([0.2, 0.2, 0.2, 1.0]); + @property({ + type: Color, + visible: true, + }) + protected _groundAlbedo = new Color(51, 51, 51, 255); + + protected _albedoArray = Float32Array.from([0.2, 0.2, 0.2, 1.0]); + protected _colorArray = Float32Array.from([0.2, 0.5, 0.8, 1.0]); - protected _scene: RenderScene; + public activate () { + if (!this._enabled) { + return + } - constructor (scene: RenderScene) { - this._scene = scene; + Color.toArray(this._colorArray, this._skyColor); + Vec3.toArray(this._albedoArray, this._groundAlbedo); } public update () {} diff --git a/cocos/core/renderer/scene/fog.ts b/cocos/core/renderer/scene/fog.ts index 9cfa6c4281c..3f29d427b00 100644 --- a/cocos/core/renderer/scene/fog.ts +++ b/cocos/core/renderer/scene/fog.ts @@ -1,5 +1,9 @@ -import { RenderScene } from './render-scene'; import { Enum } from '../../value-types'; +import { ccclass, property } from '../../data/class-decorator'; +import { Color } from '../../../core/math'; +import { CCBoolean, CCFloat } from '../../data/utils/attribute'; +import { legacyCC } from '../../global-exports'; +import { EDITOR } from 'internal:constants'; /** * @zh @@ -48,82 +52,60 @@ export const FogType = Enum({ LAYERED: 3, }); +@ccclass('cc.Fog') export class Fog { - protected _enabled = false; - protected _fogColor = Float32Array.from([0.6, 0.6, 0.6, 1.0]); - protected _fogDensity = 0.3; - protected _type = FogType.LINEAR; - protected _fogStart = 0; - protected _fogEnd = 300; - protected _fogAtten = 5; - protected _fogTop = 1.5; - protected _fogRange = 1.2; - protected _scene: RenderScene; - - private _currType = 0; /** - * @zh - * 当前雾化类型。 - * @returns {FogType} - * 返回当前全局雾类型 - * - 0:不使用雾化 - * - 1:使用线性雾 - * - 2:使用指数雾 - * - 3:使用指数平方雾 - * - 4:使用层叠雾 - * @en - * The current global fog type. - * @returns {FogType} - * Returns the current global fog type - * - 0:Disable global Fog - * - 1:Linear fog - * - 2:Exponential fog - * - 3:Exponential square fog - * - 4:Layered fog - */ - get currType() { - return this._currType; - } - - constructor (scene: RenderScene) { - this._scene = scene; - } - + * @zh 是否启用全局雾效 + * @en Enable global fog + */ set enabled (val: boolean) { + if (this._enabled === val) { + return + } this._enabled = val; if (!val) { this._currType = 0; } else { this._currType = this._type + 1; } - this._updatePipeline(); + this._enabled ? this.activate() : this._updatePipeline(); } - + get enabled () { return this._enabled; } - set type(val: any) { - this._type = val; - if (!this.enabled) { - return; - } - this._currType = val + 1; - this._updatePipeline(); + /** + * @zh 全局雾颜色 + * @en Global fog color + */ + set fogColor (val: Color) { + this._fogColor.set(val); + Color.toArray(this._colorArray, this._fogColor); } - get type() { - return this._type; + get fogColor () { + return this._fogColor; } - set fogColor (val: Float32Array) { - this._fogColor = val; + /** + * @zh 全局雾类型 + * @en Global fog type + */ + get type () { + return this._type; } - get fogColor (): Float32Array { - return this._fogColor; + set type (val) { + this._type = val; + this._currType = val + 1; + this._updatePipeline(); } + /** + * @zh 全局雾浓度 + * @en Global fog density + */ get fogDensity () { return this._fogDensity; } @@ -132,51 +114,171 @@ export class Fog { this._fogDensity = val; } - get fogStart() { + /** + * @zh 雾效起始位置,只适用于线性雾 + * @en Global fog start position, only for linear fog + */ + get fogStart () { return this._fogStart; } - protected _updatePipeline () { - const value = this._currType; - const pipeline = this._scene!.root.pipeline; - if (pipeline.macros.CC_USE_FOG === value) { return; } - pipeline.macros.CC_USE_FOG = value; - this._scene!.onGlobalPipelineStateChanged(); - } - - set fogStart(val) { + set fogStart (val) { this._fogStart = val; } - get fogEnd() { + /** + * @zh 雾效结束位置,只适用于线性雾 + * @en Global fog end position, only for linear fog + */ + get fogEnd () { return this._fogEnd; } - set fogEnd(val) { + set fogEnd (val) { this._fogEnd = val; } - get fogAtten() { + /** + * @zh 雾效衰减 + * @en Global fog attenuation + */ + get fogAtten () { return this._fogAtten; } - set fogAtten(val) { + set fogAtten (val) { this._fogAtten = val; } - get fogTop() { + /** + * @zh 雾效顶部范围,只适用于层级雾 + * @en Global fog top range, only for layered fog + */ + get fogTop () { return this._fogTop; } - set fogTop(val) { + set fogTop (val) { this._fogTop = val; } - get fogRange() { + /** + * @zh 雾效范围,只适用于层级雾 + * @en Global fog range, only for layered fog + */ + get fogRange () { return this._fogRange; } - set fogRange(val) { + set fogRange (val) { this._fogRange = val; } + /** + * @zh 当前雾化类型。 + * @en The current global fog type. + * @returns {FogType} + * Returns the current global fog type + * - 0:Disable global Fog + * - 1:Linear fog + * - 2:Exponential fog + * - 3:Exponential square fog + * - 4:Layered fog + */ + get currType () { + return this._currType; + } + + get colorArray (): Float32Array { + return this._colorArray; + } + + @property({ + type: FogType, + visible: true, + displayOrder: 1, + }) + protected _type = FogType.LINEAR; + @property({ + type: Color, + visible: true, + displayOrder: 2, + }) + protected _fogColor = new Color('#C8C8C8'); + @property({ + type: CCBoolean, + visible: true, + displayOrder: 0, + }) + protected _enabled = false; + @property({ + type: CCFloat, + range: [0, 1], + step: 0.01, + slide: true, + displayOrder: 3, + visible: function(this: Fog) { + return this._type !== FogType.LAYERED && this._type !== FogType.LINEAR; + } + }) + protected _fogDensity = 0.3; + @property({ + type: CCFloat, + step: 0.1, + displayOrder: 4, + visible: function(this: Fog) { + return this._type === FogType.LINEAR; + } + }) + protected _fogStart = 0.5; + @property({ + type: CCFloat, + step: 0.1, + displayOrder: 5, + visible: function (this: Fog){ + return this._type === FogType.LINEAR; + } + }) + protected _fogEnd = 300; + @property({ + type: CCFloat, + step: 0.1, + displayOrder: 6, + visible: function (this: Fog){ + return this._type !== FogType.LINEAR; + } + }) + protected _fogAtten = 5; + @property({ + type: CCFloat, + step: 0.1, + displayOrder: 7, + visible: function (this: Fog){ + return this._type === FogType.LAYERED; + } + }) + protected _fogTop = 1.5; + @property({ + type: CCFloat, + step: 0.1, + displayOrder: 8, + visible: function (this: Fog) { + return this._type === FogType.LAYERED; + } + }) + protected _fogRange = 1.2; + protected _currType = 0; + protected _colorArray: Float32Array = new Float32Array([0.2, 0.2, 0.2, 1.0]); + + public activate () { + Color.toArray(this._colorArray, this._fogColor); + this._currType = this._enabled ? this._type + 1 : 0; + this._updatePipeline(); + } + + protected _updatePipeline () { + const value = this._currType; + const pipeline = legacyCC.director.root.pipeline; + if (pipeline.macros.CC_USE_FOG === value) { return; } + pipeline.macros.CC_USE_FOG = value; + } } \ No newline at end of file diff --git a/cocos/core/renderer/scene/planar-shadows.ts b/cocos/core/renderer/scene/planar-shadows.ts index 0a84adb2d1d..c1ceb0cd899 100644 --- a/cocos/core/renderer/scene/planar-shadows.ts +++ b/cocos/core/renderer/scene/planar-shadows.ts @@ -3,21 +3,26 @@ import { Material } from '../../assets/material'; import { aabb, frustum, intersect } from '../../geometry'; import { GFXPipelineState } from '../../gfx/pipeline-state'; import { Color, Mat4, Quat, Vec3 } from '../../math'; -import { UBOShadow, SetIndex } from '../../pipeline/define'; +import { UBOShadow, SetIndex} from '../../pipeline/define'; import { DirectionalLight } from './directional-light'; import { Model } from './model'; -import { RenderScene } from './render-scene'; import { SphereLight } from './sphere-light'; import { GFXCommandBuffer, GFXDevice, GFXRenderPass, GFXDescriptorSet, GFXShader } from '../../gfx'; import { InstancedBuffer } from '../../pipeline/instanced-buffer'; import { PipelineStateManager } from '../../pipeline/pipeline-state-manager'; +import { ccclass, property } from '../../data/class-decorator'; +import { CCFloat, CCBoolean } from '../../data/utils/attribute'; +import { legacyCC } from '../../global-exports'; +import { RenderScene } from './render-scene'; import { DSPool, ShaderPool, PassPool, PassView } from '../core/memory-pools'; +import { EDITOR } from 'internal:constants'; import { ForwardPipeline } from '../../pipeline'; const _forward = new Vec3(0, 0, -1); const _v3 = new Vec3(); const _ab = new aabb(); const _qt = new Quat(); +const _up = new Vec3(0, 1, 0); interface IShadowRenderData { model: Model; @@ -25,56 +30,123 @@ interface IShadowRenderData { instancedBuffer: InstancedBuffer | null; } +@ccclass('cc.PlanarShadows') export class PlanarShadows { + /** + * @en Whether activate planar shadow + * @zh 是否启用平面阴影? + */ + get enabled (): boolean { + return this._enabled; + } - set enabled (enable: boolean) { - this._enabled = enable; - if (this._scene.mainLight) { this.updateDirLight(this._scene.mainLight); } + set enabled (val: boolean) { + if (this._enabled === val) { + return; + } + this._enabled = val; + this._dirty = true; + if (this._enabled) { + this.activate(); + } } - get enabled (): boolean { - return this._enabled; + /** + * @en The normal of the plane which receives shadow + * @zh 阴影接收平面的法线 + */ + get normal () { + return this._normal; } set normal (val: Vec3) { Vec3.copy(this._normal, val); - if (this._scene.mainLight) { this.updateDirLight(this._scene.mainLight); } + this._dirty = true; } - get normal () { - return this._normal; + + /** + * @en The distance from coordinate origin to the receiving plane. + * @zh 阴影接收平面与原点的距离 + */ + get distance () { + return this._distance; } set distance (val: number) { this._distance = val; - if (this._scene.mainLight) { this.updateDirLight(this._scene.mainLight); } + this._dirty = true; } - get distance () { - return this._distance; + + /** + * @en Shadow color + * @zh 阴影颜色 + */ + get shadowColor () { + return this._shadowColor; } set shadowColor (color: Color) { - Color.toArray(this._data, color, UBOShadow.SHADOW_COLOR_OFFSET); + this._shadowColor = color; + if (this._enabled) { + Color.toArray(this._data, color, UBOShadow.SHADOW_COLOR_OFFSET); + if (this._globalDescriptorSet) { + this._globalDescriptorSet.getBuffer(UBOShadow.BLOCK.binding).update(this.data); + } + } + this._dirty = true; } get matLight () { return this._matLight; } - protected _scene: RenderScene; + get data () { + return this._data; + } + + @property({ + type: CCBoolean, + visible: true, + }) protected _enabled: boolean = false; + @property({ + type: Vec3, + visible: true, + }) protected _normal = new Vec3(0, 1, 0); + @property({ + type: CCFloat, + visible: true, + }) protected _distance = 0; + @property({ + type: Color, + visible: true, + }) + protected _shadowColor = new Color(0, 0, 0, 76); protected _matLight = new Mat4(); - protected _data: Float32Array; + protected _data = Float32Array.from([ + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, // matLightPlaneProj + 0.0, 0.0, 0.0, 0.3, // shadowColor + ]); protected _record = new Map(); protected _pendingModels: IShadowRenderData[] = []; - protected _material: Material; - protected _instancingMaterial: Material; - protected _device: GFXDevice | null = null; + protected _material: Material | null = null; + protected _instancingMaterial: Material | null = null; + protected _device: GFXDevice|null = null; + protected _globalDescriptorSet: GFXDescriptorSet | null = null; + protected _dirty: boolean = true; - constructor (scene: RenderScene) { - this._scene = scene; - this._data = (scene.root.pipeline as ForwardPipeline).shadowUBO; + public activate () { + if (!this._enabled) { + return; + } + this._dirty = true; + const pipeline = legacyCC.director.root.pipeline; + this._globalDescriptorSet = pipeline.descriptorSet; + this._data = (pipeline as ForwardPipeline).shadowUBO; + Color.toArray(this._data, this._shadowColor, UBOShadow.SHADOW_COLOR_OFFSET); + this._globalDescriptorSet!.getBuffer(UBOShadow.BLOCK.binding).update(this.data); this._material = new Material(); this._material.initialize({ effectName: 'pipeline/planar-shadow' }); this._instancingMaterial = new Material(); @@ -82,6 +154,10 @@ export class PlanarShadows { } public updateSphereLight (light: SphereLight) { + if (!light.node!.hasChangedFlags && !this._dirty) { + return; + } + this._dirty = false; light.node!.getWorldPosition(_v3); const n = this._normal; const d = this._distance + 0.001; // avoid z-fighting const NdL = Vec3.dot(n, _v3); @@ -105,9 +181,16 @@ export class PlanarShadows { m.m14 = lz * d; m.m15 = NdL; Mat4.toArray(this._data, this._matLight, UBOShadow.MAT_LIGHT_PLANE_PROJ_OFFSET); + this._globalDescriptorSet!.getBuffer(UBOShadow.BLOCK.binding).update(this.data); } public updateDirLight (light: DirectionalLight) { + if (!light.node!.hasChangedFlags && !this._dirty) { + return; + } + + this._dirty = false; + light.node!.getWorldRotation(_qt); Vec3.transformQuat(_v3, _forward, _qt); const n = this._normal; const d = this._distance + 0.001; // avoid z-fighting @@ -131,13 +214,15 @@ export class PlanarShadows { m.m13 = ly * d; m.m14 = lz * d; m.m15 = 1; + Mat4.toArray(this._data, this._matLight, UBOShadow.MAT_LIGHT_PLANE_PROJ_OFFSET); + this._globalDescriptorSet!.getBuffer(UBOShadow.BLOCK.binding).update(this.data); } - public updateShadowList (frstm: frustum, stamp: number, shadowVisible = false) { + public updateShadowList (scene: RenderScene, frstm: frustum, stamp: number, shadowVisible = false) { this._pendingModels.length = 0; - if (!this._scene.mainLight || !shadowVisible) { return; } - const models = this._scene.models; + if (!scene.mainLight || !shadowVisible) { return; } + const models = scene.models; for (let i = 0; i < models.length; i++) { const model = models[i]; if (!model.enabled || !model.node || !model.castShadow) { continue; } @@ -158,9 +243,9 @@ export class PlanarShadows { const models = this._pendingModels; const modelLen = models.length; if (!modelLen) { return; } - const buffer = InstancedBuffer.get(this._instancingMaterial.passes[0]); + const buffer = InstancedBuffer.get(this._instancingMaterial!.passes[0]); if (buffer) { buffer.clear(); } - const hPass = this._material.passes[0].handle; + const hPass = this._material!.passes[0].handle; let descriptorSet = DSPool.get(PassPool.get(hPass, PassView.DESCRIPTOR_SET)); cmdBuff.bindDescriptorSet(SetIndex.MATERIAL, descriptorSet); for (let i = 0; i < modelLen; i++) { @@ -204,10 +289,10 @@ export class PlanarShadows { public createShadowData (model: Model): IShadowRenderData { const shaders: GFXShader[] = []; const material = model.isInstancingEnabled ? this._instancingMaterial : this._material; - const instancedBuffer = model.isInstancingEnabled ? InstancedBuffer.get(material.passes[0]) : null; + const instancedBuffer = model.isInstancingEnabled ? InstancedBuffer.get(material!.passes[0]) : null; const subModels = model.subModels; for (let i = 0; i < subModels.length; i++) { - const hShader = material.passes[0].getShaderVariant(model.getMacroPatches(i)); + const hShader = material!.passes[0].getShaderVariant(model.getMacroPatches(i)); shaders.push(ShaderPool.get(hShader)); } return { model, shaders, instancedBuffer }; @@ -219,6 +304,8 @@ export class PlanarShadows { public destroy () { this._record.clear(); - this._material.destroy(); + if (this._material) { + this._material.destroy(); + } } } diff --git a/cocos/core/renderer/scene/render-scene.ts b/cocos/core/renderer/scene/render-scene.ts index e73f9d47407..ae42cdec58a 100644 --- a/cocos/core/renderer/scene/render-scene.ts +++ b/cocos/core/renderer/scene/render-scene.ts @@ -6,17 +6,13 @@ import { RecyclePool } from '../../memop'; import { Root } from '../../root'; import { Node } from '../../scene-graph'; import { Layers } from '../../scene-graph/layers'; -import { Ambient } from './ambient'; import { Camera } from './camera'; import { DirectionalLight } from './directional-light'; import { Model, ModelType } from './model'; -import { PlanarShadows } from './planar-shadows'; -import { Skybox } from './skybox'; import { SphereLight } from './sphere-light'; import { SpotLight } from './spot-light'; import { PREVIEW } from 'internal:constants'; import { TransformBit } from '../../scene-graph/node-enum'; -import { Fog } from './fog'; import { legacyCC } from '../../global-exports'; import { ShadowInfo } from './shadowInfo'; @@ -49,22 +45,6 @@ export class RenderScene { return this._cameras; } - get ambient (): Ambient { - return this._ambient; - } - - get fog (): Fog { - return this._fog; - } - - get skybox (): Skybox { - return this._skybox; - } - - get planarShadows (): PlanarShadows { - return this._planarShadows; - } - get mainLight (): DirectionalLight | null { return this._mainLight; } @@ -124,24 +104,16 @@ export class RenderScene { private _root: Root; private _name: string = ''; private _cameras: Camera[] = []; - private _ambient: Ambient; - private _skybox: Skybox; - private _planarShadows: PlanarShadows; private _models: Model[] = []; private _directionalLights: DirectionalLight[] = []; private _sphereLights: SphereLight[] = []; private _spotLights: SpotLight[] = []; private _mainLight: DirectionalLight | null = null; private _modelId: number = 0; - private _fog: Fog; private _shadowInfo: ShadowInfo; constructor (root: Root) { this._root = root; - this._ambient = new Ambient(this); - this._skybox = new Skybox(this); - this._planarShadows = new PlanarShadows(this); - this._fog = new Fog(this); this._shadowInfo = ShadowInfo.instance; } @@ -155,8 +127,6 @@ export class RenderScene { this.removeSphereLights(); this.removeSpotLights(); this.removeModels(); - this._skybox.destroy(); - this._planarShadows.destroy(); } public addCamera (cam: Camera) { @@ -264,9 +234,10 @@ export class RenderScene { } public removeModel (model: Model) { + const pipeline = legacyCC.director.root.pipeline; for (let i = 0; i < this._models.length; ++i) { if (this._models[i] === model) { - this._planarShadows.destroyShadowData(model); + pipeline.planarShadows.destroyShadowData(model); model.detachFromScene(); this._models.splice(i, 1); return; @@ -275,8 +246,9 @@ export class RenderScene { } public removeModels () { + const pipeline = legacyCC.director.root.pipeline; for (const m of this._models) { - this._planarShadows.destroyShadowData(m); + pipeline.planarShadows.destroyShadowData(m); m.detachFromScene(); } this._models.length = 0; @@ -286,7 +258,6 @@ export class RenderScene { for (const m of this._models) { m.onGlobalPipelineStateChanged(); } - this._skybox.onGlobalPipelineStateChanged(); } public generateModelId (): number { diff --git a/cocos/core/renderer/scene/skybox.ts b/cocos/core/renderer/scene/skybox.ts index 0409ad4be15..17a7148e064 100644 --- a/cocos/core/renderer/scene/skybox.ts +++ b/cocos/core/renderer/scene/skybox.ts @@ -8,81 +8,160 @@ import { box } from '../../primitive'; import { MaterialInstance } from '../core/material-instance'; import { samplerLib } from '../core/sampler-lib'; import { Model } from './model'; -import { RenderScene } from './render-scene'; +import { ccclass, property } from '../../data/class-decorator'; +import { CCBoolean } from '../../data/utils/attribute'; +import { legacyCC } from '../../global-exports'; import { GFXDescriptorSet } from '../../gfx'; +import { EDITOR } from 'internal:constants'; let skybox_mesh: Mesh | null = null; let skybox_material: Material | null = null; -export class Skybox extends Model { +@ccclass('cc.Skybox') +export class Skybox { + get model () { + return this._model; + } - set useIBL (val) { - this._useIBL = val; - this._updatePipeline(); + /** + * @en Whether activate skybox in the scene + * @zh 是否启用天空盒? + */ + get enabled () { + return this._enabled; } + + set enabled (val) { + if (this._enabled === val) { + return; + } + this._enabled = val; + this._enabled ? this.activate() : this._updatePipeline(); + } + + /** + * @en Whether use environment lighting + * @zh 是否启用环境光照? + */ get useIBL () { return this._useIBL; } - set isRGBE (val) { - this._isRGBE = val; - skybox_material!.recompileShaders({ USE_RGBE_CUBEMAP: this._isRGBE }); - this.setSubModelMaterial(0, skybox_material!); + set useIBL (val) { + this._useIBL = val; this._updatePipeline(); } + + /** + * @en Whether enable RGBE data support in skybox shader + * @zh 是否需要开启 shader 内的 RGBE 数据支持? + */ get isRGBE () { return this._isRGBE; } - set envmap (val: TextureCube | null) { - const newEnvmap = val || this._default; - this._envmap = newEnvmap; - this.scene!.ambient.groundAlbedo[3] = this._envmap.mipmapLevel; - this._updateGlobalBinding(); + set isRGBE (val) { + this._isRGBE = val; + + if (this._enabled) { + if (skybox_material) { + skybox_material.recompileShaders({ USE_RGBE_CUBEMAP: this._isRGBE }); + } + + if (this._model) { + this._model.setSubModelMaterial(0, skybox_material!); + } + } + + this._updatePipeline(); } + + /** + * @en The texture cube used for the skybox + * @zh 使用的立方体贴图 + */ get envmap () { - return this._envmap; + return this._envmap || this._default; } - protected _default = builtinResMgr.get('default-cube-texture'); - protected _envmap = this._default; + set envmap (val: TextureCube | null) { + this._envmap = val; + if (this._enabled) { + legacyCC.director.root.pipeline.ambient.groundAlbedo[3] = this._envmap ? this._envmap.mipmapLevel : this._default!.mipmapLevel; + this._updateGlobalBinding(); + } + } + + @property({ + type: CCBoolean, + visible: true, + }) + protected _enabled = false; + @property({ + type: CCBoolean, + visible: true, + }) protected _isRGBE = false; + @property({ + type: CCBoolean, + visible: true, + }) protected _useIBL = false; + @property({ + type: TextureCube, + visible: true, + }) + protected _envmap: TextureCube | null = null; + protected _globalDescriptorSet: GFXDescriptorSet | null = null; + protected _model: Model | null = null; + protected _default: TextureCube | null = null; + + public activate () { + this._updatePipeline(); + + if (!this._enabled) { + return; + } + + const pipeline = legacyCC.director.root.pipeline + this._globalDescriptorSet = pipeline.descriptorSet; + if (!this._model) { + this._model = new Model(); + } - protected _globalDescriptorSet: GFXDescriptorSet; + this._default = builtinResMgr.get('default-cube-texture'); - constructor (scene: RenderScene) { - super(); - this.scene = scene; - this._globalDescriptorSet = this.scene.root.pipeline.descriptorSet; + pipeline.ambient.groundAlbedo[3] = this._envmap ? this._envmap.mipmapLevel : this._default.mipmapLevel; + this._updateGlobalBinding(); if (!skybox_material) { const mat = new Material(); mat.initialize({ effectName: 'pipeline/skybox', defines: { USE_RGBE_CUBEMAP: this._isRGBE } }); skybox_material = new MaterialInstance({ parent: mat }); + } else { + skybox_material.recompileShaders({ USE_RGBE_CUBEMAP: this._isRGBE }); } if (!skybox_mesh) { skybox_mesh = createMesh(box({ width: 2, height: 2, length: 2 })); } - this.initSubModel(0, skybox_mesh.renderingSubMeshes[0], skybox_material); + this._model.initSubModel(0, skybox_mesh.renderingSubMeshes[0], skybox_material); } public onGlobalPipelineStateChanged () { - super.onGlobalPipelineStateChanged(); + this._model!.onGlobalPipelineStateChanged(); this._updateGlobalBinding(); } protected _updatePipeline () { - const value = this._useIBL ? this._isRGBE ? 2 : 1 : 0; - const pipeline = this.scene!.root.pipeline; - const current = pipeline.macros.CC_USE_IBL || 0; + const value = this._enabled ? (this._useIBL ? this._isRGBE ? 2 : 1 : 0) : 0; + const pipeline = legacyCC.director.root.pipeline; + const current = pipeline.macros.CC_USE_IBL; if (current === value) { return; } pipeline.macros.CC_USE_IBL = value; - this.scene!.onGlobalPipelineStateChanged(); } protected _updateGlobalBinding () { - const texture = this._envmap.getGFXTexture()!; - const sampler = samplerLib.getSampler(this._device, this._envmap.getSamplerHash()); - this._globalDescriptorSet.bindSampler(UNIFORM_ENVIRONMENT.binding, sampler); - this._globalDescriptorSet.bindTexture(UNIFORM_ENVIRONMENT.binding, texture); + const texture = this.envmap!.getGFXTexture()!; + const sampler = samplerLib.getSampler(legacyCC.director._device, this.envmap!.getSamplerHash()); + this._globalDescriptorSet!.bindSampler(UNIFORM_ENVIRONMENT.binding, sampler); + this._globalDescriptorSet!.bindTexture(UNIFORM_ENVIRONMENT.binding, texture); } } diff --git a/cocos/core/root.ts b/cocos/core/root.ts index 7930ac48fab..5bc74dec807 100644 --- a/cocos/core/root.ts +++ b/cocos/core/root.ts @@ -300,10 +300,12 @@ export class Root { if (!this._pipeline.activate()) { return false; } - for (let i = 0; i < this.scenes.length; i++) { - this.scenes[i].onGlobalPipelineStateChanged(); + for (let i = 0; i < this._scenes.length; i++) { + this._scenes[i].onGlobalPipelineStateChanged(); + } + for (let i = 0; i < this._views.length; i++) { + this._views[i].onGlobalPipelineStateChanged(); } - this._ui = new UI(this); if (!this._ui.initialize()) { this.destroy(); diff --git a/cocos/core/scene-graph/scene.ts b/cocos/core/scene-graph/scene.ts index 25135c0da37..f99fdef6de5 100644 --- a/cocos/core/scene-graph/scene.ts +++ b/cocos/core/scene-graph/scene.ts @@ -32,7 +32,6 @@ import { Mat4, Quat, Vec3 } from '../math'; import { warnID, assert, getError } from '../platform/debug'; import { RenderScene } from '../renderer/scene/render-scene'; import { BaseNode } from './base-node'; -import { SceneGlobals } from './scene-globals'; import { EDITOR, TEST } from 'internal:constants'; import { legacyCC } from '../global-exports'; import { Component } from '../components/component'; @@ -55,14 +54,6 @@ export class Scene extends BaseNode { return this._renderScene; } - /** - * @en All scene related global parameters, it affects all content in the scene - * @zh 各类场景级别的渲染参数,将影响全场景的所有物体 - */ - get globals (): SceneGlobals { - return this._globals; - } - /** * @en Indicates whether all (directly or indirectly) static referenced assets of this scene are releasable by default after scene unloading. * @zh 指示该场景中直接或间接静态引用到的所有资源是否默认在场景切换后自动释放。 @@ -73,9 +64,6 @@ export class Scene extends BaseNode { public _renderScene: RenderScene | null = null; public dependAssets = null; // cache all depend assets for auto release - @property - protected _globals = new SceneGlobals(); - protected _inited: boolean; protected _prefabSyncedInLiveReload = false; @@ -226,7 +214,6 @@ export class Scene extends BaseNode { this._registerIfAttached!(active); } legacyCC.director._nodeActivator.activateNode(this, active); - this._globals.renderScene = this._renderScene!; } } diff --git a/editor/assets/default_renderpipeline/builtin-forward.rpp b/editor/assets/default_renderpipeline/builtin-forward.rpp index 01aa8fda3f3..2e8d72eb6f6 100644 --- a/editor/assets/default_renderpipeline/builtin-forward.rpp +++ b/editor/assets/default_renderpipeline/builtin-forward.rpp @@ -1,17 +1,49 @@ [ { "__type__": "ForwardPipeline", + "_name": "", + "_objFlags": 0, + "_native": "", "_tag": 0, "_flows": [ { - "__id__": 5 + "__id__": 1 }, { - "__id__": 1 + "__id__": 3 } ], "renderTextures": [], - "materials": [] + "materials": [], + "fog": { + "__id__": 7 + }, + "ambient": { + "__id__": 8 + }, + "skybox": { + "__id__": 9 + }, + "planarShadows": { + "__id__": 10 + } + }, + { + "__type__": "ShadowFlow", + "_name": "ShadowFlow", + "_priority": 0, + "_tag": 0, + "_stages": [ + { + "__id__": 2 + } + ] + }, + { + "__type__": "ShadowStage", + "_name": "ShadowStage", + "_priority": 0, + "_tag": 0 }, { "__type__": "ForwardFlow", @@ -20,7 +52,7 @@ "_tag": 0, "_stages": [ { - "__id__": 2 + "__id__": 4 } ] }, @@ -31,10 +63,10 @@ "_tag": 0, "renderQueues": [ { - "__id__": 3 + "__id__": 5 }, { - "__id__": 4 + "__id__": 6 } ] }, @@ -55,20 +87,64 @@ ] }, { - "__type__": "ShadowFlow", - "_name": "ShadowFlow", - "_priority": 0, - "_tag": 0, - "_stages": [ - { - "__id__": 6 - } - ] + "__type__": "cc.Fog", + "_type": 0, + "_fogColor": { + "__type__": "cc.Color", + "r": 200, + "g": 200, + "b": 200, + "a": 255 + }, + "_enabled": false, + "_fogDensity": 0.3, + "_fogStart": 0.5, + "_fogEnd": 300, + "_fogAtten": 5, + "_fogTop": 1.5, + "_fogRange": 1.2 }, { - "__type__": "ShadowStage", - "_name": "ShadowStage", - "_priority": 0, - "_tag": 0 + "__type__": "cc.Ambient", + "_skyColor": { + "__type__": "cc.Color", + "r": 51, + "g": 128, + "b": 204, + "a": 1 + }, + "_skyIllum": 20000, + "_groundAlbedo": { + "__type__": "cc.Color", + "r": 51, + "g": 51, + "b": 51, + "a": 255 + } + }, + { + "__type__": "cc.Skybox", + "_enabled": false, + "_isRGBE": false, + "_useIBL": false, + "_envmap": null + }, + { + "__type__": "cc.PlanarShadows", + "_enabled": false, + "_normal": { + "__type__": "cc.Vec3", + "x": 0, + "y": 1, + "z": 0 + }, + "_distance": 0, + "_shadowColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 76 + } } -] +] \ No newline at end of file diff --git a/tests/general/sealed-global-variables.json b/tests/general/sealed-global-variables.json index 7946f48dc85..eddffbf8360 100644 --- a/tests/general/sealed-global-variables.json +++ b/tests/general/sealed-global-variables.json @@ -155,6 +155,7 @@ "cc.RatioSampler", "cc.RawAsset", "cc.Rect", + "cc.RenderPipeline", "cc.RenderFlow", "cc.RenderPassStage", "cc.RenderStage", @@ -176,7 +177,6 @@ "cc.Skeleton", "cc.SkinningModelComponent", "cc.SkinningModelUnit", - "cc.SkyboxInfo", "cc.SliderComponent", "cc.SphereColliderComponent", "cc.SphereLightComponent",