# 在cesiumjs中实现真实草地渲染
6 min read
Table of Contents
草地配置
首先我们要完成草地的主要参数的配置,这里使用ts的interface来定义草地的相关参数
export interface GrassConfig { density: number //草地密度 windStrength: number //风力强度 primaryColor: string //草地主色调 secondaryColor: string //草地次色调 shadowIntensity: number //阴影强度 bounds: { west: number south: number east: number north: number } //草地范围 polygon?: Cesium.Cartesian3[] //添加多边形边界支持 enableLOD?: boolean //是否启用LOD优化 lodDistances?: { high: number //高细节距离阈值 medium: number //中细节距离阈值 low: number //低细节距离阈值 } //LOD距离阈值 //高级控制参数 bladeWidth?: number //草叶宽度 bladeHeight?: number //草叶高度 joints?: number //草叶关节数 windSpeed?: number //风速 windIntensity?: number //风强度 stretchVariation?: number //草叶拉伸变化度 maxLeanAngle?: number //最大倾斜角度(度数) leanVariation?: number //倾斜变化度 windDirection?: number //风向(度数 0=北 90=东 180=南 270=西) windAngle?: number //风倾斜角度}草实体配置
接下来我们要进行草实例的配置
export interface GrassInstance { position: Cesium.Cartesian3 //草实例的位置 scale: number //草实例的缩放比例 rotation: number //草实例的旋转角度 width: number //草实例的宽度 lean: number //倾斜角度 orientation: Cesium.Quaternion //四元数生长方向 stretch: number //拉伸系数 halfRootAngleSin: number //根部角度正弦值 halfRootAngleCos: number //根部角度余弦值}工具函数实现
然后我们需要实现一些工具函数来辅助草地的生成和渲染
四元数相乘
如果有不理解的地方,可以参考我之前写的四元数乘法的数学原理及其在3D图形中的应用
// 四元数乘法函数,在这个草地渲染系统中,四元数用于表示3D空间中的旋转。函数通过标准的四元数乘法公式组合两个旋转,生成一个新的四元数,表示先应用第一个旋转再应用第二个旋转的结果。这对于计算草叶在风中摆动时的旋转非常重要。/*在本实现中主要用于1. 组合多个旋转方向 - 将绕Y轴的旋转与绕X轴的旋转组合2. 添加细微变化 - 再叠加Z轴的微小旋转,使每片草叶的方向更自然、更随机*/function multiplyQuaternions( q1: Cesium.Quaternion, q2: Cesium.Quaternion,): Cesium.Quaternion { const x = q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x const y = -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y const z = q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z const w = -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w return new Cesium.Quaternion(x, y, z, w)}Simplex噪声实现
Simplex噪声是一种用于生成自然现象的程序化噪声函数,常用于计算机图形学中以模拟自然界中的纹理和形态
function createNoise2D() { return function (x: number, y: number): number { const n0 = Math.sin(x * 12.9898 + y * 78.233) * 43758.5453123 return (n0 - Math.floor(n0)) * 2.0 - 1.0 }}
const noise2D = createNoise2D()检测点是否在多边形内
该函数使用了射线投射算法,主要用于检测一个点是否在一个多边形内,常用于地图应用中判断某个位置是否在指定区域内
/** * 检测点是否在多边形内部 - 使用射线投射算法 */function isPointInPolygon( point: { longitude: number; latitude: number }, polygon: Cesium.Cartesian3[],): boolean { if (!polygon || polygon.length < 3) return true // 如果没有多边形,默认在内部
// 将Cartesian3多边形点转换为经纬度 const polygonPoints: { longitude: number; latitude: number }[] = []
for (let i = 0; i < polygon.length; i++) { const cartographic = Cesium.Cartographic.fromCartesian(polygon[i]) polygonPoints.push({ longitude: Cesium.Math.toDegrees(cartographic.longitude), latitude: Cesium.Math.toDegrees(cartographic.latitude), }) }
let inside = false const x = point.longitude const y = point.latitude
for (let i = 0, j = polygonPoints.length - 1; i < polygonPoints.length; j = i++) { const xi = polygonPoints[i].longitude const yi = polygonPoints[i].latitude const xj = polygonPoints[j].longitude const yj = polygonPoints[j].latitude
if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) { inside = !inside } }
return inside}