import { CubeTexture, HemisphereLight, ImageWrapType, MathUtils, Utils, EventType } from "../main";
import { BaseComponent } from "./BaseComponent";
const __ = {
private: Symbol('private'),
}
let _tempArray = [];
let _id = 0;
/**
* @class DynamicSky
* The dynamic sky.
* @memberof THING
* @extends THING.BaseComponent
* @example
* // 创建一个基础的动态天空场景
* const app = new THING.App();
*
* // 创建一个基础的盒子和平面作为场景内容
* const box = new THING.Box({
* position: [0, 0.5, 0]
* });
* const plane = new THING.Plane(20, 20);
*
* // 创建天空盒纹理
* const nightSkyTexture = new THING.CubeTexture({
* url: {
* negx: './dynamicSkyData/night/negx.png', // 左
* negy: './dynamicSkyData/night/negy.png', // 下
* negz: './dynamicSkyData/night/negz.png', // 前
* posx: './dynamicSkyData/night/posx.png', // 右
* posy: './dynamicSkyData/night/posy.png', // 上
* posz: './dynamicSkyData/night/posz.png' // 后
* }
* });
*
* // 创建月亮纹理
* const moonTexture = new THING.ImageTexture({
* url: './dynamicSkyData/texture/Full_Moon_glow.jpg',
* wrapTypeT: THING.ImageWrapType.ClampToEdge,
* wrapTypeS: THING.ImageWrapType.ClampToEdge,
* });
*
* // 创建云层纹理
* const cloudsTexture = new THING.ImageTexture('./dynamicSkyData/texture/Sample_Rectangular_2048.jpg');
*
* // 创建星星数据
* const starsData = './dynamicSkyData/data/StarsData.bytes';
*
* // 启用动态天空并设置纹理
* app.camera.dynamicSky.active = true;
* app.camera.dynamicSky.timeline = 13;
* app.camera.dynamicSky.nightSkyTexture = nightSkyTexture;
* app.camera.dynamicSky.moonTexture = moonTexture;
* app.camera.dynamicSky.starsData = starsData;
* app.camera.dynamicSky.cloudsTexture = cloudsTexture;
*
* // 调整天空参数
* app.camera.dynamicSky.lightExposure = 1.0; // 设置光照曝光度
* app.camera.dynamicSky.exposure = 0.8; // 设置天空曝光度
* app.camera.dynamicSky.sunEquatorOffset = -40; // 设置太阳赤道偏移量
* app.camera.dynamicSky.sunLightIntensity = 1.0; // 设置日光强度
* app.camera.dynamicSky.moonLightIntensity = 0.2;// 设置月光强度
* @public
*/
class CameraDynamicSkyComponent extends BaseComponent {
/**
* 相机动态天空组件,用于管理相机的动态天空效果。
*/
constructor() {
super();
this[__.private] = {};
let _private = this[__.private];
_private.activeSkyRender = false;
_private.envMap = new CubeTexture();
_private._dynamicSky = Utils.createObject('DynamicSky', {
app: this.app,
cubeTexture: _private.envMap.getTextureResource(),
});
_private._dynamicSky.setTimeline(10);
_private._light = null;
_private._sunLightIntensity = 1.0;
_private._moonLightIntensity = 0.2;
_private.hemisphereLight = null;
_private.eventListener = this._onTimelineChange.bind(this);
_private.eventListenerTag = `CameraDynamicSkyComponent_${_id++}`;
}
// #region Private Functions
/**
* Load the stars data
* @param {string | Float32Array} data
* @private
*/
async _loadStarsData(data) {
if (Utils.isString(data)) {
let _buffer = await Utils.loadBinaryFile(data);
let starsData = new Float32Array(_buffer);
return starsData;
}
if (!(data instanceof Float32Array)) {
return null;
}
}
/**
* Update the lights.
* @param {string | Float32Array} data
* @private
*/
_updateLights() {
let _private = this[__.private];
if (this._active) {
if (this.timeline < 18.2 && this.timeline > 5.8) {
if (_private._light) {
_private._light.visible = true;
_private._dynamicSky.getSunPhiAndTheta(_tempArray);
_private._light.adapter.vertAngle = MathUtils.radToDeg(_tempArray[1]);
_private._light.adapter.horzAngle = MathUtils.radToDeg(_tempArray[0]);
_private._light.color = _private._dynamicSky.getSunLightColor(_tempArray);
_private._light.intensity = _private._sunLightIntensity;
}
}
else {
if (_private._light) {
_private._light.visible = true;
_private._dynamicSky.getMoonPhiAndTheta(_tempArray);
_private._light.adapter.vertAngle = MathUtils.radToDeg(_tempArray[1]);
_private._light.adapter.horzAngle = MathUtils.radToDeg(_tempArray[0]);
_private._light.color = _private._dynamicSky.getMoonLightColor(_tempArray);
_private._light.intensity = _private._moonLightIntensity;
}
}
if (_private._hemisphereLight) {
_private._hemisphereLight.color = _private._dynamicSky.getHemisphereLightColor(_tempArray);
_private._hemisphereLight.groundColor = _private._dynamicSky.getHemisphereLightGroundColor(_tempArray);
}
}
// day: 5.8- 18.2
}
/**
* 获取时间线。
* @type {number}
* @default 13
* @private
*/
_getTimeline() {
let _private = this[__.private];
return _private._dynamicSky.getTimeline();
}
/**
* 设置时间线。
* @type {number}
* @default 10
* @private
*/
_setTimeline(value) {
let _private = this[__.private];
_private._dynamicSky.setTimeline(value);
this._updateLights();
}
_onTimelineChange(event) {
const timeOfDay = event.timeOfDay;
this._setTimeline(timeOfDay / 3600);
}
// #endregion
// #region BaseComponent Overrides
onAdd(object) {
super.onAdd(object);
let _private = this[__.private];
_private._light = this.app.scene.mainLight;
// Keep it alive to prevent destroy action
this.enable = false;
}
onRemove() {
let _private = this[__.private];
if (_private._dynamicSky) {
_private._dynamicSky.dispose();
_private._dynamicSky = null;
}
super.onRemove();
}
onUpdate(deltaTime) {
let _private = this[__.private];
if (_private._dynamicSky && this._active) {
_private._dynamicSky.update(deltaTime);
}
}
onActiveChange(value) {
let _private = this[__.private];
if (value) {
if (_private.activeSkyRender) {
this._oldBackground = this.object.background;
this.object.background = _private.envMap;
}
this.app.on(EventType.TimelineChange, _private.eventListener, _private.eventListenerTag);
}
else {
if (this._oldBackground) {
this.object.background = this._oldBackground;
}
this.app.off(EventType.TimelineChange, _private.eventListenerTag);
}
}
onImport(param) {
this.active = Utils.parseValue(param['active'], this.active);
this.activeSkyRender = Utils.parseValue(param['activeSkyRender'], this.activeSkyRender);
this.timeline = Utils.parseValue(param['timeline'], this.timeline);
this.lightExposure = Utils.parseValue(param['lightExposure'], this.lightExposure);
this.exposure = Utils.parseValue(param['exposure'], this.exposure);
this.sunEquatorOffset = Utils.parseValue(param['sunEquatorOffset'], this.sunEquatorOffset);
this.lightColorGradient = Utils.parseValue(param['lightColorGradient'], this.lightColorGradient);
this.skyColorGradient = Utils.parseValue(param['skyColorGradient'], this.skyColorGradient);
this.groundColorGradient = Utils.parseValue(param['groundColorGradient'], this.groundColorGradient);
this.sunLightIntensity = Utils.parseValue(param['sunLightIntensity'], this.sunLightIntensity);
this.moonLightIntensity = Utils.parseValue(param['moonLightIntensity'], this.moonLightIntensity);
const light = this.app.objectManager.getBaseObjectFromUUID(Utils.parseValue(param['light']))
if (light) {
this.light = light;
}
const hemisphereLight = this.app.objectManager.getBaseObjectFromUUID(Utils.parseValue(param['hemisphereLight']))
if (hemisphereLight) {
this.hemisphereLight = hemisphereLight;
}
}
onExport() {
let result = {
active: this.active,
activeSkyRender: this.activeSkyRender,
timeline: this.timeline,
lightExposure: this.lightExposure,
exposure: this.exposure,
sunEquatorOffset: this.sunEquatorOffset,
lightColorGradient: this.lightColorGradient,
skyColorGradient: this.skyColorGradient,
groundColorGradient: this.groundColorGradient,
sunLightIntensity: this.sunLightIntensity,
moonLightIntensity: this.moonLightIntensity,
}
// 如果灯光不是主光源,则添加灯光的uuid(主光源是默认值)
if (this.light && this.light != this.app.scene.mainLight) {
result.light = this.light.uuid;
}
if (this.hemisphereLight) {
result.hemisphereLight = this.hemisphereLight.uuid;
}
return result
}
// #endregion
/**
* 获取/设置天空的启用状态。
* @type {boolean}
* @public
* @deprecated
*/
async init(options) {
let _private = this[__.private];
_private._hemisphereLight = new HemisphereLight({
intensity: 0.2
});
this.app.objectManager.addKeepAliveObject(_private._hemisphereLight);
_private._hemisphereLight._isInternalCreation_ = true;
let nightSkyTexture = options.nightSkyTexture;
if (nightSkyTexture) {
_private._dynamicSky.setNightSkyTexture(nightSkyTexture.getTextureResource());
}
_private.nightSkyTexture = nightSkyTexture;
let moonTexture = options.moonTexture;
if (moonTexture) {
moonTexture.wrapTypeT = ImageWrapType.ClampToEdge;
moonTexture.wrapTypeS = ImageWrapType.ClampToEdge;
_private._dynamicSky.setMoonTexture(moonTexture.getTextureResource());
}
let cloudsTexture = options.cloudsTexture;
if (cloudsTexture) {
_private._dynamicSky.setCloudsTexture(cloudsTexture.getTextureResource());
}
let starsData = options.starsData;
if (starsData) {
starsData = await this._loadStarsData(options.starsData);
_private._dynamicSky.setStarsData(starsData);
}
if (this._active) {
this._oldBackground = this.object.background;
this.object.background = _private.envMap;
}
}
/**
* 获取/设置天空的启用状态。
* @type {boolean}
* @public
* @deprecated
*/
get enable() {
return this.active;
}
set enable(value) {
this.activeSkyRender = value
this.active = value;
}
/**
* 设置/获取时间线。
* @type {number}
* @default 10
* @public
* @deprecated
*/
get timeline() {
return this._getTimeline();
}
set timeline(value) {
this._setTimeline(value);
}
/**
* 设置天空的夜晚贴图。
* @type {CubeTextureResource}
* @public
*/
set nightSkyTexture(value) {
if (!value) {
return;
}
let _private = this[__.private];
_private._dynamicSky.setNightSkyTexture(value.getTextureResource());
}
/**
* 设置天空的云层贴图。
* @type {ImageTextureResource}
* @public
*/
set cloudsTexture(value) {
if (!value) {
return;
}
let _private = this[__.private];
_private._dynamicSky.setCloudsTexture(value.getTextureResource());
}
/**
* 设置天空的月亮贴图。
* @type {ImageTextureResource}
* @public
*/
set moonTexture(value) {
if (!value) {
return;
}
let _private = this[__.private];
_private._dynamicSky.setMoonTexture(value.getTextureResource());
}
/**
* 设置天空的星星数据。
* @type {string | Float32Array}
* @public
*/
set starsData(value) {
if (!value) {
return;
}
let _private = this[__.private];
this._loadStarsData(value).then((data) => {
_private._dynamicSky.setStarsData(data);
})
}
/**
* 获取天空的贴图。
* @type {CubeTextureResource}
* @public
*/
get envMap() {
let _private = this[__.private];
return _private.envMap;
}
/**
* 设置/获取纹理的尺寸。
* @type {Array<number>}
* @default - [1024,1024]
* @public
*/
set textureSize(value) {
let _private = this[__.private];
return _private._dynamicSky.setTextureSize(value);
}
get textureSize() {
let _private = this[__.private];
return _private._dynamicSky.getTextureSize(_tempArray);
}
/**
* 设置/获取天空的光照曝光度。
* @type {number}
* @default 1.0
* @public
*/
get lightExposure() {
let _private = this[__.private];
return _private._dynamicSky.getLightExposure();
}
set lightExposure(value) {
let _private = this[__.private];
_private._dynamicSky.setLightExposure(value);
this._updateLights();
}
/**
* 设置/获取天空的曝光度。
* @type {number}
* @default 0.8
* @public
*/
get exposure() {
let _private = this[__.private];
return _private._dynamicSky.getExposure();
}
set exposure(value) {
let _private = this[__.private];
_private._dynamicSky.setExposure(value);
}
/**
* 设置/获取太阳赤道偏移量。
* @type {number}
* @default -40
* @public
*/
get sunEquatorOffset() {
let _private = this[__.private];
return _private._dynamicSky.getSunEquatorOffset();
}
set sunEquatorOffset(value) {
let _private = this[__.private];
_private._dynamicSky.setSunEquatorOffset(value);
this._updateLights();
}
/**
* 获取主光。
* @type {DirectionalLight}
* @public
*/
get light() {
let _private = this[__.private];
return _private._light;
}
set light(value) {
let _private = this[__.private];
if (value) {
_private._light = value
this._updateLights()
}
}
/**
* 获取半球光。
* @type {HemisphereLight}
* @public
*/
get hemisphereLight() {
let _private = this[__.private];
return _private._hemisphereLight;
}
set hemisphereLight(value) {
let _private = this[__.private];
if (value) {
_private._hemisphereLight = value
this._updateLights()
}
}
/**
* 设置白天日光强度。
* @type {number}
* @public
*/
get sunLightIntensity() {
let _private = this[__.private];
return _private._sunLightIntensity;
}
set sunLightIntensity(value) {
let _private = this[__.private];
_private._sunLightIntensity = value;
this._updateLights();
}
/**
* 设置夜晚日光强度。
* @type {number}
* @public
*/
get moonLightIntensity() {
let _private = this[__.private];
return _private._moonLightIntensity;
}
set moonLightIntensity(value) {
let _private = this[__.private];
_private._moonLightIntensity = value;
this._updateLights();
}
/**
* 设置是否渲染天空盒参数。
* @type {boolean}
* @public
*/
set activeSkyRender(value) {
let _private = this[__.private];
if (_private.activeSkyRender === value) {
return;
}
if (value && this.active) {
this._oldBackground = this.object.background;
this.object.background = _private.envMap;
}
else {
if (this._oldBackground) {
this.object.background = this._oldBackground;
}
}
_private.activeSkyRender = value;
_private._dynamicSky.setIsSkyRender(value);
}
get activeSkyRender() {
let _private = this[__.private];
return _private.activeSkyRender;
}
/**
* 设置渲染光颜色。
* @type {object}
* @default
* {
0: [85 / 255, 99 / 255, 112 / 255],
0.49: [85 / 255, 99 / 255, 112 / 255],
0.51: [245 / 255, 173 / 255, 84 / 255],
0.57: [249 / 255, 208 / 255, 144 / 255],
1: [252 / 255, 222 / 255, 186 / 255]
}
* @public
*/
get lightColorGradient() {
let _private = this[__.private];
return _private._dynamicSky.getLightColorGradient();
}
set lightColorGradient(value) {
let _private = this[__.private];
_private._dynamicSky.setLightColorGradient(value);
this._updateLights();
}
/**
* 设置渲染天光颜色。
* @type {object}
* @default
* {
0: [180 / 255, 220 / 255, 255 / 255],
0.39: [180 / 255, 220 / 255, 255 / 255],
0.51: [180 / 255, 220 / 255, 255 / 255],
0.7: [180 / 255, 220 / 255, 255 / 255],
1: [203 / 255, 146 / 255, 65 / 255]
}
* @public
*/
get skyColorGradient() {
let _private = this[__.private];
return _private._dynamicSky.getSkyColorGradient();
}
set skyColorGradient(value) {
let _private = this[__.private];
_private._dynamicSky.setSkyColorGradient(value);
this._updateLights();
}
/**
* 设置渲染地面光颜色。
* @type {object}
* @default
*{
0: [63 / 255, 149 / 255, 255 / 255],
0.39: [180 / 255, 220 / 255, 255 / 255],
0.51: [180 / 255, 220 / 255, 255 / 255],
0.7: [180 / 255, 220 / 255, 255 / 255],
1: [63 / 255, 149 / 255, 255 / 255]
}
* @public
*/
get groundColorGradient() {
let _private = this[__.private];
return _private._dynamicSky.getGroundColorGradient();
}
set groundColorGradient(value) {
let _private = this[__.private];
_private._dynamicSky.setGroundColorGradient(value);
this._updateLights();
}
}
export { CameraDynamicSkyComponent }