暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一文掌握你所需Threejs3D全景预览

原创 wpp 2023-05-19
128

�����������������������������������������

���������������������������������������������������������������������������������������������������������������������������������������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();
  }
}
复制

panorama.gif

������������������

���������������������������������������������������������������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);
});
复制

���������������������������������������������������������������������

anchor.gif

������������

���������������������������������������������������������������������������������������������������������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������������������������������

CSS2DRenderer������

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���������������������������������������������������������������������

label.gif

������������������

������������������������������������������������������������������������������������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���������������������������������������������������������������������������������������������������������������������������������������������������������������������������

������������

������������������������������������������������������������������������������������������������������������������

animation.gif

���������������������������������������������������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���������������������������������������������

������������������������

������������������������������������������������������������������������������������������������������

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

A
askTom
关注
暂无图片
获得了15次点赞
暂无图片
内容获得6次评论
暂无图片
获得了38次收藏
目录
  • data-������������
    • data-������������
    • data-Threejs������
    • data-������������
    • data-���������
    • data-���������
  • data-������������
    • data-������������
    • data-������������
    • data-������������������
  • data-������������