城市边界电子围栏
初始化摄像头、灯光等
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();
效果: