使用热力贴图和高斯函数生成山峰与等高线的 WebGL Shader 解析

在 WebGL 或 Three.js 中,我们可以通过顶点着色器和片元着色器结合热力贴图或高斯函数 ,实现山峰高度生成等高线/渐变色渲染。本文将详细解析这一过程,并给出实际示例代码。


1️⃣ 顶点着色器:热力贴图或高斯函数驱动顶点高度

顶点着色器的核心目标是根据热力贴图或数学函数计算每个顶点的高度,从而形成山峰。

热力贴图驱动示例

ini 复制代码
// 热力贴图
uniform sampler2D map;
// 山丘最大高度
uniform float uHeight;
// 等高线宽度(可用于片元着色器)
uniform float uMinLne;
// 热力信息:x = 偏移, z = 缩放, w = 等高线间隔
uniform vec4 uInfo;

// 传递给片元着色器的变量
varying vec4 vColor;
varying float val;

void main(void) {
    // 1. 读取热力贴图颜色
    vec4 color = texture2D(map, uv);
    vColor = color;

    // 2. 获取透明度 a(0~1),作为热力值基础
    float a = color.a;
    
    // 如果只是想简单的实现等高可以通过 color.a * vHeight 山峰的最高值,来实现顶点计算

    // 3. 还原实际热力值 v
    float v = a * uInfo.z + uInfo.x;

    // 4. 传递热力值给片元着色器
    val = v;

    // 5. 对热力值进行等高线离散化
    float f = (floor(v / uInfo.w) * uInfo.w - uInfo.x) / uInfo.z;

    // 6. 计算顶点高度
    float h = f * uHeight;

    // 7. 输出顶点位置
    // vec4(position.x, position.y, h, 1.0) → 模型空间顶点位置
    // modelViewMatrix → 模型空间 → 视图空间
    // projectionMatrix → 视图空间 → 裁剪空间 / 屏幕空间
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, h, 1.0);
}

高斯函数多层山峰示例(五层)

ini 复制代码
// 4. 创建地形 做为渲染山峰的顶点(这里介绍一个观点,顶点着色器会将这里的平面中的每一个点进行顶点计算,通过这个原理就可以理解为什么会形成山峰)
const geometry = new THREE.PlaneGeometry(10, 10, 100, 100);
// 将平面垂直,使得山峰可见
geometry.rotateX(-Math.PI / 2);
  
const material = new THREE.ShaderMaterial({
// 这个是顶点着色器用来渲染所有的顶点位置
  vertexShader: `
    varying float vHeight;

    void main() {
      float dist = length(position.xz); // 到中心的距离

      // 五层高斯函数(衰减系数逐渐增大)
      float h1 = exp(-dist * dist * 0.05);
      float h2 = exp(-dist * dist * 0.08);
      float h3 = exp(-dist * dist * 0.11);
      float h4 = exp(-dist * dist * 0.14);
      float h5 = exp(-dist * dist * 0.18);

      // 平均层高度
      float height = 0.5*h1 + 0.5*h2 + 0.5*h3 + 0.5*h4 + 0.5*h5;

      vec3 newPos = position + vec3(0.0, height * 3.0, 0.0);
      vHeight = height;
      
        // 如果想 把顶点渲染到屏幕上,必须乘上 projectionMatrix:否则可以不乘  modelViewMatrix → 把模型空间坐标转到相机视角  vec4(position.x, position.y, h, 1.0) 决定顶点位置
      gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);
    }
  `,
  // 片元着色器用来渲染图形的颜色
  fragmentShader: `
    varying float vHeight;

    void main() {
      // 五层颜色(平滑过渡)
      vec3 c1 = vec3(0.2, 0.5, 0.2);
      vec3 c2 = vec3(0.3, 0.6, 0.3);
      vec3 c3 = vec3(0.5, 0.5, 0.3);
      vec3 c4 = vec3(0.7, 0.6, 0.4);
      vec3 c5 = vec3(0.9, 0.9, 0.9);

      vec3 color;
      if (vHeight < 0.2) {
        color = mix(c1, c2, smoothstep(0.0, 0.2, vHeight));
      } else if (vHeight < 0.4) {
        color = mix(c2, c3, smoothstep(0.2, 0.4, vHeight));
      } else if (vHeight < 0.6) {
        color = mix(c3, c4, smoothstep(0.4, 0.6, vHeight));
      } else {
        color = mix(c4, c5, smoothstep(0.6, 1.0, vHeight));
      }

      gl_FragColor = vec4(color, 1.0);
    }
  `,
});

🔑 核心原理

  1. 多层高斯函数

    • 五层高斯函数叠加,形成平缓底层和尖锐顶层
    • 平均高度权重避免底层过高、顶层过尖
  2. 渐变颜色映射

    • 根据顶点高度 vHeight 映射颜色
    • 使用 mixsmoothstep 生成平滑过渡的山脊色彩

2️⃣ 片元着色器:渲染等高线与颜色

热力贴图版本的片元着色器示例:

ini 复制代码
varying vec4 vColor;
uniform float uMinLne;
uniform vec4 uInfo;
varying float val;

void main(void) {
    // 等高线断层
    float m = mod(val, uInfo.w);
    if(m <= uMinLne || m >= uInfo.w - uMinLne) return;

    // 热力贴图颜色
    gl_FragColor.rgb = vColor.rgb;
    gl_FragColor.a = clamp(vColor.a * 10.0, 0.0, 1.0);
}
  • 等高线断层 :通过 mod 判断热力值是否落在等高线间隔边缘
  • 颜色映射:直接使用热力贴图的 RGB 值
  • 透明度控制:增强等高线视觉效果

3️⃣ 顶点 + 片元着色器协作流程

  1. 顶点着色器

    • 读取热力贴图或计算高斯高度
    • 离散化等高线
    • 输出顶点在裁剪空间的位置
  2. 片元着色器

    • 接收顶点传下来的热力值与颜色
    • 根据等高线间隔断开片元
    • 渲染颜色与透明度

最终效果:五层山峰或热力贴图驱动的地形,同时可显示等高线,颜色渐变自然。


4️⃣ 总结

  • 热力贴图 / 高斯函数 → 控制地形起伏高度
  • 顶点着色器 → 决定顶点空间位置
  • 片元着色器 → 渲染颜色、实现等高线效果
  • 多层叠加 + 平滑权重 + 渐变颜色 → 生成自然山峰效果

本文由AI生成公供参考学习

参考 敲敲敲敲暴你脑袋 的作品而成

相关推荐
wyzqhhhh2 小时前
组件库打包工具选型(npm/pnpm/yarn)的区别和技术考量
前端·npm·node.js
码上暴富2 小时前
vue2迁移到vite[保姆级教程]
前端·javascript·vue.js
土了个豆子的2 小时前
04.事件中心模块
开发语言·前端·visualstudio·单例模式·c#
全栈技术负责人3 小时前
Hybrid应用性能优化实战分享(本文iOS 与 H5为例,安卓同理)
前端·ios·性能优化·html5
xw53 小时前
移动端调试上篇
前端
@菜菜_达3 小时前
Lodash方法总结
开发语言·前端·javascript
YAY_tyy3 小时前
基于 Vue3 + VueOffice 的多格式文档预览组件实现(支持 PDF/Word/Excel/PPT)
前端·javascript·vue.js·pdf·word·excel
Yvonne爱编码3 小时前
AJAX入门-AJAX 概念和 axios 使用
前端·javascript·ajax·html·js
在路上`4 小时前
前端学习之后端java小白(三)-sql外键约束一对多
java·前端·学习