城市边界电子围栏
初始化摄像头、灯光等
  let renderer, scene, camera, stats, gui, texture;
  renderer = new THREE.WebGLRenderer({
    logarithmicDepthBuffer: true,
  });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.getElementById("hello3D").appendChild(renderer.domElement);
  scene = new THREE.Scene();
  // AxesHelper:辅助观察的坐标系
  const axesHelper = new THREE.AxesHelper(150);
  scene.add(axesHelper);
  camera = new THREE.PerspectiveCamera(30,window.innerWidth / window.innerHeight,0.1,2000);
  // 设置相机 在 threejs 三维坐标系中的位置
  camera.position.set(0, 0, 150);
  const controls = new OrbitControls(camera, renderer.domElement);
  const ambient = new THREE.AmbientLight(0xffffff, 1);
  scene.add(ambient);
城市围栏
以河南省城市数据为例子,边界线 去高德或者datav中自己过去,本样例是使用的高德api获取的处理的边界线
 threejs 是以三角形确定面的
 以下代码为了后面的贴图,直接创建了uv数组
 uv的数据一定要和三角形的数据一致,一个三角形对应三个坐标,可以这样理解:一个面由两个三角形组成,一个三角形对应的uv是三个坐标
const depth = 3;
city.forEach((polygon) => {
  // 三角形点
  const vec3List = [];
  // 三角面
  const faceList = [];
  // uv
  const uvList = [];
  const t0 = [0, 0];
  const t1 = [1, 0];
  const t2 = [1, 1];
  const t3 = [0, 1];
  for (let i = 0; i < polygon.length; i++) {
    let [x, y] = projection(polygon[i]);
    // 根据数组创建三角形点的顺序数组
    vec3List.push([x, y, 0]);
    vec3List.push([x, y, -depth]);
  }
  // 根据三角形点组成面的数组
  for (let i = 0; i < vec3List.length - 2; i++) {
    if (i % 2 == 0) {
      // 下三角
      const face = [
        ...vec3List[i],
        ...vec3List[i + 2],
        ...vec3List[i + 1],
      ];
      Array.prototype.push.apply(faceList, face);
      // uv 一定要和三角形面一致
      const uv = [...t0, ...t1, ...t3];
      Array.prototype.push.apply(uvList, uv);
    } else {
      // 上三角
      const face = [
        ...vec3List[i],
        ...vec3List[i + 2],
        ...vec3List[i + 1],
      ];
      Array.prototype.push.apply(faceList, face);
      const uv = [...t3, ...t2, ...t1];
      Array.prototype.push.apply(uvList, uv);
    }
  }
  const geometryWall = new THREE.BufferGeometry();
  geometryWall.setAttribute(
    "position",
    new THREE.BufferAttribute(new Float32Array(faceList), 3)
  );
  geometryWall.setAttribute(
    "uv",
    new THREE.BufferAttribute(new Float32Array(uvList), 2)
  );
  // 计算法向量
  geometryWall.computeVertexNormals();
  geometryWall.computeBoundingBox();
  const max = geometryWall.boundingBox.max;
  const min = geometryWall.boundingBox.min;
  console.log("max-min:", max, min);
  texture = new THREE.TextureLoader().load(
    "./textures/linearGradient1.png"
  );
  //  texture = generateTexture(128, "#FFD500");
  texture.wrapS = THREE.RepeatWrapping;
  texture.wrapT = THREE.RepeatWrapping;
  const materialWall = new THREE.MeshBasicMaterial({
    color: "#0088ff",
    transparent: true,
    opacity:0.9,
    depthTest: false,
    side: THREE.DoubleSide,
    // map: texture,
  });
  const meshWall = new THREE.Mesh(geometryWall, materialWall);
  meshWall.scale.set(5,5,1)
  meshWall.rotation.x = Math.PI *0.8 
  meshWall.updateMatrix() 
  scene.add(meshWall);
  // 设置 uv贴图
});
renderer.render(scene, camera); //执行渲染操作
// 需要这个,要不坐标系 不显示
const controls = new OrbitControls(camera, renderer.domElement);
function render() {
  renderer.render(scene, camera);
  requestAnimationFrame(render); 
}
render();
效果:
 












![[2024-06]-[大模型]-[Ollama]- WebUI](https://img-blog.csdnimg.cn/direct/15d9c2968c26446aa797d52ae1e4a66d.png)






