Zurück zur Startseite

Rendering von 3D-Wohnungen im Browser mit Three.js

Der Artikel beschreibt die Implementierung des Browser-Renderings von 3D-Wohnungen mit prozeduralen Möbeln auf Next.js und Three.js. Er behandelt Szenenarchitektur, Beleuchtung, Multiplayer auf Socket.io, Optimierungen und Gamification. Geeignet für Middle-/Senior-Entwickler.

3D-Wohnungen im Browser: Three.js + prozedurale Möbel
Advertisement 728x90

Prozedurale 3D-Wohnungsvisualisierung im Browser: Next.js, Three.js und WebSocket-Multiplayer

Im Prikolnya-Projekt werden pixelige 3D-Wohnungen für Multiplayer-Arcades ohne externe Modelle gerendert. Es nutzt Next.js 16 mit React Three Fiber, prozedurale Möbelgenerierung aus Primitiven, Canvas-Texturen für Inhalte und Socket.io für Positionssynchronisation. Szenen mit 300–800 Objekten laufen flüssig auf modernen Geräten.

Szenenarchitektur und Wohnungsvorlagen

Wohnungen werden aus Zonen (Räumen) mit gemeinsamen Wänden und Türen aufgebaut. Vorlagen werden durch Daten ohne fest kodierte Logik definiert:

type RoomDef = {
  id: string;
  name: string;
  x: number; z: number;
  width: number; depth: number;
  isSecret?: boolean;
};

type WallDef = {
  x1: number; z1: number;
  x2: number; z2: number;
  hasDoor?: boolean;
  doorOffset?: number;
};

const LOFT: ApartmentTemplate = {
  id: "loft",
  rooms: [
    { id: "lounge", name: "Lounge", x: 0, z: 0, width: 12, depth: 8 },
    { id: "gaming", name: "Gaming Room", x: 12, z: 0, width: 10, depth: 8 },
    { id: "bar", name: "Bar", x: 0, z: 8, width: 10, depth: 6 },
    { id: "studio", name: "Studio", x: 10, z: 8, width: 12, depth: 6 },
  ],
  walls: [
    { x1: 0, z1: 0, x2: 22, z2: 0 },
    { x1: 22, z1: 0, x2: 22, z2: 14 },
    { x1: 12, z1: 0, x2: 12, z2: 8, hasDoor: true },
  ],
};

Vorlagen reichen von einem Studio (12x10) bis zu einer Penthouse-Wohnung (24x22). Das Rendering ist deklarativ: Daten werden in Three.js-Objekte transformiert.

Google AdInline article slot

Beleuchtung: Ebenen und Stimmungsvorgaben

Die Szene wird mit drei Ebenen beleuchtet:

  • Ambient – Basisebene, abhängig von der Tageszeit (morgens: #ffd4a0, Intensität 1.1; nachts: #1a2244, 0.4).
  • Directional – Hauptlicht mit Schatten + Fülllicht.
  • Punktlichter – eines pro Raum in einer Höhe von 2,3 Einheiten.

Acht Stimmungsvorgaben sind hinzugefügt. Party: Decke #ff2288 (1.8), ambient #110022 (0.2), Akzent #00ffff (3.0). Komplette Transformation ohne Geometrieänderung.

Prozedurale Möbel aus Primitiven

Möbel werden aus boxGeometry und cylinderGeometry zusammengesetzt. Vorteile: keine Downloads, sofortige Generierung, Einfachheit für KI-Beschreibungen.

Google AdInline article slot

Beispiel-Arcade-Automat:

function ArcadeModel({ color, accent }: { color: string; accent: string }) {
  return (
    <group>
      <Block args={[0.7, 1.6, 0.7]} position={[0, 0.8, 0]} color={color} />
      <Block args={[0.5, 0.35, 0.05]} position={[0, 1.2, 0.33]}
             color="#0a0a2a" emissive={accent} emissiveIntensity={0.3} />
      <Block args={[0.5, 0.05, 0.25]} position={[0, 0.85, 0.25]}
             color="#1a1a2e" rotation={[-0.3, 0, 0]} />
      <mesh position={[-0.1, 0.92, 0.25]}>
        <cylinderGeometry args={[0.02, 0.02, 0.12]} />
        <meshStandardMaterial color="#ff2e63" />
      </mesh>
      {[0.05, 0.15].map((x) => (
        <mesh key={x} position={[x, 0.9, 0.2]}>
          <cylinderGeometry args={[0.025, 0.025, 0.02]} />
          <meshStandardMaterial color={accent} emissive={accent}
                                emissiveIntensity={0.5} />
        </mesh>
      ))}
    </group>
  );
}

Szene: 300–800 Objekte. KI generiert JSON mit Primitiven für Markenpräsentationen.

Wandinhalt via CanvasTexture

Poster werden dynamisch gerendert:

Google AdInline article slot
  • Canvas 256x170.
  • Hintergrund #1a1a2e, Rahmen in Autorfarbe, umgebrochener Text.
  • THREE.CanvasTexture mit NearestFilter.
  • meshStandardMaterial mit emissiveIntensity: 0.05.
const canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 170;
const ctx = canvas.getContext("2d")!;
ctx.fillStyle = "#1a1a2e";
ctx.strokeStyle = authorColor;
// Textumbruch, Zeichnen

const texture = new THREE.CanvasTexture(canvas);
texture.minFilter = THREE.NearestFilter;

3 Slots pro Wand (0.25, 0.5, 0.75), Höhe 1,3 Einheiten. Unterstützt Bilder, Video, Audio.

Pixel-Avatare und Haustiere

Avatare sind Canvas-Texturen auf einem Billboard. Ebenen: Körper (5 Töne), Augen, Hose (6), Kleidung (10), Haare (12), Accessoires (10). Skalierung 16x24 → 128x192, NearestFilter.

Haustiere werden mit lerp 0.05 (nah) / 0.15 (fern) interpoliert.

Multiplayer mit Interpolation

Socket.io sendet Positionen (~20 FPS):

useFrame(() => {
  const now = Date.now();
  if (now - lastRef.current.t < 50) return;
  const dx = Math.abs(pos.x - lastRef.current.x);
  const dz = Math.abs(pos.z - lastRef.current.z);
  if (dx < 0.05 && dz < 0.05) return;

  socketRef.current?.volatile.emit("position", { x: pos.x, z: pos.z });
});

Interpolation: position.x += (target.x - position.x) * 0.15 (15% pro Frame).

volatile.emit verwirft veraltete Pakete.

Wetter und Effekte

Partikelsysteme auf BufferGeometry:

  • Regen: 600 Partikel, lineSegments.
  • Schnee: 400 Partikel, points mit Drift.
  • Sterne: 200 Partikel, flackernd auf Y.
useFrame(() => {
  for (let i = 0; i < count; i++) {
    positions[i * 3 + 1] -= velocities[i];
    positions[i * 3] += Math.sin(Date.now() * 0.0008 + i * 0.7) * 0.004;
    if (positions[i * 3 + 1] < -0.5) {
      positions[i * 3 + 1] = 7 + Math.random() * 2;
    }
  }
  posAttr.needsUpdate = true;
});

Türen und Animationen

Öffnung auf 81° (π*0.45) basierend auf Skalarprodukt der Wandnormale:

const wallNormal = { x: -(z2 - z1), z: x2 - x1 };
const toPlayer = { x: playerX - doorX, z: playerZ - doorZ };
const dot = wallNormal.x * toPlayer.x + wallNormal.z * toPlayer.z;
const direction = dot > 0 ? 1 : -1;
currentAngle += (targetAngle * direction - currentAngle) * 0.1;

Leistungsoptimierungen

| Lösung | Effekt |

|---------|--------|

| dynamic(() => import("./Apartment3D"), { ssr: false }) | Three.js lazy-loaded, ~150 KB gzip |

| antialias: false | -15-20% Fillrate |

| dpr: Math.min(devicePixelRatio, 2) | Spart 2-4x auf HiDPI |

| NearestFilter | Kein trilineares Filtern |

| castShadow nur auf Möbeln | Schatten selektiv |

| receiveShadow nur auf Boden | Ein Empfänger |

3D-Bundle: ~600 KB roh, tree-shaken Three.js.

Gamification und Pläne

  • Wirtschaft: Münzen für Beiträge, Limit 100/Tag.
  • Level: 10, bis zu 3500 XP.
  • Wachsende Gebäude: 1-6 Stockwerke basierend auf Inhalten.
  • Events: 8/Jahr, x3 XP.
  • Geheime Räume: 10 via Codes.

Nächstes: KI-Möbel, Trophäen, Instancing/LOD.

Wichtigste Erkenntnisse

  • Prozedurale Möbel aus 4-15 Primitiven eliminieren glTF-Downloads.
  • Socket.io mit volatile.emit und 15% lerp sorgt für flüssigen Multiplayer.
  • CanvasTexture + NearestFilter für Pixel-Stil-Inhalte und Avatare.
  • Optimierungen reduzieren Bundle auf 150 KB gzip mit 300-800 Objekten.
  • Deklarative Vorlagen ermöglichen 5 Wohnungsvarianten ohne Code.

— Editorial Team

Advertisement 728x90

Weiterlesen