Jelajahi Sumber

制作新需求

bill 1 tahun lalu
induk
melakukan
ae52f97086

File diff ditekan karena terlalu besar
+ 1 - 0
public/vite.svg


+ 2 - 1
src/request/type.ts

@@ -35,6 +35,7 @@ export type ScenePoint = {
   tbStatus: number;
   createTime: string;
   updateTime: string;
+  cameraType: DeviceType;
   id: number;
   uuid: number;
   name: string;
@@ -50,7 +51,7 @@ export type Scene = {
   calcStatus?: SceneStatus;
   sceneName: string;
   title: string;
-  cameraType: number;
+  cameraType: DeviceType;
   scenePos: ScenePoint[];
   algorithmTime: string;
   endTime: string;

+ 17 - 12
src/store/scene.ts

@@ -22,16 +22,18 @@ export const scenePoints = computed(() =>
 export const relicsId = computed(() => relics.value!.relicsId);
 
 // https://4dkankan.oss-cn-shenzhen.aliyuncs.com/scene_view_data/KJ-t-OgSx9XIrvNQ/images/panoramas/22.jpg?x-oss-process=image/resize,m_fixed,w_6144&171342528615
-// const fileNames = new Array(6).fill(0);
-// export const getPointPano = (sceneCode: string, pid: number) =>
-//   fileNames.map(
-//     (_, i) =>
-//       `https://4dkk.4dage.com/scene_view_data/${sceneCode}/images/tiles/4k/${pid}_skybox${i}.jpg`
-//   );
 
-export const getPointPano = (sceneCode: string, pid: number) =>
-  `https://4dkankan.oss-cn-shenzhen.aliyuncs.com/scene_view_data/${sceneCode}/images/panoramas/${pid}.jpg`;
-// `https://4dkk.4dage.com/scene_view_data/${sceneCode}/images/pan/high/${pid}.jpg`;
+export const getPointPano = (sceneCode: string, pid: number, tile = false) => {
+  if (tile) {
+    const fileNames = new Array(6).fill(0);
+    return fileNames.map(
+      (_, i) =>
+        `https://4dkk.4dage.com/scene_view_data/${sceneCode}/images/tiles/4k/${pid}_skybox${i}.jpg`
+    );
+  } else {
+    return `https://4dkankan.oss-cn-shenzhen.aliyuncs.com/scene_view_data/${sceneCode}/images/panoramas/${pid}.jpg`;
+  }
+};
 export const refreshScenes = async () => {
   scenes.value = await relicsScenesFetch(relicsId.value);
 };
@@ -55,15 +57,18 @@ export const updateScenePointName = async (
 
 export const gotoScene = (scene: Scene, edit = false) => {
   const params = new URLSearchParams();
-  params.set("m", scene.sceneCode);
   if (edit) {
     params.set("token", gHeaders.token);
   }
   params.set("lang", "zh");
   if (scene.sceneCode.startsWith("KJ")) {
-    window.open(`https://test.4dkankan.com/spg.html?` + params.toString());
+    params.set("id", scene.sceneCode);
+    window.open(
+      `https://www.4dkankan.com/panorama/show.html?` + params.toString()
+    );
   } else {
-    window.open(`https://uat-laser.4dkankan.com/uat/?` + params.toString());
+    params.set("m", scene.sceneCode);
+    window.open(`https://laser.4dkankan.com/?` + params.toString());
   }
 };
 

+ 1 - 1
src/view/login.vue

@@ -126,7 +126,7 @@ watch(
   () => {
     if (!form.phone) {
       verification.phone = "请输入手机号";
-    } else if (form.phone == "88888888888") {
+    } else if (["88888888888", "99999999999"].includes(form.phone)) {
       verification.phone = "";
     } else {
       verification.phone = PHONE.REG.test(form.phone) ? "" : PHONE.tip;

+ 11 - 1
src/view/map/map-right.vue

@@ -90,7 +90,13 @@
       type="primary"
       :icon="Document"
       style="width: 100%; margin-top: 20px; margin-left: 0"
-      @click="exportImage(getSelectPoints())"
+      @click="
+        exportImage(
+          getSelectPoints().filter(
+            (point) => getPointSelect(point)?.cameraType === DeviceType.VR
+          )
+        )
+      "
     >
       下载全景图
     </el-button>
@@ -133,6 +139,7 @@ import { router } from "@/router";
 import { selectScenes } from "../quisk";
 import { addRelicsSceneFetch, delRelicsSceneFetch } from "@/request";
 import { exportFile, exportImage } from "./pc4Helper";
+import { DeviceType } from "@/store/device";
 
 const emit = defineEmits<{
   (e: "flyScene", data: Scene): void;
@@ -176,6 +183,9 @@ const getSelectPoints = () =>
     .filter((option: any) => option.type === "point")
     .map((option: any) => option.raw) as ScenePoint[];
 
+const getPointSelect = (point: ScenePoint) =>
+  scenes.value.find((scene) => scene.sceneCode === point.sceneCode);
+
 const addHandler = async () => {
   const sceneCodes = scenes.value.map((scene) => scene.sceneCode);
   await selectScenes({

+ 1 - 1
src/view/map/pc4Helper.ts

@@ -39,7 +39,7 @@ export const exportImage = async (points: ScenePoint[]) => {
   const downloadImages = Promise.all(
     points.map((point) => {
       const url = getPointPano(point.sceneCode, point.uuid);
-      return fetch(url)
+      return fetch(url as string)
         .then((res) => res.blob())
         .then((blob) => {
           imgFolder.file(`${point.sceneCode}-${point.uuid}.jpg`, blob);

+ 64 - 38
src/view/pano/env.ts

@@ -1,4 +1,5 @@
 import envFragSource from "./shader-env.frag?raw";
+import envCubeFragSource from "./shader-env-cube.frag?raw";
 import envVertSource from "./shader-env.vert?raw";
 import { loadImage } from "@/util";
 import { createFPSCamera, createProgram, generateVao, useTex } from "@/util/gl";
@@ -7,27 +8,29 @@ import { setUniforms } from "./setUniform";
 
 const generatePreset = (gl: WebGL2RenderingContext) => {
   const skyCubeTex = gl.createTexture();
-  // const updateSky1 = (images: HTMLImageElement[]) => {
-  //   gl.bindTexture(gl.TEXTURE_CUBE_MAP, skyCubeTex);
-  //   const mapper = [2, 4, 0, 5, 1, 3];
-  //   for (let i = 0; i < 6; i++) {
-  //     gl.texImage2D(
-  //       gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
-  //       0,
-  //       gl.RGB,
-  //       gl.RGB,
-  //       gl.UNSIGNED_BYTE,
-  //       images[mapper[i]]
-  //     );
-  //   }
-  //   gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
-  //   gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-  //   gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
-  //   gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
-  //   gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-  //   gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
-  //   gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
-  // };
+  const skyCubeTex1 = gl.createTexture();
+  const updateSky1 = (images: HTMLImageElement[]) => {
+    gl.bindTexture(gl.TEXTURE_CUBE_MAP, skyCubeTex1);
+    const mapper = [2, 4, 0, 5, 1, 3];
+    for (let i = 0; i < 6; i++) {
+      gl.texImage2D(
+        gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
+        0,
+        gl.RGB,
+        gl.RGB,
+        gl.UNSIGNED_BYTE,
+        images[mapper[i]]
+      );
+    }
+    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+    gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+  };
+
   const updateSky = (image: HTMLImageElement) => {
     gl.bindTexture(gl.TEXTURE_2D, skyCubeTex);
     gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
@@ -38,13 +41,19 @@ const generatePreset = (gl: WebGL2RenderingContext) => {
 
   return {
     skyCubeTex,
+    skyCubeTex1,
     // async preset(urls: string[]) {
     //   const images = await Promise.all(urls.map(loadImage));
     //   updateSky(images);
     // },
-    async preset(url: string) {
-      const image = await loadImage(url);
-      updateSky(image);
+    async preset(url: string | string[]) {
+      if (Array.isArray(url)) {
+        const images = await Promise.all(url.map(loadImage));
+        updateSky1(images);
+      } else {
+        const image = await loadImage(url);
+        updateSky(image);
+      }
     },
   };
 };
@@ -71,16 +80,25 @@ const getDrawVaring = (gl: WebGL2RenderingContext) => {
 };
 
 export const init = (canvas: HTMLCanvasElement) => {
-  const size = [canvas.width, canvas.height];
+  let activeTex: "skyCubeTex1" | "skyCubeTex" = "skyCubeTex1";
   const gl = canvas.getContext("webgl2", { preserveDrawingBuffer: true })!;
   const program = createProgram(gl, envVertSource, envFragSource);
-  const projectionMat = mat4.perspective(
-    mat4.create(),
-    glMatrix.toRadian(45),
-    size[0] / size[1],
-    0.1,
-    100
-  );
+  const program1 = createProgram(gl, envVertSource, envCubeFragSource);
+
+  const setSize = (size: number[]) => {
+    mat4.perspective(
+      projectionMat,
+      glMatrix.toRadian(45),
+      size[0] / size[1],
+      0.1,
+      100
+    );
+    gl.viewport(0, 0, size[0], size[1]);
+    updateInv();
+    redraw();
+  };
+
+  const projectionMat = mat4.create();
   const invProjectionViewMat = mat4.create();
   const viewMat = mat4.create();
   const varing = getDrawVaring(gl);
@@ -89,20 +107,24 @@ export const init = (canvas: HTMLCanvasElement) => {
     mat4.invert(invProjectionViewMat, invProjectionViewMat);
   };
 
-  gl.viewport(0, 0, size[0], size[1]);
   const redraw = () => {
     gl.clear(gl.COLOR_BUFFER_BIT);
     gl.enable(gl.DEPTH_TEST);
     gl.depthFunc(gl.LEQUAL);
-    gl.useProgram(program);
+    const g = activeTex === "skyCubeTex" ? program : program1;
+    gl.useProgram(g);
     gl.bindVertexArray(varing.vao);
-    setUniforms(gl, program, {
+    setUniforms(gl, g, {
       invProjectionViewMat,
-      envTex: useTex(gl, varing.skyCubeTex!),
+      envTex:
+        activeTex === "skyCubeTex1"
+          ? useTex(gl, varing.skyCubeTex1!, gl.TEXTURE_CUBE_MAP, 1)
+          : useTex(gl, varing.skyCubeTex!, gl.TEXTURE_2D),
     });
     gl.drawArrays(gl.TRIANGLES, 0, varing.numArrays);
   };
 
+  setSize([canvas.width, canvas.height]);
   const fps = createFPSCamera(
     canvas.parentElement!,
     (nViewMat) => {
@@ -116,10 +138,14 @@ export const init = (canvas: HTMLCanvasElement) => {
     80
   );
   return {
+    setSize,
     redraw,
-    changeUrls(urls: string) {
+    changeUrls(urls: string | string[]) {
       fps.recovery();
-      return varing.preset(urls).then(redraw);
+      return varing.preset(urls).then(() => {
+        activeTex = Array.isArray(urls) ? "skyCubeTex1" : "skyCubeTex";
+        redraw();
+      });
     },
     destory: fps.destory,
   };

+ 36 - 20
src/view/pano/pano.vue

@@ -45,16 +45,12 @@ import { router, setDocTitle } from "@/router";
 import { mergeFuns } from "@/util";
 import { computed, onMounted, onUnmounted, ref, watchEffect } from "vue";
 import { init } from "./env";
-import {
-  scenePoints,
-  updateScenePointName,
-  getPointPano,
-  ScenePoint,
-} from "@/store/scene";
+import { updateScenePointName, getPointPano, ScenePoint } from "@/store/scene";
 import { copyText, toDegrees } from "@/util";
 import { ElMessage } from "element-plus";
 import { relicsScenePosInfoFetch } from "@/request";
 import saveAs from "@/util/file-serve";
+import { DeviceType } from "@/store/device";
 
 type Params = { pid?: string } | null;
 const params = computed(() => router.currentRoute.value.params as Params);
@@ -64,18 +60,20 @@ const point = ref<ScenePoint>();
 watchEffect(() => {
   if (params.value?.pid) {
     const pid = Number(params.value!.pid);
-    const cachePoint = scenePoints.value.find((point) => point.id === pid);
-    if (!cachePoint) {
-      relicsScenePosInfoFetch(pid).then((data) => (point.value = data));
-    } else {
-      point.value = cachePoint;
-    }
+    relicsScenePosInfoFetch(pid).then((data) => (point.value = data));
   }
 });
 
-const panoUrls = computed(
-  () => point.value && getPointPano(point.value.sceneCode, Number(point.value.uuid))
-);
+const panoUrls = computed(() => {
+  return (
+    point.value &&
+    getPointPano(
+      point.value.sceneCode,
+      Number(point.value.uuid),
+      point.value.cameraType === DeviceType.CLUNT
+    )
+  );
+});
 const update = ref(false);
 const loading = ref(false);
 
@@ -88,21 +86,36 @@ const copyGis = async () => {
 };
 
 const photo = () => {
+  loading.value = true;
+  setSize(3, 1920, 1080);
   panoDomRef.value!.toBlob(async (blob) => {
     if (blob) {
       await saveAs(blob, "pano.png");
       ElMessage.success("图片导出成功");
     }
+
+    setSize(devicePixelRatio);
+    loading.value = false;
   }, "image/png");
 };
 
+let pano: ReturnType<typeof init>;
+const setSize = (ration: number, w?: number, h?: number) => {
+  const canvas = panoDomRef.value!;
+  canvas.width = (w || canvas.offsetWidth) * ration;
+  canvas.height = (h || canvas.offsetHeight) * ration;
+  pano.setSize([canvas.width, canvas.height]);
+};
+
 onMounted(() => {
   if (!panoDomRef.value) throw "没有canvas DOM";
-  const canvas = panoDomRef.value;
-  canvas.width = canvas.offsetWidth * 2;
-  canvas.height = canvas.offsetHeight * 2;
-  const pano = init(canvas);
+  pano = init(panoDomRef.value);
+  const resizeHandler = () => {
+    setSize(devicePixelRatio);
+  };
+  resizeHandler();
 
+  window.addEventListener("resize", resizeHandler);
   destroyFns.push(
     watchEffect(() => {
       if (panoUrls.value) {
@@ -110,7 +123,10 @@ onMounted(() => {
         pano.changeUrls(panoUrls.value).then(() => (loading.value = false));
       }
     }),
-    pano.destory
+    pano.destory,
+    () => {
+      window.removeEventListener("resize", resizeHandler);
+    }
   );
 });
 

+ 26 - 0
src/view/pano/shader-env-cube.frag

@@ -0,0 +1,26 @@
+#version 300 es
+precision mediump float;
+
+#define PI 3.14159265359
+
+uniform samplerCube envTex;
+
+in vec4 vLocalPosition;
+
+const vec2 invAtan = vec2(1.0 / (PI * 2.0), -1.0 / PI);
+vec2 getSphereUV(vec3 v) {
+    vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
+    uv *= invAtan; 
+    uv += 0.5;
+    uv = mod(uv, 1.0);
+    return uv;
+}
+
+out vec4 vFragColor;
+void main(){
+  vec3 nor = normalize(vLocalPosition.xyz / vLocalPosition.w);
+  vec2 uv = getSphereUV(nor);
+  vec3 color = texture(envTex, nor).rgb;
+  // color /= color + 1.0;
+  vFragColor = vec4(color, 1);
+}

+ 7 - 7
vite.config.ts

@@ -19,16 +19,16 @@ export default defineConfig({
     port: 5173,
     open: true,
     proxy: {
-      "/api": {
-        target: "http://192.168.0.11:8324",
-        changeOrigin: true,
-        rewrite: (path) => path.replace(/^\/api/, ""),
-      },
       // "/api": {
-      //   target: `sp.4dkankan.com`,
+      //   target: "http://192.168.0.11:8324",
       //   changeOrigin: true,
-      //   rewrite: (path) => path.replace(/^\/api/, "/api"),
+      //   rewrite: (path) => path.replace(/^\/api/, ""),
       // },
+      "/api": {
+        target: `http://sp.4dkankan.com`,
+        changeOrigin: true,
+        rewrite: (path) => path.replace(/^\/api/, "/api"),
+      },
     },
   },
 });