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 { updateVcrDisplay } from '../scene/vcr-display.js';
|
||||||
import { state } from '../state.js';
|
import { state } from '../state.js';
|
||||||
import { updateScreenEffect } from '../scene/magic-mirror.js'
|
import { updateScreenEffect } from '../scene/magic-mirror.js'
|
||||||
|
import { updateCauldron } from '../scene/cauldron.js';
|
||||||
import { updateFire } from '../scene/fireplace.js';
|
import { updateFire } from '../scene/fireplace.js';
|
||||||
|
|
||||||
function updateCamera() {
|
function updateCamera() {
|
||||||
@ -174,6 +175,7 @@ export function animate() {
|
|||||||
// updatePictureFrame();
|
// updatePictureFrame();
|
||||||
updateScreenEffect();
|
updateScreenEffect();
|
||||||
updateFire();
|
updateFire();
|
||||||
|
updateCauldron();
|
||||||
|
|
||||||
// RENDER!
|
// RENDER!
|
||||||
state.renderer.render(state.scene, state.camera);
|
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 { createMagicMirror } from './magic-mirror.js';
|
||||||
import { createFireplace } from './fireplace.js';
|
import { createFireplace } from './fireplace.js';
|
||||||
import { createTable } from './table.js';
|
import { createTable } from './table.js';
|
||||||
|
import { createCauldron } from './cauldron.js';
|
||||||
import { PictureFrame } from './PictureFrame.js';
|
import { PictureFrame } from './PictureFrame.js';
|
||||||
import painting1 from '/textures/painting1.jpg';
|
import painting1 from '/textures/painting1.jpg';
|
||||||
import painting2 from '/textures/painting2.jpg';
|
import painting2 from '/textures/painting2.jpg';
|
||||||
@ -78,6 +79,9 @@ export function createSceneObjects() {
|
|||||||
|
|
||||||
createTable(-1.8, 0, -0.8, Math.PI / 2.3);
|
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 ---
|
// --- 8. Timber Frames ---
|
||||||
const beamThickness = 0.15;
|
const beamThickness = 0.15;
|
||||||
const beamDepth = 0.2;
|
const beamDepth = 0.2;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user