坐标映射实现物体颜色动态渲染
要运用Cesium.Cartesian3改变物体渲染颜色一个直接且常见的应用是将其分量X, Y, Z映射到颜色空间如RGB从而创建基于空间位置或数据值的可视化效果。虽然Cesium.Cartesian3本身不直接存储颜色信息但其数值可以作为驱动颜色变化的参数。一、核心原理从坐标到颜色的映射Cesium.Cartesian3的x,y,z属性通常是空间坐标或向量分量。我们可以通过归一化、线性插值或自定义函数将这些标量值映射到Cesium.Color的red,green,blue或alpha通道。1. 基础映射方法/** * 将 Cartesian3 的位置坐标映射为 RGB 颜色。 * 假设坐标值在已知的[min, max]范围内。 * param {Cesium.Cartesian3} position - 输入坐标 * param {Cesium.Cartesian3} minBounds - 坐标最小值 (xMin, yMin, zMin) * param {Cesium.Cartesian3} maxBounds - 坐标最大值 (xMax, yMax, zMax) * returns {Cesium.Color} - 映射后的颜色 */ function positionToColor(position, minBounds, maxBounds) { // 将每个分量归一化到 [0, 1] 区间 const normalize (value, min, max) (value - min) / (max - min); const r normalize(position.x, minBounds.x, maxBounds.x); const g normalize(position.y, minBounds.y, maxBounds.y); const b normalize(position.z, minBounds.z, maxBounds.z); // 创建颜色确保值在 [0, 1] 之间 return new Cesium.Color( Cesium.Math.clamp(r, 0.0, 1.0), Cesium.Math.clamp(g, 0.0, 1.0), Cesium.Math.clamp(b, 0.0, 1.0), 1.0 // 不透明度 ); } // 使用示例假设点云坐标范围在 (0,0,0) 到 (100,100,100) 之间 const pointPosition new Cesium.Cartesian3(30, 60, 90); const min new Cesium.Cartesian3(0, 0, 0); const max new Cesium.Cartesian3(100, 100, 100); const pointColor positionToColor(pointPosition, min, max); // 结果pointColor 近似为 RGB(0.3, 0.6, 0.9)2. 基于高度Z值的渐变色映射这是地形或模型高程着色的典型应用。/** * 根据高度Z值生成热力渐变色如低-蓝中-绿高-红 * param {Cesium.Cartesian3} position - 输入坐标 * param {Number} minHeight - 最小高度 * param {Number} maxHeight - 最大高度 * returns {Cesium.Color} */ function heightToColor(position, minHeight, maxHeight) { const height position.z; const normalizedHeight (height - minHeight) / (maxHeight - minHeight); const clampedHeight Cesium.Math.clamp(normalizedHeight, 0.0, 1.0); // 定义渐变颜色控制点 const colors [ { stop: 0.0, color: Cesium.Color.BLUE }, // 低处为蓝 { stop: 0.5, color: Cesium.Color.GREEN }, // 中间为绿 { stop: 1.0, color: Cesium.Color.RED } // 高处为红 ]; // 找到对应的颜色区间 for (let i 1; i colors.length; i) { if (clampedHeight colors[i].stop) { const prev colors[i - 1]; const curr colors[i]; const t (clampedHeight - prev.stop) / (curr.stop - prev.stop); // 线性插值颜色 return Cesium.Color.fromBytes( Cesium.Math.lerp(prev.color.red * 255, curr.color.red * 255, t), Cesium.Math.lerp(prev.color.green * 255, curr.color.green * 255, t), Cesium.Math.lerp(prev.color.blue * 255, curr.color.blue * 255, t), 255 ); } } return Cesium.Color.WHITE; } // 为地形图层设置基于高度的材质 const viewer new Cesium.Viewer(cesiumContainer); viewer.terrainProvider Cesium.createWorldTerrain(); const terrainMaterial new Cesium.Material({ fabric: { type: Color, uniforms: { color: new Cesium.Color(1.0, 1.0, 1.0, 1.0) }, source: // 在着色器中可以通过 positionMC模型坐标获取高度 czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material czm_getDefaultMaterial(materialInput); // 这里可以基于 materialInput.positionMC.z 计算颜色 // 实际实现会更复杂需要传递minHeight/maxHeight等uniforms material.diffuse color.rgb; return material; } } }); //二、动态改变实体颜色的实现1. 为 Primitive 设置逐顶点颜色对于自定义Geometry可以直接在几何属性中包含颜色信息。// 创建一组带颜色的点 const positions []; const colors []; const min new Cesium.Cartesian3(-100000, -100000, 0); const max new Cesium.Cartesian3(100000, 100000, 50000); // 生成100个随机点 for (let i 0; i 100; i) { const x Cesium.Math.randomBetween(min.x, max.x); const y Cesium.Math.randomBetween(min.y, max.y); const z Cesium.Math.randomBetween(min.z, max.z); const position new Cesium.Cartesian3(x, y, z); positions.push(x, y, z); // 基于位置计算颜色 const color positionToColor(position, min, max); colors.push(color.red, color.green, color.blue, color.alpha); // RGBA } const pointPrimitive viewer.scene.primitives.add(new Cesium.PointPrimitiveCollection()); // 为每个点创建独立的Primitive颜色固定 positions.forEach((pos, index) { const position Cesium.Cartesian3.fromArray(positions, index * 3); const color Cesium.Color.fromBytes( colors[index * 4] * 255, colors[index * 4 1] * 255, colors[index * 4 2] * 255, colors[index * 4 3] * 255 ); pointPrimitive.add({ position: position, color: color, pixelSize: 10 }); }); //2. 使用 Property API 动态更新 Entity 颜色对于会随时间或交互变化的颜色可以使用Cesium.CallbackProperty。// 创建一个实体其颜色随位置动态变化 const dynamicEntity viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 1000), ellipse: { semiMajorAxis: 500.0, semiMinorAxis: 500.0, height: 0, material: new Cesium.ColorMaterialProperty( // 使用回调属性每次渲染时重新计算颜色 new Cesium.CallbackProperty(function(time, result) { const position dynamicEntity.position.getValue(time); // 基于X坐标的正弦波变化颜色 const r (Math.sin(position.x / 10000) 1) / 2; // 红色分量 [0,1] const g (Math.cos(position.y / 10000) 1) / 2; // 绿色分量 [0,1] const b 0.5; // 固定蓝色分量 if (!result) { result new Cesium.Color(); } return Cesium.Color.fromRandom({ red: r, green: g, blue: b, alpha: 1.0 }, result); }, false) // false 表示每次请求都计算true 表示缓存 ) } }); // 让实体动起来观察颜色变化 dynamicEntity.position new Cesium.CallbackProperty(function(time) { const start Cesium.JulianDate.now(); const seconds Cesium.JulianDate.secondsDifference(time, start); return Cesium.Cartesian3.fromDegrees( -75.59777 Math.sin(seconds * 0.1) * 0.01, // 经度微动 40.03883, 1000 Math.sin(seconds * 0.5) * 500 // 高度波动 ); }, false); //三、高级应用基于向量场的方向着色当Cartesian3表示向量如速度、法线、梯度而非位置时可以将其方向映射为颜色。1. 法线向量可视化/** * 将单位法线向量映射为RGB颜色常用于显示模型法线 * param {Cesium.Cartesian3} normal - 单位法线向量 * returns {Cesium.Color} */ function normalToColor(normal) { // 法线分量范围是[-1, 1]映射到[0, 1]用于颜色 const r (normal.x 1) / 2; const g (normal.y 1) / 2; const b (normal.z 1) / 2; return new Cesium.Color(r, g, b, 1.0); } // 为模型应用法线着色材质 const modelEntity viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-75.628982543, 40.0280494682, 100), model: { uri: ./models/CesiumAir/Cesium_Air.glb, minimumPixelSize: 128, maximumScale: 20000, color: new Cesium.CallbackProperty(function(time, result) { // 这里简化实际应用中需要从模型的顶点法线计算 // 假设有一个随时间变化的伪法线 const seconds Cesium.JulianDate.toDate(time).getTime() / 1000; const pseudoNormal new Cesium.Cartesian3( Math.sin(seconds * 0.5), Math.cos(seconds * 0.3), Math.sin(seconds * 0.7) ); Cesium.Cartesian3.normalize(pseudoNormal, pseudoNormal); return normalToColor(pseudoNormal); }, false) } }); //2. 速度场着色// 创建表示速度向量的箭头图 const velocityVectors []; const startPos Cesium.Cartesian3.fromDegrees(-75.6, 40.0, 0); for (let i 0; i 10; i) { for (let j 0; j 10; j) { const position Cesium.Cartesian3.fromDegrees( -75.6 i * 0.01, 40.0 j * 0.01, 0 ); // 模拟一个涡旋速度场 const dx position.y - startPos.y; const dy -(position.x - startPos.x); const velocity new Cesium.Cartesian3(dx * 100, dy * 100, 0); // 速度大小决定颜色强度 const speed Cesium.Cartesian3.magnitude(velocity); const maxSpeed 50000; const intensity Cesium.Math.clamp(speed / maxSpeed, 0, 1); // 速度方向决定色相 const direction new Cesium.Cartesian3(); Cesium.Cartesian3.normalize(velocity, direction); const hue Math.atan2(direction.y, direction.x) / (2 * Math.PI); // [-π,π] - [-0.5,0.5] viewer.entities.add({ position: position, polyline: { positions: [position, Cesium.Cartesian3.add(position, velocity, new Cesium.Cartesian3())], width: 3, material: Cesium.Color.fromHsl( (hue 1) % 1, // 归一化到 [0,1) 1.0, // 饱和度 0.5 * intensity 0.3, // 明度随强度变化 1.0 ) } }); } } //四、性能优化与最佳实践场景推荐方法说明静态颜色直接设置material.color最简单的固定颜色基于位置的动态色CallbackProperty 映射函数适合移动实体但频繁计算可能影响性能大量点云着色Geometry顶点颜色属性GPU加速性能最佳但需要预计算实时数据流ColorMaterialProperty 自定义着色器最灵活性能好但实现复杂着色器示例GLSL对于最高性能的场景可以编写自定义材质着色器。const customMaterial new Cesium.Material({ fabric: { type: PositionToColor, uniforms: { minBounds: new Cesium.Cartesian3(-100, -100, 0), maxBounds: new Cesium.Cartesian3(100, 100, 100) }, source: // 在顶点着色器中传递位置 varying vec3 v_position; void vertex() { v_position (czm_model * vec4(position, 1.0)).xyz; } // 在片元着色器中计算颜色 czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material czm_getDefaultMaterial(materialInput); // 从uniforms获取边界 vec3 minBounds vec3(uniforms.minBounds); vec3 maxBounds vec3(uniforms.maxBounds); // 归一化位置 vec3 normalizedPos (v_position - minBounds) / (maxBounds - minBounds); normalizedPos clamp(normalizedPos, 0.0, 1.0); // 直接使用归一化位置作为RGB material.diffuse normalizedPos; material.alpha 1.0; return material; } } }); // 应用到primitive const primitive new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: /* 你的几何体 */, attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE) } }), appearance: new Cesium.MaterialAppearance({ material: customMaterial, translucent: false }) }); //五、OpenClaw抓取仿真中的颜色应用在机器人抓取仿真中颜色常用于视觉反馈例如// 示例根据抓取器与目标的距离改变目标颜色 function updateTargetColorBasedOnDistance(gripperPos, targetPos, targetEntity) { const distance Cesium.Cartesian3.distance(gripperPos, targetPos); const maxDistance 5.0; // 最大有效距离 // 距离越近颜色越红警示 const intensity Cesium.Math.clamp(1.0 - distance / maxDistance, 0, 1); const color Cesium.Color.fromHsl(0.0, 1.0, 0.5 * intensity 0.3, 1.0); // 红色系 targetEntity.ellipse.material new Cesium.ColorMaterialProperty(color); // 或者基于抓取力度假设force是Cartesian3表示的力向量 const forceMagnitude Cesium.Cartesian3.magnitude(forceVector); const maxForce 100.0; const forceIntensity Cesium.Math.clamp(forceMagnitude / maxForce, 0, 1); // 力度越大颜色越偏向黄色警告 const forceColor Cesium.Color.fromHsl(forceIntensity * 0.15, 1.0, 0.5, 1.0); // 红-橙-黄 } //通过将Cesium.Cartesian3的空间信息映射到颜色空间可以实现丰富的数据可视化效果从简单的高度着色到复杂的向量场可视化。关键在于设计合适的映射函数并根据性能需求选择正确的实现方式Property API、Geometry属性或自定义着色器。参考来源快速验证OpenClaw抓取模型在快马平台5分钟搭建3D配置原型快速验证机器人抓取逻辑在快马平台用AI十分钟搭建OpenClaw101仿真原型快速验证机器人抓取逻辑用快马AI一键生成OpenClaw Skill交互原型利用快马平台快速构建OpenClaw中文版机器人抓取仿真原型AI数字劳工从多模态Agent到可执行工作流的工程实践51c大模型~合集111