chore(controller): three-player-controller als Ordner statt Submodul

Das Submodul zeigte auf GitHub, der eingetragene Stand 028c652 lag aber nur
lokal vor: GitHub-Master ac39682 plus Showcase mit Figuren und launch.json.
Frische Klone konnten den Controller deshalb nicht laden. Jetzt liegt dieser
Stand als normaler Ordner im Repo, ohne Verweis auf GitHub.

dist/ und node_modules/ im Controller bleiben ignoriert und werden wie bisher
lokal gebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Opus 5 committed 2026-09-15 21:27:03 +02:00
1 parent 780e246fe5
commit fb38652e7f
153 files changed
+42561 -4

No files matched your search

@@ -0,0 +1,124 @@
import {
ACESFilmicToneMapping,
DirectionalLight,
MathUtils,
PerspectiveCamera,
Scene,
VSMShadowMap,
WebGLRenderer,
} from "three";
import { MapControls } from "three/examples/jsm/Addons.js";
import { LightProbeGrid } from "three/addons/lighting/LightProbeGrid.js";
import { LightProbeGridHelper } from "three/addons/helpers/LightProbeGridHelper.js";
export function createSceneSetup({ container }) {
// ==================== 渲染器 ====================
const renderer = new WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.toneMapping = ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = VSMShadowMap;
container.appendChild(renderer.domElement);
// ==================== 场景 & 相机 ====================
const scene = new Scene();
const camera = new PerspectiveCamera(
60,
container.clientWidth / container.clientHeight,
0.1,
2000
);
// ==================== 控制器 ====================
const controls = new MapControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.1;
controls.maxDistance = 2000;
// ==================== 参数 ====================
const params = {
showLightHelper: true,
lightAzimuth: 45,
lightElevation: 45,
lightIntensity: 10,
shadows: true,
probesEnabled: true,
showProbes: false,
probeSize: 0.5,
boundsX: 8, boundsY: 3.2, boundsZ: -2,
sizeX: 40, sizeY: 3, sizeZ: 25,
countX: 20, countY: 4, countZ: 10,
};
// ==================== 平行光 ====================
const dirLight = new DirectionalLight(0xfff2dc, params.lightIntensity);
dirLight.castShadow = true;
dirLight.shadow.mapSize.setScalar(2048);
dirLight.shadow.camera.left = -50;
dirLight.shadow.camera.right = 50;
dirLight.shadow.camera.top = 50;
dirLight.shadow.camera.bottom = -50;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 200;
dirLight.shadow.bias = -0.001;
scene.add(dirLight);
scene.add(dirLight.target);
function updateLightPosition() {
const azimuth = MathUtils.degToRad(params.lightAzimuth);
const elevation = MathUtils.degToRad(params.lightElevation);
const radius = 100;
const h = Math.cos(elevation) * radius;
const v = Math.sin(elevation) * radius;
dirLight.position.set(Math.cos(azimuth) * h, v, Math.sin(azimuth) * h);
dirLight.target.position.set(0, 0, 0);
dirLight.target.updateMatrixWorld();
}
updateLightPosition();
// ==================== 光探针 ====================
let probes = null;
let probesHelper = null;
let isBaking = false;
let bakeQueued = false;
async function bakeProbes() {
if (isBaking) { bakeQueued = true; return; }
isBaking = true;
do {
bakeQueued = false;
if (probes) { scene.remove(probes); probes.dispose(); }
probes = new LightProbeGrid(
params.sizeX, params.sizeY, params.sizeZ,
params.countX, params.countY, params.countZ
);
probes.position.set(params.boundsX, params.boundsY, params.boundsZ);
probes.updateMatrixWorld(true); // 强制更新世界矩阵,否则 bake() 读到旧位置
if (probesHelper) probesHelper.visible = false;
const far = Math.max(params.sizeX, params.sizeY, params.sizeZ) * 2;
probes.bake(renderer, scene, { cubemapSize: 32, near: 0.05, far });
probes.visible = params.probesEnabled;
scene.add(probes);
if (!probesHelper) {
probesHelper = new LightProbeGridHelper(probes, params.probeSize);
scene.add(probesHelper);
} else {
probesHelper.probes = probes;
probesHelper.update();
}
probesHelper.position.set(params.boundsX, params.boundsY, params.boundsZ);
probesHelper.visible = params.showProbes;
} while (bakeQueued);
isBaking = false;
}
return { scene, renderer, camera, controls, dirLight, bakeProbes };
}