D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\main.ts
import "./style.css";
import Base from "./threejs/Base";
((document) => {
const oApp = document.getElementById("app")!;
const oCanvas = document.createElement("canvas");
oCanvas.style.position = "absolute";
Base.getInstance(oCanvas);
oApp.appendChild(oCanvas);
})(document);
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\main_单例模式_constructor.ts
import "./style.css";
import Base from "./threejs/Base";
((document) => {
const oApp = document.getElementById("app")!;
const oCanvas = document.createElement("canvas");
new Base(oCanvas);
oApp.appendChild(oCanvas);
})(document);
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\main_单例模式_getInstance.ts
import "./style.css";
import Base from "./threejs/Base";
((document) => {
const oApp = document.getElementById("app")!;
const oCanvas = document.createElement("canvas");
oCanvas.style.position = "absolute";
Base.getInstance(oCanvas);
oApp.appendChild(oCanvas);
})(document);
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\Base.ts
import { Scene } from "three";
import Camera from "./Camera";
import Helper from "./Helper";
import Renderer from "./Renderer";
import Size from "./Size";
import Time from "./Time";
import World from "./World/World";
import Car from "./World/Car";
export default class Base {
public static base: Base;
public canvas: HTMLCanvasElement;
public scene: Scene;
public camera: Camera;
public size: Size;
public time: Time;
public renderer: Renderer;
public world: World;
constructor(canvas: HTMLCanvasElement) {
Base.base = this;
this.canvas = canvas as HTMLCanvasElement;
this.scene = new Scene();
this.size = new Size();
this.camera = new Camera();
this.time = new Time();
this.renderer = new Renderer();
new Helper();
this.world = new World();
new Car();
this.time.on("update", () => {
this.update();
});
this.size.on("resize", () => {
this.resize();
});
}
public static getInstance(canvas?: HTMLCanvasElement) {
if (canvas === undefined && Base.base !== undefined) {
return Base.base;
}
Base.base = new Base(canvas as HTMLCanvasElement);
return Base.base;
}
private resize() {
this.camera.resize();
this.renderer.resize();
}
private update() {
this.camera.update();
this.renderer.update();
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\Camera.ts
import { PerspectiveCamera, Scene } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Base from "./Base";
import type Size from "./Size";
export default class Camera {
private size: Size;
private scene: Scene;
private canvas: HTMLCanvasElement;
public perspectiveCamera: PerspectiveCamera;
private controls: OrbitControls;
constructor() {
const base = Base.getInstance();
this.size = base.size;
this.scene = base.scene;
this.canvas = base.canvas;
this.perspectiveCamera = this.createPerspectiveCamera();
this.scene.add(this.perspectiveCamera);
this.controls = this.createOrbitControls();
}
private createPerspectiveCamera() {
const perspectiveCamera = new PerspectiveCamera(
35,
this.size.aspect,
0.1,
1000
);
perspectiveCamera.position.set(15, 30, 20);
return perspectiveCamera;
}
private createOrbitControls() {
const controls = new OrbitControls(this.perspectiveCamera, this.canvas);
controls.enableDamping = true;
controls.enableZoom = true;
return controls;
}
public update() {
this.controls.update();
}
public resize() {
// Updating Perspective Camera on Resize
this.perspectiveCamera.aspect = this.size.aspect;
this.perspectiveCamera.updateProjectionMatrix();
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\Helper.ts
import { AxesHelper, GridHelper } from "three";
import Base from "./Base";
export default class {
constructor() {
const base = Base.getInstance();
const axesHelper = new AxesHelper(5);
base.scene.add(axesHelper);
const size = 10;
const divisions = 10;
const gridHelper = new GridHelper(size, divisions);
base.scene.add(gridHelper);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\Renderer.ts
import * as THREE from "three";
import Base from "./Base";
import { Scene, WebGLRenderer } from "three";
import Camera from "./Camera";
import Size from "./Size";
export default class Renderer {
private size: Size;
private scene: Scene;
private canvas: HTMLCanvasElement;
private camera: Camera;
private renderer: WebGLRenderer;
constructor() {
const base = Base.getInstance();
this.size = base.size;
this.scene = base.scene;
this.canvas = base.canvas;
this.camera = base.camera;
this.renderer = this.setRenderer();
}
setRenderer() {
const renderer = new WebGLRenderer({
canvas: this.canvas,
antialias: true,
});
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.CineonToneMapping;
renderer.toneMappingExposure = 1.75;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(this.size.width, this.size.height);
renderer.setPixelRatio(this.size.pixelRatio);
return renderer;
}
resize() {
this.renderer.setSize(this.size.width, this.size.height);
this.renderer.setPixelRatio(this.size.pixelRatio);
}
update() {
this.renderer.render(this.scene, this.camera.perspectiveCamera);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\Size.ts
import EventEmitter from "eventemitter2";
export default class Size extends EventEmitter {
public width: number;
public height: number;
public aspect: number;
public pixelRatio: number;
constructor() {
super();
this.width = window.innerWidth;
this.height = window.innerHeight;
this.aspect = this.width / this.height;
this.pixelRatio = Math.min(window.devicePixelRatio, 2);
window.addEventListener("resize", () => {
this.width = window.innerWidth;
this.height = window.innerHeight;
this.aspect = this.width / this.height;
this.pixelRatio = Math.min(window.devicePixelRatio, 2);
this.emit("resize");
});
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\Time.ts
import EventEmitter from "eventemitter2";
import { Clock } from "three";
export default class Time extends EventEmitter {
public clock: Clock;
constructor() {
super();
this.clock = new Clock();
this.update();
}
update() {
this.emit("update");
window.requestAnimationFrame(() => this.update());
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\World\Car.ts
import { BoxGeometry, MeshBasicMaterial, Mesh } from "three";
import Base from "../Base";
export default class Car {
constructor() {
const base = Base.getInstance();
const cube = new Mesh(
new BoxGeometry(1, 1, 1),
new MeshBasicMaterial({ color: 0x00ff00 })
);
cube.position.y = 0.5;
base.scene.add(cube);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\World\Environment.ts
import { AmbientLight, DirectionalLight } from "three";
import Base from "../Base";
export default class Environment {
private sunLight: DirectionalLight;
private ambientLight: AmbientLight;
constructor() {
const base = Base.getInstance();
this.sunLight = new DirectionalLight("#ffffff", 3);
this.sunLight.castShadow = true;
this.sunLight.shadow.camera.far = 20;
this.sunLight.shadow.mapSize.set(2048, 2048);
this.sunLight.shadow.normalBias = 0.05;
// const helper = new THREE.CameraHelper(this.sunLight.shadow.camera);
// this.scene.add(helper);
this.sunLight.position.set(-1.5, 7, 3);
base.scene.add(this.sunLight);
this.ambientLight = new AmbientLight("#ffffff", 1);
base.scene.add(this.ambientLight);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs\World\World.ts
import { BackSide, Mesh, MeshBasicMaterial, PlaneGeometry } from "three";
import Base from "../Base";
export default class World {
private plane: Mesh;
constructor() {
const base = Base.getInstance();
const geometry = new PlaneGeometry(10, 10);
const material = new MeshBasicMaterial({
color: 0xfefefe,
side: BackSide,
});
this.plane = new Mesh(geometry, material);
this.plane.rotateX(Math.PI * 0.5);
base.scene.add(this.plane);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_constructor\Base.ts
import { Scene } from "three";
import Camera from "./Camera";
export default class Base {
public static base: Base;
public canvas!: HTMLCanvasElement;
public scene!: Scene;
public camera!: Camera;
constructor(canvas?: HTMLCanvasElement) {
if (canvas === undefined && Base.base !== undefined) {
return Base.base;
}
Base.base = this;
this.canvas = canvas as HTMLCanvasElement;
this.scene = new Scene();
this.camera = new Camera();
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_constructor\Camera.ts
import Base from "./Base";
export default class Camera {
constructor() {
const base = new Base();
console.log(base.canvas);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\Base.ts
import { Scene } from "three";
import Camera from "./Camera";
import Helper from "./Helper";
import Renderer from "./Renderer";
import Size from "./Size";
import Time from "./Time";
import World from "./World/World";
export default class Base {
public static base: Base;
public canvas: HTMLCanvasElement;
public scene: Scene;
public camera: Camera;
public size: Size;
public time: Time;
public renderer: Renderer;
public world: World;
constructor(canvas: HTMLCanvasElement) {
Base.base = this;
this.canvas = canvas as HTMLCanvasElement;
this.scene = new Scene();
this.size = new Size();
this.camera = new Camera();
this.time = new Time();
this.renderer = new Renderer();
new Helper();
this.world = new World();
this.time.on("update", () => {
this.update();
});
this.size.on("resize", () => {
this.resize();
});
}
public static getInstance(canvas?: HTMLCanvasElement) {
if (canvas === undefined && Base.base !== undefined) {
return Base.base;
}
Base.base = new Base(canvas as HTMLCanvasElement);
return Base.base;
}
private resize() {
this.camera.resize();
this.renderer.resize();
}
private update() {
this.camera.update();
this.renderer.update();
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\Camera.ts
import { PerspectiveCamera, Scene } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Base from "./Base";
import type Size from "./Size";
export default class Camera {
private size: Size;
private scene: Scene;
private canvas: HTMLCanvasElement;
public perspectiveCamera: PerspectiveCamera;
private controls: OrbitControls;
constructor() {
const base = Base.getInstance();
this.size = base.size;
this.scene = base.scene;
this.canvas = base.canvas;
this.perspectiveCamera = this.createPerspectiveCamera();
this.scene.add(this.perspectiveCamera);
this.controls = this.createOrbitControls();
}
private createPerspectiveCamera() {
const perspectiveCamera = new PerspectiveCamera(
35,
this.size.aspect,
0.1,
1000
);
perspectiveCamera.position.set(15, 30, 20);
return perspectiveCamera;
}
private createOrbitControls() {
const controls = new OrbitControls(this.perspectiveCamera, this.canvas);
controls.enableDamping = true;
controls.enableZoom = true;
return controls;
}
public update() {
this.controls.update();
}
public resize() {
// Updating Perspective Camera on Resize
this.perspectiveCamera.aspect = this.size.aspect;
this.perspectiveCamera.updateProjectionMatrix();
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\Helper.ts
import { AxesHelper, GridHelper } from "three";
import Base from "./Base";
export default class {
constructor() {
const base = Base.getInstance();
const axesHelper = new AxesHelper(5);
base.scene.add(axesHelper);
const size = 10;
const divisions = 10;
const gridHelper = new GridHelper(size, divisions);
base.scene.add(gridHelper);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\Renderer.ts
import * as THREE from "three";
import Base from "./Base";
import { Scene, WebGLRenderer } from "three";
import Camera from "./Camera";
import Size from "./Size";
export default class Renderer {
private size: Size;
private scene: Scene;
private canvas: HTMLCanvasElement;
private camera: Camera;
private renderer: WebGLRenderer;
constructor() {
const base = Base.getInstance();
this.size = base.size;
this.scene = base.scene;
this.canvas = base.canvas;
this.camera = base.camera;
this.renderer = this.setRenderer();
}
setRenderer() {
const renderer = new WebGLRenderer({
canvas: this.canvas,
antialias: true,
});
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.CineonToneMapping;
renderer.toneMappingExposure = 1.75;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(this.size.width, this.size.height);
renderer.setPixelRatio(this.size.pixelRatio);
return renderer;
}
resize() {
this.renderer.setSize(this.size.width, this.size.height);
this.renderer.setPixelRatio(this.size.pixelRatio);
}
update() {
this.renderer.render(this.scene, this.camera.perspectiveCamera);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\Size.ts
import EventEmitter from "eventemitter2";
export default class Size extends EventEmitter {
public width: number;
public height: number;
public aspect: number;
public pixelRatio: number;
constructor() {
super();
this.width = window.innerWidth;
this.height = window.innerHeight;
this.aspect = this.width / this.height;
this.pixelRatio = Math.min(window.devicePixelRatio, 2);
window.addEventListener("resize", () => {
this.width = window.innerWidth;
this.height = window.innerHeight;
this.aspect = this.width / this.height;
this.pixelRatio = Math.min(window.devicePixelRatio, 2);
this.emit("resize");
});
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\Time.ts
import EventEmitter from "eventemitter2";
import { Clock } from "three";
export default class Time extends EventEmitter {
public clock: Clock;
constructor() {
super();
this.clock = new Clock();
this.update();
}
update() {
this.emit("update");
window.requestAnimationFrame(() => this.update());
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\World\Environment.ts
import { AmbientLight, DirectionalLight } from "three";
import Base from "../Base";
export default class Environment {
private sunLight: DirectionalLight;
private ambientLight: AmbientLight;
constructor() {
const base = Base.getInstance();
this.sunLight = new DirectionalLight("#ffffff", 3);
this.sunLight.castShadow = true;
this.sunLight.shadow.camera.far = 20;
this.sunLight.shadow.mapSize.set(2048, 2048);
this.sunLight.shadow.normalBias = 0.05;
// const helper = new THREE.CameraHelper(this.sunLight.shadow.camera);
// this.scene.add(helper);
this.sunLight.position.set(-1.5, 7, 3);
base.scene.add(this.sunLight);
this.ambientLight = new AmbientLight("#ffffff", 1);
base.scene.add(this.ambientLight);
}
}
D:\code_gitee\threejs_learn_vanilla_class_singleton\threejs_learn_vanilla_ts_class_singleton\src\threejs_单例模式_getInstance\World\World.ts
import { BackSide, Mesh, MeshBasicMaterial, PlaneGeometry } from "three";
import Base from "../Base";
export default class World {
private plane: Mesh;
constructor() {
const base = Base.getInstance();
const geometry = new PlaneGeometry(10, 10);
const material = new MeshBasicMaterial({
color: 0xfefefe,
side: BackSide,
});
this.plane = new Mesh(geometry, material);
this.plane.rotateX(Math.PI * 0.5);
base.scene.add(this.plane);
}
}