Tweaked scene - tall lamp
This commit is contained in:
+282
-105
@@ -62,14 +62,18 @@
|
||||
|
||||
<!-- 3D Canvas will be injected here by Three.js --><script>
|
||||
// --- Global Variables ---
|
||||
let scene, camera, renderer, tvScreen, videoTexture, dust, screenLight, lampLight;
|
||||
let scene, camera, renderer, tvScreen, videoTexture, dust, screenLight, lampLightPoint, lampLightSpot;
|
||||
let isVideoLoaded = false;
|
||||
let videoUrls = []; // Array to hold all video URLs
|
||||
let currentVideoIndex = -1; // Index of the currently playing video
|
||||
|
||||
const originalLampIntensity = 1.5; // Base intensity for the flickering lamp
|
||||
const originalScreenIntensity = 1.5; // Base intensity for the screen glow
|
||||
const originalScreenIntensity = 0.2; // Base intensity for the screen glow
|
||||
const screenIntensityPulse = 0.4;
|
||||
|
||||
const roomSize = 5;
|
||||
const roomHeight = 3;
|
||||
|
||||
const container = document.body;
|
||||
const videoElement = document.getElementById('video');
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
@@ -78,7 +82,24 @@
|
||||
const nextTapeButton = document.getElementById('nextTapeButton');
|
||||
const loader = new THREE.TextureLoader();
|
||||
|
||||
const debugLight = false;
|
||||
const debugLight = true;
|
||||
|
||||
// --- Utility: Random Color (seeded) ---
|
||||
function getRandomColor() {
|
||||
const hue = seededRandom();
|
||||
const saturation = 0.6 + seededRandom() * 0.4;
|
||||
const lightness = 0.3 + seededRandom() * 0.4;
|
||||
return new THREE.Color().setHSL(hue, saturation, lightness).getHex();
|
||||
}
|
||||
|
||||
// --- Seedable Random Number Generator (Mulberry32) ---
|
||||
let seed = 12345; // Default seed, will be overridden per shelf
|
||||
function seededRandom() {
|
||||
let t = seed += 0x6D2B79F5;
|
||||
t = Math.imul(t ^ t >>> 15, t | 1);
|
||||
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
||||
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
||||
}
|
||||
|
||||
// --- Initialization ---
|
||||
function init() {
|
||||
@@ -87,7 +108,8 @@
|
||||
scene.background = new THREE.Color(0x000000);
|
||||
|
||||
// 2. Camera Setup
|
||||
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
const FOV = 65;
|
||||
camera = new THREE.PerspectiveCamera(FOV, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
camera.position.set(0, 1.5, 4);
|
||||
|
||||
// 3. Renderer Setup
|
||||
@@ -104,17 +126,6 @@
|
||||
const ambientLight = new THREE.AmbientLight(0x111111);
|
||||
scene.add(ambientLight);
|
||||
|
||||
// Light from the screen (initially low intensity, will increase when video loads)
|
||||
screenLight = new THREE.PointLight(0xffffff, 0.1, 10);
|
||||
screenLight.position.set(0, 1.7, 1.2);
|
||||
// Screen light casts shadows
|
||||
screenLight.castShadow = true;
|
||||
screenLight.shadow.mapSize.width = 1024;
|
||||
screenLight.shadow.mapSize.height = 1024;
|
||||
screenLight.shadow.camera.near = 0.2;
|
||||
screenLight.shadow.camera.far = 10;
|
||||
scene.add(screenLight);
|
||||
|
||||
// 5. Build the entire scene with TV and surrounding objects
|
||||
createSceneObjects();
|
||||
|
||||
@@ -131,8 +142,8 @@
|
||||
scene.add(screenHelper);
|
||||
|
||||
// Lamp Helper will now work since lampLight is added to the scene
|
||||
const lampHelper = new THREE.PointLightHelper(lampLight, 0.1, 0x00ff00); // Green for lamp
|
||||
scene.add(lampHelper);
|
||||
const lampHelperPoint = new THREE.PointLightHelper(lampLightPoint, 0.1, 0x00ff00); // Green for lamp
|
||||
scene.add(lampHelperPoint);
|
||||
}
|
||||
|
||||
// 9. Event Listeners
|
||||
@@ -166,9 +177,6 @@
|
||||
specular: 0x111111 // Subtle reflection
|
||||
});
|
||||
|
||||
const roomSize = 15;
|
||||
const roomHeight = 8;
|
||||
|
||||
// 1. Back Wall (behind the TV)
|
||||
const backWall = new THREE.Mesh(new THREE.PlaneGeometry(roomSize, roomHeight), wallMaterial);
|
||||
backWall.position.set(0, roomHeight / 2, -roomSize / 2);
|
||||
@@ -249,8 +257,152 @@
|
||||
scene.add(vBar);
|
||||
}
|
||||
|
||||
// --- Scene Modeling Function ---
|
||||
function createSceneObjects() {
|
||||
function createBookshelf(x, z, rotationY, uniqueSeed) {
|
||||
seed = uniqueSeed; // Reset seed for this specific shelf instance
|
||||
|
||||
const shelfHeight = 2.2;
|
||||
const shelfDepth = 0.35;
|
||||
const shelfWidth = 1.2;
|
||||
const numShelves = 6;
|
||||
const woodThickness = 0.04;
|
||||
const woodColor = 0x5c4033; // Darker, richer wood
|
||||
|
||||
const shelfGroup = new THREE.Group();
|
||||
shelfGroup.position.set(x, 0, z);
|
||||
shelfGroup.rotation.y = rotationY;
|
||||
|
||||
const woodMaterial = new THREE.MeshPhongMaterial({ color: woodColor, shininess: 30 });
|
||||
|
||||
// 1. Build Frame (Hollow box)
|
||||
// Back Panel
|
||||
const backGeo = new THREE.BoxGeometry(shelfWidth, shelfHeight, woodThickness);
|
||||
const backPanel = new THREE.Mesh(backGeo, woodMaterial);
|
||||
backPanel.position.set(0, shelfHeight / 2, -shelfDepth / 2 + woodThickness / 2);
|
||||
backPanel.castShadow = true;
|
||||
backPanel.receiveShadow = true;
|
||||
shelfGroup.add(backPanel);
|
||||
|
||||
// Side Panels (Left & Right)
|
||||
const sideGeo = new THREE.BoxGeometry(woodThickness, shelfHeight, shelfDepth);
|
||||
const leftSide = new THREE.Mesh(sideGeo, woodMaterial);
|
||||
leftSide.position.set(-shelfWidth / 2 + woodThickness / 2, shelfHeight / 2, 0);
|
||||
leftSide.castShadow = true;
|
||||
leftSide.receiveShadow = true;
|
||||
shelfGroup.add(leftSide);
|
||||
|
||||
const rightSide = new THREE.Mesh(sideGeo, woodMaterial);
|
||||
rightSide.position.set(shelfWidth / 2 - woodThickness / 2, shelfHeight / 2, 0);
|
||||
rightSide.castShadow = true;
|
||||
rightSide.receiveShadow = true;
|
||||
shelfGroup.add(rightSide);
|
||||
|
||||
// Top & Bottom Panels
|
||||
const topBottomGeo = new THREE.BoxGeometry(shelfWidth, woodThickness, shelfDepth);
|
||||
const bottomPanel = new THREE.Mesh(topBottomGeo, woodMaterial);
|
||||
bottomPanel.position.set(0, woodThickness / 2, 0);
|
||||
bottomPanel.receiveShadow = true;
|
||||
shelfGroup.add(bottomPanel);
|
||||
|
||||
const topPanel = new THREE.Mesh(topBottomGeo, woodMaterial);
|
||||
topPanel.position.set(0, shelfHeight - woodThickness / 2, 0);
|
||||
topPanel.castShadow = true;
|
||||
shelfGroup.add(topPanel);
|
||||
|
||||
// 2. Individual Shelves & Books
|
||||
const internalHeight = shelfHeight - (2 * woodThickness);
|
||||
const shelfSpacing = internalHeight / numShelves;
|
||||
const internalWidth = shelfWidth - (2 * woodThickness);
|
||||
|
||||
for (let i = 0; i < numShelves; i++) {
|
||||
const currentShelfY = woodThickness + (i * shelfSpacing);
|
||||
|
||||
// Shelf board (skip for the very bottom one as we have a bottom panel)
|
||||
if (i > 0) {
|
||||
const shelfBoard = new THREE.Mesh(
|
||||
new THREE.BoxGeometry(internalWidth, woodThickness, shelfDepth - woodThickness), // Slightly shallower to fit inside back panel
|
||||
woodMaterial
|
||||
);
|
||||
shelfBoard.position.set(0, currentShelfY, woodThickness / 2); // Offset forward slightly
|
||||
shelfBoard.castShadow = true;
|
||||
shelfBoard.receiveShadow = true;
|
||||
shelfGroup.add(shelfBoard);
|
||||
}
|
||||
|
||||
// 3. Procedural Books
|
||||
let currentBookX = -internalWidth / 2 + 0.01; // Start at left inside edge
|
||||
const shelfSurfaceY = currentShelfY + woodThickness / 2;
|
||||
|
||||
while (currentBookX < internalWidth / 2 - 0.05) {
|
||||
const bookWidth = 0.02 + seededRandom() * 0.05; // 2cm to 7cm wide
|
||||
const bookHeight = (shelfSpacing * 0.6) + seededRandom() * (shelfSpacing * 0.3); // Vary height within shelf limits
|
||||
const bookDepth = 0.15 + seededRandom() * 0.1; // Vary depth
|
||||
|
||||
if (currentBookX + bookWidth > internalWidth / 2) break;
|
||||
|
||||
const bookColor = getRandomColor();
|
||||
const bookMat = new THREE.MeshPhongMaterial({ color: bookColor, shininess: 60 });
|
||||
const bookGeo = new THREE.BoxGeometry(bookWidth, bookHeight, bookDepth);
|
||||
const book = new THREE.Mesh(bookGeo, bookMat);
|
||||
|
||||
// Position: Resting on shelf, pushed towards the back with slight random variation
|
||||
const depthVariation = seededRandom() * 0.05;
|
||||
book.position.set(
|
||||
currentBookX + bookWidth / 2,
|
||||
shelfSurfaceY + bookHeight / 2,
|
||||
-shelfDepth / 2 + woodThickness + bookDepth / 2 + depthVariation
|
||||
);
|
||||
|
||||
book.castShadow = true;
|
||||
book.receiveShadow = true;
|
||||
shelfGroup.add(book);
|
||||
|
||||
currentBookX += bookWidth + 0.002; // Tiny gap between books
|
||||
}
|
||||
}
|
||||
|
||||
scene.add(shelfGroup);
|
||||
}
|
||||
|
||||
function createDoor(x, z, rotY) {
|
||||
const doorGroup = new THREE.Group();
|
||||
doorGroup.position.set(x, 1.1, z); // Centered vertically for a 2.2m door
|
||||
doorGroup.rotation.set(0, rotY, 0);
|
||||
|
||||
// Door Frame
|
||||
const frameMaterial = new THREE.MeshPhongMaterial({ color: 0x473e3a }); // Dark wood for frame
|
||||
const frameTop = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.1, 0.15), frameMaterial);
|
||||
frameTop.position.set(0, 1.15, 0);
|
||||
frameTop.castShadow = true;
|
||||
doorGroup.add(frameTop);
|
||||
|
||||
const frameLeft = new THREE.Mesh(new THREE.BoxGeometry(0.1, 2.3, 0.15), frameMaterial);
|
||||
frameLeft.position.set(-0.55, 0.05, 0);
|
||||
frameLeft.castShadow = true;
|
||||
doorGroup.add(frameLeft);
|
||||
|
||||
const frameRight = new THREE.Mesh(new THREE.BoxGeometry(0.1, 2.3, 0.15), frameMaterial);
|
||||
frameRight.position.set(0.55, 0.05, 0);
|
||||
frameRight.castShadow = true;
|
||||
doorGroup.add(frameRight);
|
||||
|
||||
// Main Door Panel
|
||||
const doorMaterial = new THREE.MeshPhongMaterial({ color: 0x8b5a2b, shininess: 10 }); // Lighter wood for door
|
||||
const door = new THREE.Mesh(new THREE.BoxGeometry(1.0, 2.2, 0.08), doorMaterial);
|
||||
door.castShadow = true;
|
||||
door.receiveShadow = true;
|
||||
doorGroup.add(door);
|
||||
|
||||
// Door Knob
|
||||
const knobMaterial = new THREE.MeshPhongMaterial({ color: 0xd4af37, shininess: 100 }); // Gold/Brass
|
||||
const knob = new THREE.Mesh(new THREE.SphereGeometry(0.05, 16, 16), knobMaterial);
|
||||
knob.position.set(0.4, 0, 0.06); // Position on the right side of the door
|
||||
knob.castShadow = true;
|
||||
doorGroup.add(knob);
|
||||
|
||||
scene.add(doorGroup);
|
||||
}
|
||||
|
||||
function createTvSet(x, z, rotY) {
|
||||
// --- Materials (MeshPhongMaterial) ---
|
||||
const darkWood = new THREE.MeshPhongMaterial({ color: 0x3d352e, shininess: 10 });
|
||||
const darkMetal = new THREE.MeshPhongMaterial({
|
||||
@@ -259,45 +411,38 @@
|
||||
specular: 0x888888
|
||||
});
|
||||
const tvPlastic = new THREE.MeshPhongMaterial({ color: 0x2d251e, shininess: 10 });
|
||||
|
||||
// --- 1. Floor ---
|
||||
const floorGeometry = new THREE.PlaneGeometry(20, 20);
|
||||
const floorMaterial = new THREE.MeshPhongMaterial({ color: 0x1a1a1a, shininess: 5 });
|
||||
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
|
||||
floor.rotation.x = -Math.PI / 2;
|
||||
floor.position.y = 0;
|
||||
floor.receiveShadow = true;
|
||||
scene.add(floor);
|
||||
|
||||
// --- 2. Table (TV stand) ---
|
||||
const tableGeometry = new THREE.BoxGeometry(4.0, 0.7, 2.5);
|
||||
const tvGroup = new THREE.Group();
|
||||
|
||||
// --- 1. Table (TV stand) ---
|
||||
const tableGeometry = new THREE.BoxGeometry(2.0, 0.7, 1.0);
|
||||
const table = new THREE.Mesh(tableGeometry, darkWood);
|
||||
table.position.y = 0.35;
|
||||
table.castShadow = true;
|
||||
table.receiveShadow = true;
|
||||
scene.add(table);
|
||||
tvGroup.add(table);
|
||||
|
||||
// --- 3. The TV Set ---
|
||||
const cabinetGeometry = new THREE.BoxGeometry(2.8, 2, 1.5);
|
||||
// --- 2. The TV box ---
|
||||
const cabinetGeometry = new THREE.BoxGeometry(1.75, 1.5, 1.0);
|
||||
const cabinet = new THREE.Mesh(cabinetGeometry, tvPlastic);
|
||||
cabinet.position.y = 1.7;
|
||||
cabinet.position.y = 1.51;
|
||||
cabinet.castShadow = true;
|
||||
cabinet.receiveShadow = true;
|
||||
scene.add(cabinet);
|
||||
tvGroup.add(cabinet);
|
||||
|
||||
// Screen Frame
|
||||
const frameGeometry = new THREE.BoxGeometry(2.3, 1.6, 0.2);
|
||||
// --- 3. Screen Frame ---
|
||||
const frameGeometry = new THREE.BoxGeometry(1.5, 1.3, 0.2);
|
||||
const frameMaterial = new THREE.MeshPhongMaterial({ color: 0x111111, shininess: 20 });
|
||||
const frame = new THREE.Mesh(frameGeometry, frameMaterial);
|
||||
frame.position.set(0, 1.7, 0.68);
|
||||
frame.position.set(0, 1.5, 0.68);
|
||||
frame.castShadow = true;
|
||||
frame.receiveShadow = true;
|
||||
scene.add(frame);
|
||||
tvGroup.add(frame);
|
||||
|
||||
// --- 4. Curved Screen (CRT Effect) ---
|
||||
const screenRadius = 3.0; // Radius for the subtle curve
|
||||
const screenWidth = 2.3;
|
||||
const screenHeight = 1.5;
|
||||
const screenWidth = 1.4;
|
||||
const screenHeight = 1.2;
|
||||
const thetaLength = screenWidth / screenRadius; // Calculate angle needed for the arc
|
||||
|
||||
// Use CylinderGeometry as a segment
|
||||
@@ -321,14 +466,52 @@
|
||||
tvScreen = new THREE.Mesh(screenGeometry, screenMaterial);
|
||||
|
||||
// Position the curved screen
|
||||
tvScreen.position.set(0, 1.7, -2);
|
||||
scene.add(tvScreen);
|
||||
tvScreen.position.set(0, 1.5, -2);
|
||||
tvGroup.add(tvScreen);
|
||||
|
||||
tvGroup.position.set(x, 0, z);
|
||||
tvGroup.rotation.y = rotY;
|
||||
|
||||
// Light from the screen (initially low intensity, will increase when video loads)
|
||||
screenLight = new THREE.PointLight(0xffffff, 0, 10);
|
||||
screenLight.position.set(0, 1.5, 1.0);
|
||||
// Screen light casts shadows
|
||||
screenLight.castShadow = true;
|
||||
screenLight.shadow.mapSize.width = 1024;
|
||||
screenLight.shadow.mapSize.height = 1024;
|
||||
screenLight.shadow.camera.near = 0.2;
|
||||
screenLight.shadow.camera.far = 5;
|
||||
tvGroup.add(screenLight);
|
||||
|
||||
scene.add(tvGroup);
|
||||
}
|
||||
|
||||
// --- Scene Modeling Function ---
|
||||
function createSceneObjects() {
|
||||
// --- Materials (MeshPhongMaterial) ---
|
||||
const darkWood = new THREE.MeshPhongMaterial({ color: 0x3d352e, shininess: 10 });
|
||||
const darkMetal = new THREE.MeshPhongMaterial({
|
||||
color: 0x6b6b6b,
|
||||
shininess: 80,
|
||||
specular: 0x888888
|
||||
});
|
||||
const tvPlastic = new THREE.MeshPhongMaterial({ color: 0x2d251e, shininess: 10 });
|
||||
|
||||
// --- 1. Floor ---
|
||||
const floorGeometry = new THREE.PlaneGeometry(20, 20);
|
||||
const floorMaterial = new THREE.MeshPhongMaterial({ color: 0x1a1a1a, shininess: 5 });
|
||||
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
|
||||
floor.rotation.x = -Math.PI / 2;
|
||||
floor.position.y = 0;
|
||||
floor.receiveShadow = true;
|
||||
scene.add(floor);
|
||||
|
||||
createTvSet(-roomSize/2 + 1.2, -roomSize/2 + 0.8, Math.PI * 0.1);
|
||||
|
||||
// --- 5. Lamp (On the table, right side) ---
|
||||
const lampBase = new THREE.CylinderGeometry(0.1, 0.2, 0.1, 12);
|
||||
const lampPole = new THREE.CylinderGeometry(0.05, 0.05, 0.6, 8);
|
||||
const lampShade = new THREE.ConeGeometry(0.3, 0.4, 16);
|
||||
const lampBase = new THREE.CylinderGeometry(0.05, 0.2, 0.1, 12);
|
||||
const lampPole = new THREE.CylinderGeometry(0.02, 0.02, 1.5, 8);
|
||||
const lampShade = new THREE.ConeGeometry(0.2, 0.4, 16);
|
||||
|
||||
const baseMesh = new THREE.Mesh(lampBase, darkMetal);
|
||||
const poleMesh = new THREE.Mesh(lampPole, darkMetal);
|
||||
@@ -337,55 +520,40 @@
|
||||
// Ensure lamp parts cast shadows
|
||||
baseMesh.castShadow = true; baseMesh.receiveShadow = true;
|
||||
poleMesh.castShadow = true; poleMesh.receiveShadow = true;
|
||||
shadeMesh.castShadow = true; shadeMesh.receiveShadow = true;
|
||||
//shadeMesh.castShadow = true; shadeMesh.receiveShadow = true;
|
||||
|
||||
poleMesh.position.y = 0.3;
|
||||
baseMesh.position.y = -0.6;
|
||||
poleMesh.position.y = 0.0;
|
||||
shadeMesh.position.y = 0.8 + 0.1;
|
||||
shadeMesh.rotation.x = Math.PI;
|
||||
|
||||
const lampGroup = new THREE.Group();
|
||||
lampGroup.add(baseMesh, poleMesh, shadeMesh);
|
||||
lampGroup.position.set(2.5, 0.7, -0.6);
|
||||
|
||||
// Lamp Light (Warm Glow) - Configured to cast shadows
|
||||
lampLight = new THREE.PointLight(0xffaa00, originalLampIntensity, 4);
|
||||
lampLight.position.set(2.5, 1.35, -0.6);
|
||||
lampLight.castShadow = true;
|
||||
lampLightPoint = new THREE.PointLight(0xffaa00, originalLampIntensity, 4);
|
||||
lampLightPoint.position.set(-0.01, roomHeight-0.9, 0.01);
|
||||
lampLightPoint.castShadow = true;
|
||||
// Optimization: Reduced map size and far plane to ease resource burden
|
||||
lampLight.shadow.mapSize.width = 512;
|
||||
lampLight.shadow.mapSize.height = 512;
|
||||
lampLight.shadow.camera.near = 0.1;
|
||||
lampLight.shadow.camera.far = 4; // Matches the light's attenuation distance (4)
|
||||
lampLightPoint.shadow.mapSize.width = 512;
|
||||
lampLightPoint.shadow.mapSize.height = 512;
|
||||
lampLightPoint.shadow.camera.near = 0.1;
|
||||
lampLightPoint.shadow.camera.far = 4; // Matches the light's attenuation distance (4)
|
||||
lampLightPoint.penumbra = 0.5;
|
||||
|
||||
lampLightSpot = new THREE.SpotLight(0xffaa00, originalLampIntensity, 4);
|
||||
lampLightSpot.position.set(-0.01, 1.0, 0.01);
|
||||
lampLightSpot.target.position.set(0, 5, 0);
|
||||
lampLightSpot.castShadow = true;
|
||||
// Optimization: Reduced map size and far plane to ease resource burden
|
||||
lampLightSpot.shadow.mapSize.width = 512;
|
||||
lampLightSpot.shadow.mapSize.height = 512;
|
||||
lampLightSpot.shadow.camera.near = 0.1;
|
||||
lampLightSpot.shadow.camera.far = 4; // Matches the light's attenuation distance (4)
|
||||
lampLightSpot.penumbra = 0.5;
|
||||
|
||||
// Crucially, add the lamp group and its light to the scene
|
||||
scene.add(lampGroup, lampLight);
|
||||
const lampGroup = new THREE.Group();
|
||||
lampGroup.add(baseMesh, poleMesh, shadeMesh, lampLightSpot, lampLightSpot.target, lampLightPoint);
|
||||
lampGroup.position.set(0.8, 0.7, -roomSize/2+0.5);
|
||||
|
||||
|
||||
// --- 6. Vase with a Flower (On the table, left side) ---
|
||||
const vaseGeometry = new THREE.CylinderGeometry(0.2, 0.15, 0.4, 12);
|
||||
const vaseMaterial = new THREE.MeshPhongMaterial({ color: 0x356644, shininess: 15 });
|
||||
const vase = new THREE.Mesh(vaseGeometry, vaseMaterial);
|
||||
vase.position.set(0, -0.2, 0);
|
||||
vase.castShadow = true; vase.receiveShadow = true;
|
||||
|
||||
// Flower
|
||||
const flowerStem = new THREE.CylinderGeometry(0.01, 0.01, 0.3, 8);
|
||||
const flowerHead = new THREE.SphereGeometry(0.08, 10, 10);
|
||||
const stemMaterial = new THREE.MeshPhongMaterial({ color: 0x228B22, shininess: 10 });
|
||||
const headMaterial = new THREE.MeshPhongMaterial({ color: 0xdd2222, shininess: 30 });
|
||||
|
||||
const stem = new THREE.Mesh(flowerStem, stemMaterial);
|
||||
stem.position.y = 0.1;
|
||||
const head = new THREE.Mesh(flowerHead, headMaterial);
|
||||
head.position.y = 0.3;
|
||||
stem.castShadow = true; head.castShadow = true;
|
||||
stem.receiveShadow = true; head.receiveShadow = true;
|
||||
|
||||
const flowerGroup = new THREE.Group();
|
||||
flowerGroup.add(stem, head, vase);
|
||||
flowerGroup.position.set(-1.65, 1.1, 1);
|
||||
|
||||
scene.add(flowerGroup);
|
||||
scene.add(lampGroup);
|
||||
|
||||
// --- 7. Old Camera (On the table) ---
|
||||
const cameraBody = new THREE.BoxGeometry(0.4, 0.3, 0.2);
|
||||
@@ -399,9 +567,10 @@
|
||||
const cameraMesh = new THREE.Mesh(cameraBody, cameraMaterial);
|
||||
const lensMesh = new THREE.Mesh(cameraLens, cameraMaterial);
|
||||
lensMesh.position.z = 0.15;
|
||||
lensMesh.rotation.x = Math.PI/2;
|
||||
|
||||
cameraMesh.add(lensMesh);
|
||||
cameraMesh.position.set(-2.0, 0.7 + 0.15, -0.4);
|
||||
cameraMesh.position.set(-1.7, 0.15, 0.4);
|
||||
cameraMesh.rotation.y = -Math.PI / 10;
|
||||
cameraMesh.castShadow = true; cameraMesh.receiveShadow = true;
|
||||
scene.add(cameraMesh);
|
||||
@@ -414,6 +583,10 @@
|
||||
pizzaBox.rotation.y = Math.PI / 5;
|
||||
pizzaBox.castShadow = true; pizzaBox.receiveShadow = true;
|
||||
scene.add(pizzaBox);
|
||||
|
||||
createDoor(roomSize/2, -roomSize/2 * 0.5, -Math.PI/2);
|
||||
createBookshelf(-roomSize/2 + 0.2, roomSize/2*0.7, Math.PI/2, 0);
|
||||
createBookshelf(roomSize/2 * 0.7, -roomSize/2+0.3, 0, 1);
|
||||
}
|
||||
|
||||
// --- Dust Particle System Function ---
|
||||
@@ -478,7 +651,7 @@
|
||||
function playVideoByIndex(index) {
|
||||
if (index < 0 || index >= videoUrls.length) {
|
||||
statusText.textContent = 'End of playlist reached. Reload tapes to start again.';
|
||||
screenLight.intensity = 0.1; // Keep minimum intensity for shadow map
|
||||
screenLight.intensity = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -521,7 +694,7 @@
|
||||
statusText.textContent = `Playing tape ${currentVideoIndex + 1} of ${videoUrls.length}.`;
|
||||
updateControls();
|
||||
}).catch(error => {
|
||||
screenLight.intensity = 0.5; // Dim the light if playback fails
|
||||
screenLight.intensity = originalScreenIntensity * 0.5; // Dim the light if playback fails
|
||||
statusText.textContent = `Playback blocked for tape ${currentVideoIndex + 1}. Click Next Tape to try again.`;
|
||||
console.error('Playback Error: Could not start video playback.', error);
|
||||
});
|
||||
@@ -601,12 +774,12 @@
|
||||
// Base Camera Position in front of the TV
|
||||
const baseX = 0;
|
||||
const baseY = 1.5;
|
||||
const baseZ = 4;
|
||||
const baseZ = 3;
|
||||
|
||||
// Base LookAt target (Center of the screen)
|
||||
const baseTargetX = 0;
|
||||
const baseTargetX = -1;
|
||||
const baseTargetY = 1.7;
|
||||
const baseTargetZ = 0.96;
|
||||
const baseTargetZ = -0.96;
|
||||
|
||||
// Camera Position Offsets (Drift)
|
||||
const camOffsetX = Math.sin(globalTime * 3.1) * camAmplitude;
|
||||
@@ -633,31 +806,35 @@
|
||||
|
||||
if (Math.random() > flickerChance) {
|
||||
// Flickers quickly to a dimmer random value (between 0.3 and 1.05)
|
||||
lampLight.intensity = originalLampIntensity * (0.3 + Math.random() * 0.7);
|
||||
} else if (lampLight.intensity < originalLampIntensity) {
|
||||
let lampLightIntensity = originalLampIntensity * (0.3 + Math.random() * 0.7);
|
||||
lampLightSpot.intensity = lampLightIntensity;
|
||||
lampLightPoint.intensity = lampLightIntensity;
|
||||
} else if (lampLightPoint.intensity < originalLampIntensity) {
|
||||
// Smoothly restore original intensity
|
||||
lampLight.intensity = THREE.MathUtils.lerp(lampLight.intensity, originalLampIntensity, restoreRate);
|
||||
let lampLightIntensity = THREE.MathUtils.lerp(lampLightPoint.intensity, originalLampIntensity, restoreRate);
|
||||
lampLightSpot.intensity = lampLightIntensity;
|
||||
lampLightPoint.intensity = lampLightIntensity;
|
||||
}
|
||||
|
||||
// 4. Screen Light Pulse and Movement Effect (Updated)
|
||||
if (isVideoLoaded && screenLight.intensity > 0) {
|
||||
// A. Pulse Effect (Intensity Fluctuation)
|
||||
// Generate a small random fluctuation for the pulse (Range: 1.35 to 1.65 around base 1.5)
|
||||
const pulseTarget = originalScreenIntensity + (Math.random() - 0.5) * 0.7;
|
||||
const pulseTarget = originalScreenIntensity + (Math.random() - 0.5) * screenIntensityPulse;
|
||||
// Smoothly interpolate towards the new target fluctuation
|
||||
screenLight.intensity = THREE.MathUtils.lerp(screenLight.intensity, pulseTarget, 0.1);
|
||||
|
||||
// B. Movement Effect (Subtle circle around the screen center - circling the room area)
|
||||
const lightTime = Date.now() * 0.002;
|
||||
const radius = 0.05; // Small circle radius (5 cm)
|
||||
const lightTime = Date.now() * 0.0001;
|
||||
const radius = 0.01;
|
||||
const centerX = 0;
|
||||
const centerY = 1.7;
|
||||
const centerZ = 1.2; // Use the updated Z position of the light source
|
||||
const centerY = 1.5;
|
||||
//const centerZ = 1.2; // Use the updated Z position of the light source
|
||||
|
||||
// Move the light in a subtle, erratic circle
|
||||
screenLight.position.x = centerX + Math.cos(lightTime) * radius;
|
||||
screenLight.position.y = centerY + Math.sin(lightTime * 1.5) * radius * 0.5; // Slightly different freq for Y
|
||||
screenLight.position.z = centerZ; // Keep Z constant at the screen light plane
|
||||
//screenLight.position.z = centerZ; // Keep Z constant at the screen light plane
|
||||
}
|
||||
|
||||
// 5. Update video texture (essential to grab the next frame)
|
||||
|
||||
Reference in New Issue
Block a user