加入导出功能
This commit is contained in:
13
index.html
13
index.html
@@ -60,17 +60,6 @@
|
|||||||
to { transform: rotate(360deg); }
|
to { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#stats {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 20px;
|
|
||||||
background: rgba(0, 0, 0, 0.7);
|
|
||||||
padding: 10px 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: white;
|
|
||||||
font-size: 12px;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -82,8 +71,6 @@
|
|||||||
|
|
||||||
<div id="container"></div>
|
<div id="container"></div>
|
||||||
|
|
||||||
<div id="stats">FPS: <span id="fps">60</span></div>
|
|
||||||
|
|
||||||
<script type="module" src="/src/main.js"></script>
|
<script type="module" src="/src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
|||||||
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
||||||
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
|
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
|
||||||
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
||||||
|
import Stats from 'three/addons/libs/stats.module.js';
|
||||||
import { TerrainGenerator } from './TerrainGenerator.js';
|
import { TerrainGenerator } from './TerrainGenerator.js';
|
||||||
import { VegetationSystem } from './VegetationSystem.js';
|
import { VegetationSystem } from './VegetationSystem.js';
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ export class OceanScene {
|
|||||||
this.bloomPass = null;
|
this.bloomPass = null;
|
||||||
this.rainPass = null;
|
this.rainPass = null;
|
||||||
this.snowPass = null;
|
this.snowPass = null;
|
||||||
|
this.stats = null;
|
||||||
this.cloudGroup = null;
|
this.cloudGroup = null;
|
||||||
this.cloudMaterials = [];
|
this.cloudMaterials = [];
|
||||||
this.cloudLayers = [];
|
this.cloudLayers = [];
|
||||||
@@ -83,8 +85,6 @@ export class OceanScene {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.clock = new THREE.Clock();
|
this.clock = new THREE.Clock();
|
||||||
this.frameCount = 0;
|
|
||||||
this.lastTime = performance.now();
|
|
||||||
this.lightningFlash = 0;
|
this.lightningFlash = 0;
|
||||||
this.lightningLocalFlash = 0;
|
this.lightningLocalFlash = 0;
|
||||||
this.lightningBurstEnd = 0;
|
this.lightningBurstEnd = 0;
|
||||||
@@ -94,6 +94,7 @@ export class OceanScene {
|
|||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
this.initRenderer();
|
this.initRenderer();
|
||||||
|
this.initStats();
|
||||||
this.initScene();
|
this.initScene();
|
||||||
this.initCamera();
|
this.initCamera();
|
||||||
this.initControls();
|
this.initControls();
|
||||||
@@ -124,6 +125,18 @@ export class OceanScene {
|
|||||||
this.container.appendChild(this.renderer.domElement);
|
this.container.appendChild(this.renderer.domElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initStats() {
|
||||||
|
this.stats = new Stats();
|
||||||
|
this.stats.showPanel(0);
|
||||||
|
this.stats.dom.style.position = 'fixed';
|
||||||
|
this.stats.dom.style.left = '0';
|
||||||
|
this.stats.dom.style.top = '0';
|
||||||
|
this.stats.dom.style.bottom = 'auto';
|
||||||
|
this.stats.dom.style.margin = '0';
|
||||||
|
this.stats.dom.style.zIndex = '120';
|
||||||
|
this.container.appendChild(this.stats.dom);
|
||||||
|
}
|
||||||
|
|
||||||
initScene() {
|
initScene() {
|
||||||
this.scene = new THREE.Scene();
|
this.scene = new THREE.Scene();
|
||||||
this.scene.fog = new THREE.FogExp2(0x8cb8d4, 0.0006);
|
this.scene.fog = new THREE.FogExp2(0x8cb8d4, 0.0006);
|
||||||
@@ -1535,6 +1548,7 @@ export class OceanScene {
|
|||||||
|
|
||||||
animate() {
|
animate() {
|
||||||
requestAnimationFrame(() => this.animate());
|
requestAnimationFrame(() => this.animate());
|
||||||
|
this.stats?.begin();
|
||||||
|
|
||||||
const time = this.clock.getElapsedTime();
|
const time = this.clock.getElapsedTime();
|
||||||
this.updateLightning(time);
|
this.updateLightning(time);
|
||||||
@@ -1589,18 +1603,7 @@ export class OceanScene {
|
|||||||
} else {
|
} else {
|
||||||
this.renderer.render(this.scene, this.camera);
|
this.renderer.render(this.scene, this.camera);
|
||||||
}
|
}
|
||||||
|
this.stats?.end();
|
||||||
this.frameCount++;
|
|
||||||
const currentTime = performance.now();
|
|
||||||
if (currentTime - this.lastTime >= 1000) {
|
|
||||||
const fps = Math.round(this.frameCount * 1000 / (currentTime - this.lastTime));
|
|
||||||
const fpsElement = document.getElementById('fps');
|
|
||||||
if (fpsElement) {
|
|
||||||
fpsElement.textContent = fps;
|
|
||||||
}
|
|
||||||
this.frameCount = 0;
|
|
||||||
this.lastTime = currentTime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hideLoading() {
|
hideLoading() {
|
||||||
|
|||||||
90
src/main.js
90
src/main.js
@@ -37,6 +37,89 @@ function setupControls(oceanScene) {
|
|||||||
gui.domElement.style.zIndex = '120';
|
gui.domElement.style.zIndex = '120';
|
||||||
|
|
||||||
const params = oceanScene.params;
|
const params = oceanScene.params;
|
||||||
|
const presetKeys = [
|
||||||
|
'elevation',
|
||||||
|
'azimuth',
|
||||||
|
'exposure',
|
||||||
|
'turbidity',
|
||||||
|
'rayleigh',
|
||||||
|
'bloomStrength',
|
||||||
|
'bloomRadius',
|
||||||
|
'cloudCoverage',
|
||||||
|
'cloudDensity',
|
||||||
|
'cloudElevation',
|
||||||
|
'fogDensity',
|
||||||
|
'fogHeight',
|
||||||
|
'fogRange',
|
||||||
|
'rainEnabled',
|
||||||
|
'rainScreenIntensity',
|
||||||
|
'rainVeilIntensity',
|
||||||
|
'rainDropSize',
|
||||||
|
'rainSpeed',
|
||||||
|
'rainAudioEnabled',
|
||||||
|
'rainAudioVolume',
|
||||||
|
'snowEnabled',
|
||||||
|
'snowIntensity',
|
||||||
|
'snowSpeed',
|
||||||
|
'lightningEnabled',
|
||||||
|
'lightningIntensity'
|
||||||
|
];
|
||||||
|
const presetComments = {
|
||||||
|
elevation: '太阳高度角',
|
||||||
|
azimuth: '太阳方位角',
|
||||||
|
exposure: '场景曝光度',
|
||||||
|
turbidity: '天空浑浊度',
|
||||||
|
rayleigh: '瑞利散射强度',
|
||||||
|
bloomStrength: '泛光强度',
|
||||||
|
bloomRadius: '泛光扩散范围',
|
||||||
|
cloudCoverage: '云层覆盖度',
|
||||||
|
cloudDensity: '云层密度',
|
||||||
|
cloudElevation: '云层高度',
|
||||||
|
fogDensity: '雾气浓度',
|
||||||
|
fogHeight: '雾气高度',
|
||||||
|
fogRange: '雾气范围',
|
||||||
|
rainEnabled: '是否启用雨效',
|
||||||
|
rainScreenIntensity: '屏幕雨滴强度',
|
||||||
|
rainVeilIntensity: '雨线强度',
|
||||||
|
rainDropSize: '雨滴尺寸',
|
||||||
|
rainSpeed: '雨效速度',
|
||||||
|
rainAudioEnabled: '是否启用雨声',
|
||||||
|
rainAudioVolume: '雨声音量',
|
||||||
|
snowEnabled: '是否启用降雪',
|
||||||
|
snowIntensity: '雪量',
|
||||||
|
snowSpeed: '降雪速度',
|
||||||
|
lightningEnabled: '是否启用雷闪',
|
||||||
|
lightningIntensity: '雷闪强度'
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportActions = {
|
||||||
|
导出预设: () => {
|
||||||
|
const preset = {
|
||||||
|
meta: {
|
||||||
|
version: 1,
|
||||||
|
comment: '场景预设导出文件',
|
||||||
|
exportedAt: new Date().toISOString()
|
||||||
|
},
|
||||||
|
comments: Object.fromEntries(
|
||||||
|
presetKeys.map((key) => [key, presetComments[key]])
|
||||||
|
),
|
||||||
|
params: Object.fromEntries(
|
||||||
|
presetKeys.map((key) => [key, params[key]])
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const blob = new Blob([JSON.stringify(preset, null, 2)], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `scene-preset-${stamp}.json`;
|
||||||
|
link.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
gui.add(exportActions, '导出预设');
|
||||||
|
|
||||||
const skyFolder = gui.addFolder('天空');
|
const skyFolder = gui.addFolder('天空');
|
||||||
skyFolder.add(params, 'elevation', 0, 90, 0.1).name('太阳高度').onChange((value) => oceanScene.setSunElevation(value));
|
skyFolder.add(params, 'elevation', 0, 90, 0.1).name('太阳高度').onChange((value) => oceanScene.setSunElevation(value));
|
||||||
@@ -46,8 +129,8 @@ function setupControls(oceanScene) {
|
|||||||
skyFolder.add(params, 'rayleigh', 0, 4, 0.01).name('瑞利散射').onChange((value) => oceanScene.setRayleigh(value));
|
skyFolder.add(params, 'rayleigh', 0, 4, 0.01).name('瑞利散射').onChange((value) => oceanScene.setRayleigh(value));
|
||||||
|
|
||||||
const bloomFolder = gui.addFolder('泛光');
|
const bloomFolder = gui.addFolder('泛光');
|
||||||
bloomFolder.add(params, 'bloomStrength', 0, 3, 0.01).name('强度').onChange((value) => oceanScene.setBloomStrength(value));
|
bloomFolder.add(params, 'bloomStrength', 0, 1, 0.01).name('强度').onChange((value) => oceanScene.setBloomStrength(value));
|
||||||
bloomFolder.add(params, 'bloomRadius', 0, 1, 0.01).name('扩散').onChange((value) => oceanScene.setBloomRadius(value));
|
bloomFolder.add(params, 'bloomRadius', 0, 3, 0.01).name('扩散').onChange((value) => oceanScene.setBloomRadius(value));
|
||||||
|
|
||||||
const cloudFolder = gui.addFolder('云层');
|
const cloudFolder = gui.addFolder('云层');
|
||||||
cloudFolder.add(params, 'cloudCoverage', 0, 1, 0.01).name('覆盖度').onChange((value) => oceanScene.setCloudCoverage(value));
|
cloudFolder.add(params, 'cloudCoverage', 0, 1, 0.01).name('覆盖度').onChange((value) => oceanScene.setCloudCoverage(value));
|
||||||
@@ -75,8 +158,7 @@ function setupControls(oceanScene) {
|
|||||||
snowFolder.add(params, 'snowIntensity', 0, 1.5, 0.01).name('雪量').onChange((value) => oceanScene.setSnowIntensity(value));
|
snowFolder.add(params, 'snowIntensity', 0, 1.5, 0.01).name('雪量').onChange((value) => oceanScene.setSnowIntensity(value));
|
||||||
snowFolder.add(params, 'snowSpeed', 0.2, 2.2, 0.01).name('速度').onChange((value) => oceanScene.setSnowSpeed(value));
|
snowFolder.add(params, 'snowSpeed', 0.2, 2.2, 0.01).name('速度').onChange((value) => oceanScene.setSnowSpeed(value));
|
||||||
|
|
||||||
skyFolder.open();
|
gui.close();
|
||||||
rainFolder.open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error);
|
main().catch(console.error);
|
||||||
|
|||||||
Reference in New Issue
Block a user