Feature: bubling cauldron
This commit is contained in:
parent
a98c058f3d
commit
499fc006f5
@ -3,6 +3,7 @@ import { updateDoor } from '../scene/door.js';
|
||||
import { updateVcrDisplay } from '../scene/vcr-display.js';
|
||||
import { state } from '../state.js';
|
||||
import { updateScreenEffect } from '../scene/magic-mirror.js'
|
||||
import { updateCauldron } from '../scene/cauldron.js';
|
||||
import { updateFire } from '../scene/fireplace.js';
|
||||
|
||||
function updateCamera() {
|
||||
@ -174,6 +175,7 @@ export function animate() {
|
||||
// updatePictureFrame();
|
||||
updateScreenEffect();
|
||||
updateFire();
|
||||
updateCauldron();
|
||||
|
||||
// RENDER!
|
||||
state.renderer.render(state.scene, state.camera);
|
||||
|
||||
97
magic-mirror/src/scene/cauldron.js
Normal file
97
magic-mirror/src/scene/cauldron.js
Normal file
@ -0,0 +1,97 @@
|
||||
import * as THREE from 'three';
|
||||
import { state } from '../state.js';
|
||||
|
||||
let cauldronParticles;
|
||||
let cauldronLight;
|
||||
const particleCount = 8;
|
||||
const particleVelocities = [];
|
||||
|
||||
export function createCauldron(x, y, z) {
|
||||
const cauldronGroup = new THREE.Group();
|
||||
|
||||
const cauldronRadius = 0.2;
|
||||
const cauldronHeight = 0.25;
|
||||
|
||||
// 1. Cauldron Body
|
||||
const cauldronMaterial = new THREE.MeshPhongMaterial({ color: 0x111111, shininess: 80 });
|
||||
// Use a sphere geometry cut in half for the bowl shape
|
||||
const cauldronGeo = new THREE.SphereGeometry(cauldronRadius, 32, 16, 0, Math.PI * 2, 0, Math.PI / 2);
|
||||
const cauldronMesh = new THREE.Mesh(cauldronGeo, cauldronMaterial);
|
||||
cauldronMesh.castShadow = true;
|
||||
cauldronMesh.rotation.z = Math.PI;
|
||||
cauldronGroup.add(cauldronMesh);
|
||||
|
||||
// 2. Glowing Liquid Surface
|
||||
const liquidColor = 0x00ff00; // Bright green
|
||||
const liquidMaterial = new THREE.MeshPhongMaterial({
|
||||
color: liquidColor,
|
||||
emissive: liquidColor,
|
||||
emissiveIntensity: 0.6,
|
||||
shininess: 100
|
||||
});
|
||||
const liquidGeo = new THREE.CircleGeometry(cauldronRadius * 0.95, 32);
|
||||
const liquidSurface = new THREE.Mesh(liquidGeo, liquidMaterial);
|
||||
liquidSurface.rotation.x = -Math.PI / 2;
|
||||
liquidSurface.position.y = -0.01; // Slightly below the rim
|
||||
cauldronGroup.add(liquidSurface);
|
||||
|
||||
// 3. Bubbling Particles
|
||||
const particleGeo = new THREE.BufferGeometry();
|
||||
const positions = new Float32Array(particleCount * 3);
|
||||
|
||||
for (let i = 0; i < particleCount; i++) {
|
||||
positions[i * 3] = (Math.random() - 0.5) * cauldronRadius * 1.5;
|
||||
positions[i * 3 + 1] = (Math.random() - 0.5) * 0.05; // Start near the surface
|
||||
positions[i * 3 + 2] = (Math.random() - 0.5) * cauldronRadius * 1.5;
|
||||
particleVelocities.push((0.05 + Math.random() * 0.1) / 60); // Random upward velocity
|
||||
}
|
||||
particleGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
||||
|
||||
const particleMaterial = new THREE.PointsMaterial({
|
||||
color: liquidColor,
|
||||
size: 0.015,
|
||||
transparent: true,
|
||||
blending: THREE.AdditiveBlending,
|
||||
depthWrite: false,
|
||||
opacity: 0.7
|
||||
});
|
||||
|
||||
cauldronParticles = new THREE.Points(particleGeo, particleMaterial);
|
||||
cauldronGroup.add(cauldronParticles);
|
||||
|
||||
// 4. Light from the cauldron
|
||||
cauldronLight = new THREE.PointLight(liquidColor, 0.8, 3);
|
||||
cauldronLight.position.y = 0.2;
|
||||
cauldronLight.castShadow = true;
|
||||
cauldronGroup.add(cauldronLight);
|
||||
|
||||
// Position and add to scene
|
||||
cauldronGroup.position.set(x, y, z);
|
||||
state.scene.add(cauldronGroup);
|
||||
}
|
||||
|
||||
export function updateCauldron() {
|
||||
if (!cauldronParticles || !cauldronLight) return;
|
||||
|
||||
// Animate Bubbles
|
||||
const positions = cauldronParticles.geometry.attributes.position.array;
|
||||
const bubbleMaxHeight = 0.1;
|
||||
const overfly = Math.random() * bubbleMaxHeight;
|
||||
|
||||
for (let i = 0; i < particleCount; i++) {
|
||||
positions[i * 3 + 1] += particleVelocities[i]; // Move bubble up
|
||||
|
||||
// Reset bubble if it goes too high
|
||||
if (positions[i * 3 + 1] > bubbleMaxHeight + overfly) {
|
||||
positions[i * 3 + 1] = (Math.random() - 0.5) * 0.05;
|
||||
// Give it a new random X/Z position
|
||||
positions[i * 3] = (Math.random() - 0.5) * 0.2 * 1.5;
|
||||
positions[i * 3 + 2] = (Math.random() - 0.5) * 0.2 * 1.5;
|
||||
}
|
||||
}
|
||||
cauldronParticles.geometry.attributes.position.needsUpdate = true;
|
||||
|
||||
// Flicker Light
|
||||
const flicker = Math.random() * 0.02;
|
||||
cauldronLight.intensity = 0.1 + flicker;
|
||||
}
|
||||
@ -5,6 +5,7 @@ import { createBookshelf } from './bookshelf.js';
|
||||
import { createMagicMirror } from './magic-mirror.js';
|
||||
import { createFireplace } from './fireplace.js';
|
||||
import { createTable } from './table.js';
|
||||
import { createCauldron } from './cauldron.js';
|
||||
import { PictureFrame } from './PictureFrame.js';
|
||||
import painting1 from '/textures/painting1.jpg';
|
||||
import painting2 from '/textures/painting2.jpg';
|
||||
@ -78,6 +79,9 @@ export function createSceneObjects() {
|
||||
|
||||
createTable(-1.8, 0, -0.8, Math.PI / 2.3);
|
||||
|
||||
// Add cauldron on top of the table (Y = table height + cauldron radius)
|
||||
createCauldron(-1.8, 0.5 + 0.2, -0.8);
|
||||
|
||||
// --- 8. Timber Frames ---
|
||||
const beamThickness = 0.15;
|
||||
const beamDepth = 0.2;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user