Oasis Engine 3d全景展示demo

Oasis Engine 是一套 Web 为先,移动优先的互动引擎,使用 Typescript 编写。核心功能由 oasis-engine 提供,非核心和偏业务逻辑定制的高级功能由 oasis-engine-toolkit 提供,推荐通过 NPM 的方式进行安装:

官网:Oasis Engine

体验demo地址:3D全景展示 

1660708514209838

<!--
 * @Descripttion: 天道通勤
 * @version: 1.0.1
 * @Author: 汤玉鹏
 * @Date: 2022-07-06 15:00:10
 * @LastEditors: typ
 * @LastEditTime: 2022-08-17 11:45:12
-->
<script setup lang="ts">
import { ElLoading } from "element-plus";
import { onMounted, ref, reactive, getCurrentInstance } from "vue";
// import { createOasis } from "./oasis";
import { OrbitControl, OrthoControl } from "@oasis-engine-toolkit/controls";
// import { OrbitControl,OrthoControl } from "@oasis-engine-toolkit";
import {
  AmbientLight,
  AssetType,
  BackgroundMode,
  Camera,
  DirectLight,
  GLTFResource,
  Logger,
  PrimitiveMesh,
  SkyBoxMaterial,
  WebGLEngine,
  Script,
  Vector3,
  Animator,
  SpotLight,
  PointLight
} from "oasis-engine";
// 右上角面板
// const gui = new dat.GUI();
const msg = ref("Hello Vue3");
const instance = getCurrentInstance();
const setShow = ref(false);
const innerHeight = ref(969);
const tablePage = reactive({
  formData: {
    pageNum: 1,
    pageSize: 10,
    galleryType: 1
  },
  a: 1
});
const show = () => {
  setShow.value = true;
};

const hide = () => {
  setShow.value = false;
};

const createOasis = () => {
  show();
  const engine = new WebGLEngine("canvas");
  Logger.enable();
  //-- create engine object

  engine.canvas.resizeByClientSize();

  const scene = engine.sceneManager.activeScene;
  const { ambientLight, background } = scene;
  const rootEntity = scene.createRootEntity();

  //Create camera 创建相机
  const cameraNode = rootEntity.createChild("camera_node");
  // setPosition 通过X, Y, Z值设置本地位置。
  cameraNode.transform.setPosition(0, 0, 5);
  cameraNode.addComponent(Camera);
  // cameraNode.addComponent(OrbitControl);

  // 设置相机能够上下左右旋转的角度
  const control = cameraNode.addComponent(OrbitControl);
  // 判定的距离操作合理范围的最小值
  control.minDistance = 2;
  // 判定的距离操作合理范围的最大值
  control.maxDistance = 7;
  //竖直方向操作合理范围的最大弧度
  // control.maxPolarAngle = (Math.PI * 3) / 4;
  //竖直方向操作合理范围的最小弧度
  // control.minPolarAngle = (Math.PI * 1) / 4;
  // 水平方向操作合理范围的最大弧度,默认为正无穷大
  // control.maxAzimuthAngle = Math.PI / 2;
  // 水平方向操作合理范围的最小弧度,默认为负无穷大
  // control.minAzimuthAngle = -Math.PI / 2;
  // 相机旋转速度,默认为 1.0
  control.rotateSpeed = 0.7;
  // 是否支持相机旋转,默认为 true
  // control.enableRotate = true;

  // Create sky 创建的天空
  const sky = background.sky;
  const skyMaterial = new SkyBoxMaterial(engine);
  background.mode = BackgroundMode.SolidColor;
  //rgb(116, 111, 108)=(1-116/255,111/255,108/255,1(透明度))
  background.solidColor.set(0.545, 0.565, 0.576, 1);

  sky.material = skyMaterial;
  sky.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);

  // 光照

  //平行光1正面
  // const lightEntityDirect = rootEntity.createChild("light");
  // const directLight = lightEntityDirect.addComponent(DirectLight);
  // //光照颜色
  // directLight.color.set(1, 1, 1, 1);
  // //光照强度
  // directLight.intensity = 1;
  // // 调整方向
  // lightEntityDirect.transform.setRotation(0, 0, 10);

  // //平行光2背面
  // const lightEntityDirec2 = rootEntity.createChild("light");
  // const directLight2 = lightEntityDirec2.addComponent(DirectLight);
  // //光照颜色
  // directLight2.color.set(1, 1, 1, 1);
  // //光照强度
  // directLight2.intensity = 1;
  // // 调整方向
  // lightEntityDirec2.transform.setRotation(0, 0, 100);

  // 聚光灯1正面
  const lightEntitySpot = rootEntity.createChild("light");
  const spotLight = lightEntitySpot.addComponent(SpotLight);

  spotLight.angle = Math.PI / 10; // 散射角度
  spotLight.penumbra = Math.PI / 6; // 半影衰减角度
  spotLight.color.set(1, 1, 1, 1);
  // 光照强度
  spotLight.intensity = 5;
  //光照距离
  spotLight.distance = 1.5;
  //光照位置
  lightEntitySpot.transform.setPosition(0, 1.5, 0.1);
  //光照角度
  lightEntitySpot.transform.setRotation(-90, 0, 0);

  // 聚光灯2背面
  const lightEntitySpot2 = rootEntity.createChild("light");
  const spotLight2 = lightEntitySpot2.addComponent(SpotLight);

  spotLight2.angle = Math.PI / 10; // 散射角度
  spotLight2.penumbra = Math.PI / 6; // 半影衰减角度
  spotLight2.color.set(1, 1, 1, 1);
  // 光照强度
  spotLight2.intensity = 5;
  //光照距离
  spotLight2.distance = 2;
  //光照位置
  lightEntitySpot2.transform.setPosition(0, 1.5, -0.1);
  //光照角度
  lightEntitySpot2.transform.setRotation(-90, 0, 0);

  // 点光1正面
  const lightEntityPoint = rootEntity.createChild("light");
  const pointLight = lightEntityPoint.addComponent(PointLight);
  // 光照强度
  pointLight.intensity = 2;
  //光照距离
  pointLight.distance = 0.4;
  // 光照颜色
  pointLight.color.set(1, 1, 1, 1);
  //光照位置
  lightEntityPoint.transform.setPosition(-0.5, -0.8, 0.3);

  // 点光2正面
  const lightEntityPoint2 = rootEntity.createChild("light");
  const pointLight2 = lightEntityPoint2.addComponent(PointLight);
  // 光照强度
  pointLight2.intensity = 5;
  //光照距离
  pointLight2.distance = 1;
  // 光照颜色
  pointLight2.color.set(1, 1, 1, 1);
  //光照位置
  lightEntityPoint2.transform.setPosition(1, 0.5, 0);

  // 点光3背面
  const lightEntityPoint3 = rootEntity.createChild("light");
  const pointLight3 = lightEntityPoint3.addComponent(PointLight);
  // 光照强度
  pointLight3.intensity = 2;
  //光照距离
  pointLight3.distance = 0.4;
  // 光照颜色
  pointLight3.color.set(1, 1, 1, 1);
  //光照位置
  lightEntityPoint3.transform.setPosition(-0.5, -0.8, -0.3);

  // 点光4背面
  const lightEntityPoint4 = rootEntity.createChild("light");
  const pointLight4 = lightEntityPoint4.addComponent(PointLight);
  // 光照强度
  pointLight4.intensity = 2;
  //光照距离
  pointLight4.distance = 1;
  // 光照颜色
  pointLight4.color.set(1, 1, 1, 1);
  //光照位置
  lightEntityPoint4.transform.setPosition(1, -0.6, 0);

  // 点光5背面
  const lightEntityPoint5 = rootEntity.createChild("light");
  const pointLight5 = lightEntityPoint5.addComponent(PointLight);
  // 光照强度
  pointLight5.intensity = 2;
  //光照距离
  pointLight5.distance = 1.5;
  // 光照颜色
  pointLight5.color.set(1, 1, 1, 1);
  //光照位置
  lightEntityPoint5.transform.setPosition(-1, 0, 0);

  // 点光6背面
  const lightEntityPoint6 = rootEntity.createChild("light");
  const pointLight6 = lightEntityPoint6.addComponent(PointLight);
  // 光照强度
  pointLight6.intensity = 1;
  //光照距离
  pointLight6.distance = 2;
  // 光照颜色
  pointLight6.color.set(1, 1, 1, 1);
  //光照位置
  lightEntityPoint6.transform.setPosition(0.3, -1, -1);
  window.onresize = () => {
    return (() => {
      // 监听浏览器发生变化,并重新初始化模型,防止变形
      engine.canvas.resizeByClientSize();
    })();
  };
  //光照完结--------

  Promise.all([
    engine.resourceManager
      // GLTF资源路径
      // .load<GLTFResource>("src/assets/sxgs.gltf")
      // .load<GLTFResource>("src/assets/mao.glb")
      .load<GLTFResource>(
        "https://file.zhenqingkongjian.com/gallery/embroidery/361d6f_fengye.glb"
      )
      // .load<GLTFResource>("https://gw.alipayobjects.com/os/bmw-prod/150e44f6-7810-4c45-8029-3575d36aff30.gltf")
      .then(gltf => {
        const model = gltf.defaultSceneRoot;
        // 设置模型默认旋转的角度
        // model.transform.rotate(0, 0, 0);
        // 设置模型偏移位置
        model.transform.setPosition(0, 0, 0);

        const entity = rootEntity.createChild("");
        entity.addChild(gltf.defaultSceneRoot);

        // entity.transform.rotate(new Vector3(0, 0, 0))

        // 添加旋转方法
        model.addComponent(Rotate);
      }),
    // 环境光
    engine.resourceManager
      .load<AmbientLight>({
        type: AssetType.Env,
        // url: "https://gw.alipayobjects.com/os/bmw-prod/f369110c-0e33-47eb-8296-756e9c80f254.bin"
        url:
          "https://file.zhenqingkongjian.com/gallery/embroidery/88c5b9_modelBg081.env"
        // url: "src/assets/modelBg.hdr.env"
      })
      .then(ambientLight => {
        scene.ambientLight = ambientLight;
        skyMaterial.textureCubeMap = ambientLight.specularTexture;
        skyMaterial.textureDecodeRGBM = true;
        // 设置环境光颜色
        // ambientLight.diffuseSolidColor.set(0.5, 0.5, 1, 1);
        // 设置环境光强度
        ambientLight.diffuseIntensity = 0.5;
        // openDebug(ambientLight.specularTexture);
      })
  ]).then(results => {
    console.log("results:", results);
    engine.run();
    let getNum = 0;
    let getNumber = setInterval(() => {
      getNum++;
      if (getNum == 10) {
        clearInterval(getNumber);
        engine.canvas.resizeByClientSize();
        hide();
      }
    }, 100);
    console.log("加载完成.....");
  });
  // 旋转逻辑
  class Rotate extends Script {
    private _tempVector = new Vector3(0, 0.75, 0); //旋转方向和速度控制,现为绕Y轴旋转,每帧旋转0.625°
    private _totalTime: number = 0;
    private _countNum: number = 0;

    onStart() {
      console.log("_countNum:", this._countNum);
    }
    onUpdate(deltaTime: number) {
      if (this._countNum < 200) {
        this._countNum++; //时间累进
        this.entity.transform.rotate(this._tempVector); //控制旋转,旋转时长为240ms,旋转角度为200*0.75 = 150°
        const scaleFactor = 250 / this._countNum; //缩放的倍数控制,由最大倍数缩小至1.25(250/200)倍
        this.entity.transform.scale = new Vector3(
          scaleFactor,
          scaleFactor,
          scaleFactor
        );
      }
    }
  }
};

onMounted(() => {
  innerHeight.value = window.innerHeight;

  // engine.canvas.resizeByClientSize();
  // alert(window.screen.availHeight + "---" + window.innerHeight);

  createOasis();
});
</script>

<template>
  <div class="content-box">
    <!-- {
   
   {innerHeight}} -->
    <!-- {
   
   { msg }}--{
   
   { tablePage.formData.pageNum }}--{
   
   { tablePage.a }} -->
    <transition name="test">
      <div class="page" @click.stop v-show="setShow">
        <div class="loadings">
          <img
            src="./assets/bgtu.png"
            alt=""
            width="80"
            style="width:80px; margin-bottom:10px"
          />
          <el-progress
            :percentage="20"
            :indeterminate="true"
            :show-text="false"
            color="#ffca85"
          />
        </div>
      </div>
    </transition>
    <canvas
      :style="{ width: '100vw', height: innerHeight + 'px' }"
      id="canvas"
    />
  </div>
</template>
<style>
.test-enter,
.test-leave-to {
  opacity: 0;
}
.test-enter-to,
.test-leave {
  opacity: 1;
}
.test-enter-active,
.test-leave-active {
  transition: all 2s;
}
::v-deep .el-progress-bar__outer {
  background-color: #746f6c;
}
.loadings {
  width: 100px;
  text-align: center;
  background: #000;
  padding: 20px;
  border-radius: 10px;
}
.page {
  position: fixed;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  top: 0;
  left: 0;
  z-index: 999;
  background: rgba(0, 0, 0, 1);
}
.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30vw;
  height: 30vw;
  background: rgba(0, 0, 0, 0.7);
  border-radius: 6px;
}
.el-loading-mask {
  position: absolute;
  z-index: 2000;
  background-color: rgba(0, 0, 0, 0.1);
  margin: 0;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  transition: opacity 0.3s;
}
.lodding-box {
  position: absolute;
  top: 50%;
  left: 50%;
  margin-left: -60px;
  margin-top: -60px;
  z-index: 2001;
}
.loading {
  width: 60px;
  height: 60px;
  margin: 0 auto;
  margin-top: 100px;
  position: relative;
  -webkit-animation: load 3s linear infinite;
}
.loading div {
  width: 100%;
  height: 100%;
  position: absolute;
}
.loading span {
  display: inline-block;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #99cc66;
  position: absolute;
  left: 50%;
  margin-top: -10px;
  margin-left: -10px;
  -webkit-animation: changeBgColor 3s ease infinite;
}
@-webkit-keyframes load {
  0% {
    -webkit-transform: rotate(0deg);
  }
  33.3% {
    -webkit-transform: rotate(120deg);
  }
  66.6% {
    -webkit-transform: rotate(240deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
  }
}
@-webkit-keyframes changeBgColor {
  0%,
  100% {
    background: #99cc66;
  }
  33.3% {
    background: #ffff66;
  }
  66.6% {
    background: #ff6666;
  }
}
.loading div:nth-child(2) {
  -webkit-transform: rotate(120deg);
}
.loading div:nth-child(3) {
  -webkit-transform: rotate(240deg);
}
.loading div:nth-child(2) span {
  -webkit-animation-delay: 1s;
}
.loading div:nth-child(3) span {
  -webkit-animation-delay: 2s;
}
.content-box {
  position: relative;
}
.leftbox_img {
  position: absolute;
  top: 10px;
  left: 10px;
  right: 0;
}
.leftText {
  color: #fff;
}
</style>

猜你喜欢

转载自blog.csdn.net/qq_27318177/article/details/126383197