3D区块渐变围栏

news/2024/11/8 4:04:13/

3dfefc9d5442cd907c422a1ef91f4e.png" width="1200" />

这里主要用到的就是threejs的shader,至于其他知识点,可以参考json绘制3d地区 

下面的主要代码:

javascript">import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import * as d3geo from 'd3-geo'
import guangzhouJSON from '../assets/json/guangzhou.json'export default (domId) => {/* ------------------------------初始化三件套--------------------------------- */const dom = document.getElementById(domId);const { innerHeight, innerWidth } = windowconst scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 2000);camera.position.set(0, 0, 10);camera.lookAt(scene.position);const renderer = new THREE.WebGLRenderer({antialias: true,// 抗锯齿alpha: false,// 透明度powerPreference: 'high-performance',// 性能logarithmicDepthBuffer: true,// 深度缓冲})// renderer.setClearColor(0x000000, 0);// 设置背景色// renderer.clear();// 清除渲染器renderer.shadowMap.enabled = true;// 开启阴影renderer.shadowMap.type = THREE.PCFSoftShadowMap;// 阴影类型renderer.outputEncoding = THREE.sRGBEncoding;// 输出编码renderer.toneMapping = THREE.ACESFilmicToneMapping;// 色调映射renderer.toneMappingExposure = 1;// 色调映射曝光renderer.physicallyCorrectLights = true;// 物理正确灯光renderer.setPixelRatio(devicePixelRatio);// 设置像素比renderer.setSize(innerWidth, innerHeight);// 设置渲染器大小dom.appendChild(renderer.domElement);// 重置大小window.addEventListener('resize', () => {const { innerHeight, innerWidth } = windowcamera.aspect = innerWidth / innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth, innerHeight);})/* ------------------------------初始化工具--------------------------------- */const controls = new OrbitControls(camera, renderer.domElement) // 相机轨道控制器controls.enableDamping = true // 是否开启阻尼controls.dampingFactor = 0.05// 阻尼系数controls.panSpeed = -1// 平移速度// const axesHelper = new THREE.AxesHelper(10);// scene.add(axesHelper);/* ------------------------------正题--------------------------------- */// 相机控制器配置const cameraControl = {autoCamera: true,// 是否自动旋转height: 10,// 相机高度width: 0.5,// 相机宽度depth: 1,// 相机深度cameraPosX: 10,// 相机位置xcameraPosY: 181,// 相机位置ycameraPosZ: 116,// 相机位置zautoRotate: false,// 是否自动旋转rotateSpeed: 2000// 旋转速度}let geoFun;// 地理投影函数let guangzhouData = [];// 地图数据let shape = null;// 地图形状const group = new THREE.Group();// 初始化地理投影const initGeo = (size) => {geoFun = d3geo.geoMercator().scale(size || 100)}// 经纬度转像素坐标const latlng2px = (pos) => {if (pos[0] >= -180 && pos[0] <= 180 && pos[1] >= -90 && pos[1] <= 90) {return geoFun(pos);}return pos;};// 处理地图数据const processData = () => {guangzhouData = guangzhouJSON.features[0].geometry.coordinates[0][0];// 数据 从 经纬度-> 像素坐标-> 三维坐标guangzhouData = guangzhouData.map(item => {const two = latlng2px(item);const three = new THREE.Vector3(two[0], 0, two[1]);return three;})}// 创建地图块const createMap = () => {const extrudeSettings = {depth: 0.2,// 区块厚度bevelEnabled: false// 是否使用倒角};shape = new THREE.Shape();shape.moveTo(guangzhouData[0].x, guangzhouData[0].z);// 移动到第一个点for (let i = 1; i < guangzhouData.length; i++) {shape.lineTo(guangzhouData[i].x, guangzhouData[i].z);// 连线}shape.lineTo(guangzhouData[0].x, guangzhouData[0].z);// 闭合const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);const img = new URL('../assets/images/tex.png', import.meta.url).href;const text = new THREE.TextureLoader().load(img);text.wrapS = THREE.RepeatWrapping;// 水平方向text.wrapT = THREE.RepeatWrapping;// 垂直方向const material = new THREE.MeshBasicMaterial({map: text,color: new THREE.Color('#00FFFF')})const mesh = new THREE.Mesh(geometry, material);mesh.rotateX(Math.PI / 2);// 旋转90度mesh.position.y = extrudeSettings.depth * 0.5;group.add(mesh);}// 创建边缘线const createEdge = () => {const material = new THREE.ShaderMaterial({side: THREE.DoubleSide,// 双面transparent: true,// 透明depthTest: false,// 不检测深度uniforms: {color1: { value: new THREE.Color('#00FFFF') }},vertexShader: ` varying vec2 vUv;// 纹理坐标varying vec3 vNormal;// 法线void main() {vUv=uv;vNormal=normal;           gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}`,fragmentShader: `uniform vec3 color1;                varying vec2 vUv; varying vec3 vNormal;void main() {if(vNormal.z==1.0||vNormal.z==-1.0||vUv.y ==0.0){discard;}else{gl_FragColor =vec4(color1,mix(1.0,0.0, vUv.y)) ;} }`});const extrudeSettings = {depth: 1,// 厚度bevelEnabled: false// 是否使用倒角};const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);const mesh = new THREE.Mesh(geometry, material);mesh.rotation.x = Math.PI * 0.5;mesh.position.y = extrudeSettings.depth + 0.1;group.add(mesh);}// 设置模型的中心点const setModeCenter = (object, viewControl) => {// 如果对象不存在,则返回   if (!object) {return;}if (object.updateMatrixWorld) {object.updateMatrixWorld();// 更新模型矩阵}// 获得包围盒得min和maxlet box = new THREE.Box3().setFromObject(object);let objSize;// 获取包围盒的尺寸try {objSize = box.getSize();} catch (error) {objSize = new THREE.Vector3(Math.abs(box.max.x - box.min.x),Math.abs(box.max.y - box.min.y),Math.abs(box.max.z - box.min.z));}// 返回包围盒的中心点const center = box.getCenter(new THREE.Vector3());object.position.x += object.position.x - center.x;object.position.y += object.position.y - center.y;object.position.z += object.position.z - center.z;let width = objSize.x;let height = objSize.y;let depth = objSize.z;// 设置相机位置let centroid = new THREE.Vector3().copy(objSize);centroid.multiplyScalar(0.5);if (viewControl.autoCamera) {camera.position.x =centroid.x * (viewControl.centerX || 0) + width * (viewControl.width || 0);camera.position.y =centroid.y * (viewControl.centerY || 0) + height * (viewControl.height || 0);camera.position.z =centroid.z * (viewControl.centerZ || 0) + depth * (viewControl.depth || 0);} else {camera.position.set(viewControl.cameraPosX || 0,viewControl.cameraPosY || 0,viewControl.cameraPosZ || 0);}camera.lookAt(0, 0, 0);}// 初始化const init = () => {initGeo(180)// 初始化地理投影processData()// 处理地图数据createMap()// 创建地图块createEdge()// 创建边缘线scene.add(group);// 添加到场景中setModeCenter(group, cameraControl)// 设置模型的中心点}init();/* ------------------------------动画函数--------------------------------- */const animation = () => {controls.update();// 如果不调用,就会很卡// animationRender()renderer.render(scene, camera);requestAnimationFrame(animation);}animation();
}

 


http://www.ppmy.cn/news/1545248.html

相关文章

深入理解 lsof:Linux 系统中的文件打开状态洞察者

在 Linux 系统管理和故障排除中&#xff0c;lsof 命令是一个强大的工具&#xff0c;它能够列出系统中所有打开的文件以及与之相关的进程信息。本文将深入探讨 lsof 命令的各个方面&#xff0c;包括其功能、用法、示例、注意事项以及与其他工具的配合使用。 一、lsof 简介 lso…

ubuntu 异常 断电 日志 查看

sudo less /var/log/syslog 搜 Linux version

Java8新特性/java

1.lambda表达式 区别于js的箭头函数&#xff0c;python、cpp的lambda表达式&#xff0c;java8的lambda是一个匿名函数&#xff0c;java8运行把函数作为参数传递进方法中。 语法格式 (parameters) -> expression 或 (parameters...) ->{ statements; }实战 替代匿名内部类…

MySQL 批量删除海量数据的几种方法

目录 一、问题分析 二、批量删除海量数据的几种方法 方法 1&#xff1a;使用 LIMIT 分批删除 方法 2&#xff1a;通过主键范围分批删除 方法 3&#xff1a;通过自定义批量删除存储过程 方法 4&#xff1a;创建临时表替换旧表 三、性能优化建议 总结 在数据库的日常维护…

用图说明 CPU、MCU、MPU、SoC 的区别

CPU CPU 负责执行构成计算机程序的指令&#xff0c;执行这些指令所指定的算术、逻辑、控制和输入/输出&#xff08;I/O&#xff09;操作。 MCU (microcontroller unit) 不同的 MCU 架构如下&#xff0c;注意这里的 MPU 表示 memory protection unit MPU (microprocessor un…

鸿蒙进阶篇-网格布局 Grid/GridItem(二)

hello大家好&#xff0c;这里是鸿蒙开天组&#xff0c;今天让我们来继续学习鸿蒙进阶篇-网格布局 Grid/GridItem&#xff0c;上一篇博文我们已经学习了固定行列、合并行列和设置滚动&#xff0c;这一篇我们将继续学习Grid的用法&#xff0c;实现翻页滚动、自定义滚动条样式&…

配置文件中spring.main.allow-bean-definition-overriding属性

spring.main.allow-bean-definition-overriding属性是SpringBoot应用中的一个关键配置&#xff0c;它决定了是否允许在Spring容器中存在名称相同的Bean定义覆盖。以下是对该属性的详细介绍&#xff1a; 一、属性作用 • 控制Bean定义覆盖&#xff1a;当多个配置类或组件定义了…

OpenResty 1.27.1.1 已经正式发布

OpenResty 1.27.1.1 已经正式发布&#xff0c;这是一个基于 NGINX 和 LuaJIT 的 web 平台。以下是关于此次发布的一些重点信息和更新内容&#xff1a; 下载与安装 你可以在此处下载最新版本的 OpenResty。提供了便携式源代码分发、Win32/Win64 二进制分发以及为 Ubuntu、Debi…