登峰造极境

  • WIN
    • CSharp
    • JAVA
    • OAM
    • DirectX
    • Emgucv
  • UNIX
    • FFmpeg
    • QT
    • Python
    • Opencv
    • Openwrt
    • Twisted
    • Design Patterns
    • Mysql
    • Mycat
    • MariaDB
    • Make
    • OAM
    • Supervisor
    • Nginx
    • KVM
    • Docker
    • OpenStack
  • WEB
    • ASP
    • Node.js
    • PHP
    • Directadmin
    • Openssl
    • Regex
  • APP
    • Android
  • AI
    • Algorithm
    • Deep Learning
    • Machine Learning
  • IOT
    • Device
    • MSP430
  • DIY
    • Algorithm
    • Design Patterns
    • MATH
    • X98 AIR 3G
    • Tucao
    • fun
  • LIFE
    • 美食
    • 关于我
  • LINKS
  • ME
Claves
长风破浪会有时,直挂云帆济沧海
  1. 首页
  2. Programming
  3. babylon.js
  4. 正文

Babylonjs中实现热力图材质ShaderMaterial

2025-05-09

一、素材

二、参考资料

https://www.patrick-wied.at/static/heatmapjs

三、技术实现

https://playground.babylonjs.com/#IAR6FJ#11

var createScene = function () {
    // This creates a basic Babylon Scene object (non-mesh)
    var scene = new BABYLON.Scene(engine);

    // This creates and positions a free camera (non-mesh)
    const camera = new BABYLON.ArcRotateCamera("camera", Math.PI / 2, Math.PI / 4, 10, BABYLON.Vector3.Zero(), scene);
    // This targets the camera to scene origin
    camera.setTarget(BABYLON.Vector3.Zero());
    camera.attachControl(canvas, true);
    var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
    light.intensity = 0.7;

    var skybox = BABYLON.Mesh.CreateBox("BackgroundSkybox", 5000, scene, undefined, BABYLON.Mesh.BACKSIDE);
    var backgroundMaterial = new BABYLON.BackgroundMaterial("backgroundMaterial", scene);
    backgroundMaterial.reflectionTexture = new BABYLON.CubeTexture("textures/TropicalSunnyDay", scene);
    backgroundMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
    skybox.material = backgroundMaterial;


    // 定义固定温度点数据
    const fixedPoints = [
        { position: new BABYLON.Vector2(1, 1), temperature: 30 },
        { position: new BABYLON.Vector2(3, 2), temperature: 25 },
        { position: new BABYLON.Vector2(5, 5), temperature: 40 },
        { position: new BABYLON.Vector2(7, 3), temperature: 20 },
        { position: new BABYLON.Vector2(2, 6), temperature: 35 }
    ];
    const tempValues = fixedPoints.map(p => [p.position.x,p.position.y,p.temperature]).flat();

    const shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, {
        vertexSource: `
            precision highp float;
            attribute vec3 position;
            attribute vec2 uv;
            uniform mat4 worldViewProjection;
            varying vec2 vUV;
            
            void main() {
                vUV = uv;
                gl_Position = worldViewProjection * vec4(position, 1.0);
            }
        `,
        fragmentSource: `
            precision highp float;
            varying vec2 vUV;
            
            const int numPoints = 5;
            // Uniforms
            uniform float minTemp;
            uniform float maxTemp;
            uniform float power;
            uniform float tempValues[numPoints*3];
      

            // 温度转颜色
            vec3 temperatureToColor(float temp) {
                float t = (temp - minTemp) / (maxTemp - minTemp);
                t = clamp(t, 0.0, 1.0);
                
                vec3 colorCold = vec3(0.0, 0.0, 1.0);    // 蓝
                vec3 colorCool = vec3(0.0, 1.0, 1.0);    // 青
                vec3 colorNeutral = vec3(0.0, 1.0, 0.0); // 绿
                vec3 colorWarm = vec3(1.0, 1.0, 0.0);    // 黄
                vec3 colorHot = vec3(1.0, 0.0, 0.0);     // 红
                
                if (t < 0.25) {
                    return mix(colorCold, colorCool, t / 0.25);
                } else if (t < 0.5) {
                    return mix(colorCool, colorNeutral, (t - 0.25) / 0.25);
                } else if (t < 0.75) {
                    return mix(colorNeutral, colorWarm, (t - 0.5) / 0.25);
                } else {
                    return mix(colorWarm, colorHot, (t - 0.75) / 0.25);
                }
            }

            void main() {
                vec2 worldPos = vUV*8.0;

                // 反距离加权插值
                float numerator = 0.0;
                float denominator = 0.0001; // 避免除以零
                
                for (int i = 0; i < numPoints; i++) {
           
                    vec2 pointPos = vec2(tempValues[3*i], tempValues[3*i+1]);
                    float dist = distance(worldPos, pointPos);
                    
                    if (dist < 0.001) { // 正好在点上
                        numerator = tempValues[3*i+2];
                        denominator = 1.0;
                        break;
                    }
                    
                    float weight = 1.0 / pow(dist, power);
                    numerator += tempValues[3*i+2] * weight;
                    denominator += weight;
                }
                
                float temp = numerator / denominator;
                // 应用颜色映射
                gl_FragColor = vec4(temperatureToColor(temp), 1.0);
            }
        `
    }, {
        attributes: ["position", "uv"],
        uniforms: ["worldViewProjection"],
        samplers: []
    });

    
    // // 设置着色器参数
    shaderMaterial.setFloat("power",2.0);
    shaderMaterial.setFloat("minTemp", 20.0);
    shaderMaterial.setFloat("maxTemp", 40.0);
    shaderMaterial.setFloats("tempValues", tempValues);


    var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 8, height: 8}, scene);

var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 2}, scene);
sphere.position.y = -2;
var box = BABYLON.MeshBuilder.CreateBox("box", {size: 2}, scene);
box.position.y = -4;
var cylinder = BABYLON.MeshBuilder.CreateCylinder("cylinder", {height: 2, diameter: 1}, scene);
cylinder.position.y = -6;
    ground.material = shaderMaterial;
    sphere.material = shaderMaterial;
    box.material = shaderMaterial;
    cylinder.material = shaderMaterial;

    return scene;
};
标签: 暂无
最后更新:2025-05-09

代号山岳

知之为知之 不知为不知

点赞
< 上一篇

COPYRIGHT © 2099 登峰造极境. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

蜀ICP备14031139号-5

川公网安备51012202000587号