�����������������������������������������
���������������������������������������������������������������������������������������������������������������������������������������3D������������������������������������������������������������������������������������360������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������+���������
������������
���������������������������Threejs���������
������������
������������������������������������������������������������360��������������������������������������������������������������������������360��������������������������������������Threejs���
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������+���������+������������������������������������������������������������������������������������������������������������������������������
������������������������������vlog���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Threejs������
���������������������������������������������Threejs���������������������������������������������������Threejs������������������������������
import {
Scene,
WebGLRenderer,
PerspectiveCamera,
Vector3,
PCFSoftShadowMap,
Color,
Clock,
AxesHelper,
LinearToneMapping,
} from "three";
import Stats from "stats.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
复制
���������������������������������������������config���������������div���id���������webgl-output
���������������������������������������������div������id���������������
// ���������������
const DEFAULT_CONFIG = {
domId: "webgl-output",
initPosition: new Vector3(20, 10, 10),
fov: 60,
near: 1,
far: 10000,
rendererOptions: {},
// ������������
clearColor: new Color(0x94959a),
// ������������Stats
showStats: false,
// AxesHelper
helper: 0,
// ���������
exposure: 1,
// ������������������������
enableDamping: true,
};
复制
������������������������Stage���������������������������������������������������������������
export default class Stage {
constructor(config) {
const dConfig = DEFAULT_CONFIG;
if (isObject(config)) {
Object.assign(dConfig, config);
}
const {
fov,
near,
far,
initPosition,
clearColor,
domId,
enableDamping,
} = dConfig;
this.scene = new Scene();
this.camera = new PerspectiveCamera(fov, window.innerWidth / window.innerHeight, near, far);
this.camera.position.copy(initPosition);
this.camera.lookAt(this.scene.position);
// ���������������
this.renderer = new WebGLRenderer({ antialias: true });
document.getElementById(domId)?.append(this.renderer.domElement);
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
this.orbitControls.enableDamping = enableDamping;
}
render() {
this.orbitControls.update();
this.beforeRender && this.beforeRender();
requestAnimationFrame(this.render.bind(this));
this.renderer.render(this.scene, this.camera);
}
}
复制
������������render������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������beforeRender
���������������������������render���������
������������������������������������������������������������������������������������������������������������������������
// ���������������������������
this.renderer.shadowMap.enabled = true;
// ���������������������������������THREE.PCFSoftShadowMap
this.renderer.shadowMap.type = PCFSoftShadowMap;
// ������������������������������
this.renderer.setClearColor(clearColor);
// ������������
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.toneMapping = LinearToneMapping;
// ���������
this.renderer.toneMappingExposure = exposure;
// ���������������������������������
this.renderer.physicallyCorrectLights = true;
复制
������������������Stage������������render���������������������������������������������������beforeRender������������������render������������������
import Stage from "./stage"
import { onMounted } from "vue"
class Panorama extends Stage {
constructor() {
super({
initPosition: new Vector3(0, 0, 1),
clearColor: new Color(0x000000),
});
// ���render���������������������������������������������������
// ������������������constructor���������������������������
this.render();
}
beforeRender() {
// ������������������������������������������������
}
}
onMounted(() => {
new Panorama();
});
复制
������������������������dom���������������������������������
������������
������������������������������������scene���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
������������������CubeTextureLoader������������������������������������������������������������������������[right,left,up,down,front,back]���������������������������������������
const urls = [
"/images/panorama/px.jpg",
"/images/panorama/nx.jpg",
"/images/panorama/py.jpg",
"/images/panorama/ny.jpg",
"/images/panorama/pz.jpg",
"/images/panorama/nz.jpg",
];
class Panorama extends Stage {
constructor() {
super({
initPosition: new Vector3(0, 0, 1),
clearColor: new Color(0x000000),
});
const cubeLoader = new CubeTextureLoader();
const map = cubeLoader.load(urls);
this.scene.background = map;
this.scene.environment = map;
this.render();
}
}
复制
���������������������������������������������������������������px���nx������������������������������x���y���z���������������p������positive���������n������negative���������������px���������������������nx���������������
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
���������
���������������������������������������������������������������������������������������������������
class Panorama extends Stage {
constructor() {
super({
fov: 75,
near: 1,
far: 1100,
initPosition: new Vector3(0, 0, 1),
clearColor: new Color(0x000000),
});
const sphereGeometry = new SphereGeometry(500, 50, 50);
sphereGeometry.scale(-1, 1, 1);
const sphereMaterial = new MeshBasicMaterial({
map: new TextureLoader().load("/images/panorama/panorama.jpg"),
});
const sphere = new Mesh(sphereGeometry, sphereMaterial);
this.scene.add(sphere);
this.render();
}
}
复制
������������������������������������������500������������������������������������������������������sphereGeometry.scale(-1, 1, 1)
���������������sphereGeometry.scale.x = -1
������������������x������������������
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
���������
���������������������������������������������������������������SphereGeometry���������������BoxGeometry���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
const urls = [
"/images/panorama/cubemap/px.png",
"/images/panorama/cubemap/nx.png",
"/images/panorama/cubemap/py.png",
"/images/panorama/cubemap/ny.png",
"/images/panorama/cubemap/pz.png",
"/images/panorama/cubemap/nz.png",
];
const materialArr = [];
const textureLoader = new TextureLoader();
urls.map((item) => {
const material = new MeshBasicMaterial({
map: textureLoader.load(item),
});
materialArr.push(material);
});
var box = new BoxGeometry(500, 500, 500);
var mesh = new Mesh(box, materialArr);
mesh.geometry.scale(-1, 1, 1);
this.scene.add(mesh);
复制
������������������������������������������������������������������Mesh������������������������������������������������������������������������������mesh���������X������������������
������������
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Threejs���������������Sprite������������������������������������������������������������������������������������������������������������������������
Sprite(material: Material)
复制
���������������material���SpriteMaterial������������������������������������������������������������������������������
������������
������������������������������������������������������������������������������������������������������dat.gui
������������XYZ���������������
const posList = [
{
x: -5,
y: -4,
z: -14,
content: "���",
},
{
x: -20,
y: -5,
z: -9,
content: "������",
},
{
x: 10,
y: -6,
z: 12,
content: "������",
},
];
复制
������������������������������������Sprite���������������������������������������������������������������������������������������������������png���������������������������SpriteMaterial������������������������������������Sprite������������������������
const spriteMaterial = new SpriteMaterial({
map: textureLoader.load("/images/icon/position.png")
});
posList.map((item) => {
const { x, y, z } = item;
const sprite = new Sprite(spriteMaterial);
sprite.position.set(x, y, z);
this.scene.add(sprite);
});
复制
���������������������������������������������������������������������
������������
���������������������������������������������������������������������������������������������������������Threejs���������������div������������������������������������������������������������������������������canvas���������������������������������������SpriteMaterial���map���������
const createSpriteLabel = (txt, x, y, z) => {
const canvas = document.createElement("canvas");
canvas.setAttribute("width", "286px");
canvas.setAttribute("height", "112px");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.lineWidth = 4;
const textMetrics = ctx.measureText(txt);
ctx.fillText(txt, (canvas.width - textMetrics.width) / 2, 55);
const texture = new Texture(canvas);
texture.needsUpdate = true;
const spriteMaterial = new SpriteMaterial({
map: texture,
});
const sp = new Sprite(spriteMaterial);
sp.scale.set(4, 2, 1);
sp.position.set(x, y, z);
return sp;
};
复制
������������������������canvas���������������������������������������������������������������canvas������Texture���������������map���������������SpriteMaterial���������������Sprite������������������������������
canvas������������������������������������������������������������������Sprite���������
���������������������������������CSS2DRenderer���CSS 2D������������������������������������������������������������������������������������������������������������div������������������������������������dom���������������������div���������������������������HTML������������������������������������������������dom������������������������������������������������������������������������������������������������DOM���������������������������������������������������������������������body������������������div������������������������������
import {
CSS2DRenderer,
CSS2DObject
} from "three/examples/jsm/renderers/CSS2DRenderer";
复制
������CSS2DRenderer���Threejs������������������������������������������������������������������CSS2DRenderer���������������������CSS2DObject������������������������������������������������������Stage������������������
export default class Stage {
constructor(config) {
// ...������������
//������CSS2DRenderer
const labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = "absolute";
labelRenderer.domElement.style.top = 0;
labelRenderer.domElement.style.left = 0;
this.labelRenderer = labelRenderer;
document.body.appendChild(labelRenderer.domElement);
// ���������������������������������renderer������labelRenderer
this.orbitControls = new OrbitControls(this.camera, this.labelRenderer.domElement);
}
render() {
this.renderer.render(this.scene, this.camera);
// ���������������CSS2DRenderer���������
this.labelRenderer.render(this.scene, this.camera);
}
}
复制
������CSS2DRenderer������������WebGLRenderer������������������������setSize���render������������������������������������domElement���������body���������CSS2DRenderer������������������������������������������������render���������������������������
������������������������������Sprite���������������������������div������������������������scene������
function createLableObj(text, x, y, z) {
let laberDiv = document.createElement("div"); //������div������
laberDiv.className = "laber_name";
laberDiv.innerHTML = text;
laberDiv.style.color = "#F4EA2A";
laberDiv.style.fontSize = "30px";
laberDiv.style.background = "url(/images/icon/position.png) no-repeat";
laberDiv.style.cursor = "pointer";
let pointLabel = new CSS2DObject(laberDiv);
pointLabel.position.set(x, y, z);
return pointLabel;
}
posList.map((item) => {
const { x, y, z, content } = item;
const label = createLableObj(content, x, y, z);
this.scene.add(label);
});
复制
������������������������������������div������������div���������������CSS2DObject������������������������������XYZ������������������������������������������Threejs���������������������������������������������������������������������
������������������
������������������������������������������������������������������������������������CSS2DRenderer������������������������������dom���������������������������������������������������������
// ������div������
const laberDiv = document.createElement("div");
// ������������������
laberDiv.addEventListener("click", (ev) => {
console.log("ev", ev);
});
// ������������������
laberDiv.addEventListener("mouseover", (ev) => {
console.log("ev", ev);
});
const pointLabel = new CSS2DObject(laberDiv);
复制
���������������������������������������������������������������������������������������������������������������������Sprite������������������������������Threejs������������������������������������������������������������������������Sprite���������addEventListener���������
������������������������������������������Raycaster������������������������������������������������������������������������������������������������������������������������������
������������������������������������������������������������������������������������������������������������������������������������������������������������������������
���������������������������������������
class Panorama extends Stage {
constructor() {
this.raycaster = new Raycaster();
this.mouse = new Vector2();
this.list = [];
posList.map((item) => {
this.list.push(sprite);
})
}
}
复制
���������������������Raycaster���������������������������mouse������������������������������������������������������������������������Sprite������������list������������Raycaster���������������������������������������������������������������������������������������scene.children������������������������������������������������������������������������������������������������������������������������������������������������
class Panorama extends Stage {
constructor() {
this._pointerMove = this.pointerMove.bind(this);
// ������������������������
this.renderer.domElement.addEventListener("mousemove", this._pointerMove);
}
pointerMove(event) {
// ������������������������������������������x ��� y ������������������������ (-1 to +1)
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// ������������������������������������������
this.raycaster.setFromCamera(this.mouse, this.camera);
const intersects = this.raycaster.intersectObjects(this.list);
if (intersects.length) {
// ������������������
console.log("intersects", intersects);
}
}
beforeDestroy() {
this.renderer.domElement.removeEventListener("mousemove", this._pointerMove);
}
}
复制
������������������������������������������������������event���������mouse���XY������������������setFromCamera������������������������������������������������������������������[-1, 1]������������������setFromCamera���������������������������������������������������������mouse���camera���������������������������������������intersectObject������������������������������������intersects������������������������Mesh���������
������������������Sprite���CSS2DRenderer���������������������������Sprite���������������������������������canvas������������������������������������������������������������CSS2DRenderer���������������������������������������������������������������������������������������������������������������������������������������������������������������������������
������������
������������������������������������������������������������������������������������������������������������������
���������������������������������������������������SphereGeometry���������������������������������������������������������������
class Panorama extends Stage {
constructor() {
super({
// ������
fov: 100,
near: 1,
far: 10000,
// ������������
initPosition: new Vector3(0, 500, 0),
clearColor: new Color(0x000000),
});
// ���������������500
const sphereGeometry = new SphereGeometry(500, 50, 50);
sphereGeometry.scale.x = -1;
const sphereMaterial = new MeshBasicMaterial({
map: new TextureLoader().load("/images/panorama/simons_town_harbour.jpg"),
});
const sphere = new Mesh(sphereGeometry, sphereMaterial);
this.sphere = sphere;
this.scene.add(sphere);
}
}
复制
���������������������initPosition
������������������������������������������������Y���500���������������������������������������500������������������������������������������������������������������������������������������������������������������
���������������������������������������tween.js���������������������������������������������������������������������������������������������������������������������������������������������������������tween.js������������������������������������������������������������������������������
import Tween from "@tweenjs/tween.js";
class Panorama extends Stage {
constructor() {
setTimeout(() => {
this.animateCamera();
}, 1.5 * 1000);
}
animateCamera() {
// ���������������������������
new Tween.Tween({
y: 500,
})
// ���������������������
.to({
y: 0,
}, 4000)
.onUpdate((pos) => {
// ������������
this.camera.position.y = pos.y;
this.camera.updateProjectionMatrix();
})
.start();
}
beforeRender() {
Tween.update();
}
}
复制
������������������������������������������������������������������������Tween���������������y������������������������������4000������������onUpdate������������������������������������y���������������������������start������������tween���������������������������������render���������������Tween.update
���������
new Tween.Tween({
y: 500,
fov: 100,
z: 0,
})
.to(
{
y: 0,
fov: 70,
z: -200,
},
4000,
)
.onUpdate((pos) => {
this.camera.position.y = pos.y;
this.camera.updateProjectionMatrix();
this.camera.fov = pos.fov;
this.camera.lookAt(new Vector3(0, 0, pos.z));
// ���������������������
this.sphere.rotation.y += 0.006;
})
.start();
复制
������������������������������������������������������������������������������������lookAt���������������������������������������������������������������������������������fov���100������������������������������fov���������������������������������������������
������������������������������������������������������������������������������������������������������