news 2026/7/5 11:20:24

Three.js 城市线条教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Three.js 城市线条教程

城市线条 ·City Line· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • ShaderMaterial 自定义着色器实现核心视觉效果
  • OrbitControls 相机轨道交互
  • FBXLoader 加载 FBX 城市/角色模型
  • EdgesGeometry 模型边线提取
  • requestAnimationFrame渲染循环与resize自适应

效果说明

本案例演示城市线条效果:基于 WebGL 实现「城市线条」可视化效果,附完整可运行源码;核心用到 ShaderMaterial、OrbitControls、FBXLoader。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • Scene / Camera / WebGLRenderer构成最小渲染闭环;大场景可开logarithmicDepthBuffer缓解 Z-fighting。
  • ShaderMaterial通过uniforms+ 自定义 GLSL 控制逐像素/逐点效果;透明粒子常配合depthTest: false
  • OrbitControls提供轨道旋转/缩放;开启enableDamping后需在 animate 中controls.update()

实现步骤

  • 搭建 Scene、PerspectiveCamera、WebGLRenderer,挂载 canvas 并处理resize
  • 异步加载模型 / 3D Tiles / GeoJSON 等资源并加入 scene 或 entities
  • 定义 uniforms / onBeforeCompile 或 ShaderMaterial,编写 GLSL 与材质参数
  • 创建 OrbitControls(及 Raycaster 等交互控件,若源码包含)
  • requestAnimationFrame循环中更新状态并 render(Cesium 为viewer.render或自动渲染)
  • 代码要点

    import * as THREE from 'three'

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'

    class City {

    constructor() { this.fbxLoader = new FBXLoader(); this.group = new THREE.Group(); this.clock = new THREE.Clock() this.surroundLineMaterial = null;// 定义包围线材质属性 this.time = { value: 0 }; this.startTime = { value: 0 }; this.startLength = { value: 2 } this.isStart = false;

    this.fbxLoader.load(FILE_HOST + 'models/fbx/shanghai.FBX', (group) => {

    this.group.add(group); group.traverse((child) => { // 设置城市建筑(mesh物体),材质基本颜色 if (child.name == 'CITY_UNTRIANGULATED') { const materials = Array.isArray(child.material) ? child.material : [child.material] materials.forEach((material) => { material.transparent = true; material.color.setStyle("#9370DB"); }) }

    // 设置城市地面(mesh物体),材质基本颜色 if (child.name == 'LANDMASS') { const materials = Array.isArray(child.material) ? child.material : [child.material] materials.forEach((material) => { material.transparent = true; material.color.setStyle("#040912"); }) } })

    this.init(); }); }

    // 初始化城市类的实例 init() { this.isStart = true; // 城市渲染启动 this.clock.start() this.surroundLine(); }

    // 创建包围线条效果 surroundLine() { let cityBuildings // 城市建筑群 this.group.traverse(child => { if (child.name !== 'CITY_UNTRIANGULATED') return cityBuildings = child })

    const geometry = new THREE.EdgesGeometry(cityBuildings.geometry); const surroundLineMaterial = new THREE.ShaderMaterial({ transparent: true, uniforms: { uColor: { value: new THREE.Color('#FFF') } }, vertexShader:void main() { gl_Position = projectionMatrixmodelViewMatrixvec4(position, 1.0); }, fragmentShader:uniform vec3 uColor; void main() { gl_FragColor = vec4(uColor, 1); }});

    const line = new THREE.LineSegments(geometry, surroundLineMaterial); line.name = 'surroundLine'; line.applyMatrix4(cityBuildings.matrix.clone()) cityBuildings.parent.add(line) }

    updateData = () => { if (!this.isStart) return false; const dt = this.clock.getDelta(); this.time.value += dt; this.startTime.value += dt; if (this.startTime.value >= this.startLength.value) { this.startTime.value = this.startLength.value; } } }

    const box = document.getElementById('box')

    const scene = new THREE.Scene()

    const camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 1000000) camera.position.set(600, 750, -1221)

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }) renderer.setSize(box.clientWidth, box.clientHeight) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setClearColor(new THREE.Color('#32373E'), 1);

    const controls = new OrbitControls(camera, renderer.domElement) controls.enableDamping = true

    window.onresize = () => { renderer.setSize(box.clientWidth, box.clientHeight) camera.aspect = box.clientWidth / box.clientHeight camera.updateProjectionMatrix() }

    box.appendChild(renderer.domElement)

    // 坐标轴 scene.add(new THREE.AxesHelper(100000)) const light = new THREE.AmbientLight(0xadadad, 3); // 环境光,soft white light const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5); // 方向光 directionalLight.position.set(100, 100, 0); scene.add(light); scene.add(directionalLight);

    // 实例化 const city = new City({}); scene.add(city.group);

    // 渲染 animate() function animate() { city.updateData(); controls.update() renderer.render(scene, camera) requestAnimationFrame(animate) }

    完整源码:GitHub

    小结

    • 本文提供城市线条完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 11:19:33

Python实现协同过滤理财推荐系统架构与优化

1. 项目背景与核心价值理财推荐系统是金融科技领域的热门应用方向。传统金融机构在向客户推荐理财产品时,往往面临两个痛点:一是人工推荐效率低下,难以覆盖海量客户;二是标准化推荐缺乏个性化,难以匹配客户真实需求。基…

作者头像 李华
网站建设 2026/7/5 11:16:44

从零构建智能AI助手:Hermes Agent核心架构与自动化实战

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 如果你正在寻找一个能真正理解你、能持续学习、能帮你处理日常开发任务的 AI 助手,而不是一个只会回答单次问题的聊天机器…

作者头像 李华
网站建设 2026/7/5 11:14:56

MAA明日方舟助手:5个核心功能让你彻底告别重复操作

MAA明日方舟助手:5个核心功能让你彻底告别重复操作 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/7/5 11:14:16

AI工程师转型:从算法调优到工程落地,普通人如何抓住新红利

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 最近和几个做技术招聘的朋友聊天,话题总绕不开一个现象:前两年还炙手可热的“AI算法工程师”岗位,…

作者头像 李华
网站建设 2026/7/5 11:13:51

AI Agent平台架构:从设计到实现的企业级智能系统构建指南

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 这次我们来看一个在技术面试中高频出现、也是当前企业级AI应用落地的核心议题:AI Agent平台架构。如果你正在准备大厂面试…

作者头像 李华