ground.vue 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. <template></template>
  2. <script lang="ts" setup>
  3. import {
  4. FrontSide,
  5. Mesh,
  6. MeshPhysicalMaterial,
  7. PlaneGeometry,
  8. RepeatWrapping,
  9. TextureLoader,
  10. Vector2,
  11. } from "three";
  12. import { useRender, useTree } from "../hook/use-stage";
  13. import { subgroupName } from "../container";
  14. import { useLineBBox } from "../hook/use-getter";
  15. import { EXRLoader } from "three/examples/jsm/Addons.js";
  16. import { pickPromise } from "@/utils/shared";
  17. const geometry = new PlaneGeometry(1, 1);
  18. const padding = 100;
  19. const tileSize = 100;
  20. const bbox = useLineBBox();
  21. const size = bbox.value.size.clone().add({ x: padding * 2, y: padding * 2 });
  22. const tileCount = size.clone().multiplyScalar(1 / tileSize);
  23. const texloads: Promise<void>[] = [];
  24. const loadTex = (loader: TextureLoader | EXRLoader, url: string) => {
  25. const { promise, resolve, reject } = pickPromise<void>();
  26. texloads.push(promise);
  27. const tex = loader.load(
  28. `/static/models/texture/ground/${url}`,
  29. () => resolve(),
  30. undefined,
  31. reject
  32. );
  33. tex.wrapS = RepeatWrapping;
  34. tex.wrapT = RepeatWrapping;
  35. tex.repeat.copy(tileCount);
  36. return tex;
  37. };
  38. const texLoader = new TextureLoader();
  39. const exrLoader = new EXRLoader();
  40. const diffuseMap = loadTex(texLoader, "laminate_floor_02_diff_1k.jpg");
  41. const displacementMap = loadTex(texLoader, "laminate_floor_02_disp_1k.png");
  42. const normalMap = loadTex(exrLoader, "laminate_floor_02_nor_gl_1k.exr");
  43. const roughnessMap = loadTex(exrLoader, "laminate_floor_02_rough_1k.exr");
  44. const render = useRender();
  45. Promise.all(texloads).then(render);
  46. const material = new MeshPhysicalMaterial({
  47. // 基础属性
  48. color: 0xffffff, // 基础颜色(会被贴图覆盖)
  49. map: diffuseMap, // 颜色贴图
  50. // 物理渲染属性
  51. roughness: 0.7, // 基础粗糙度(会被粗糙度贴图调整)
  52. metalness: 0.0, // 木材无金属性
  53. clearcoat: 0.1, // 轻微清漆效果
  54. clearcoatRoughness: 0.2,
  55. // 贴图增强
  56. normalMap: normalMap, // 法线贴图
  57. normalScale: new Vector2(1, 1), // 法线强度
  58. displacementMap: displacementMap, // 置换贴图
  59. displacementScale: 0.05, // 置换强度(根据实际效果调整)
  60. displacementBias: -0.02,
  61. roughnessMap: roughnessMap, // 粗糙度贴图
  62. // 其他设置
  63. side: FrontSide,
  64. transparent: false,
  65. premultipliedAlpha: false,
  66. });
  67. const ground = new Mesh(geometry, material);
  68. ground.receiveShadow = true;
  69. ground.name = subgroupName;
  70. ground.scale.set(size.x, size.y, 1);
  71. ground.rotateX(-Math.PI / 2);
  72. useTree().value = ground;
  73. </script>