three.js 通过着色器实现热力图效果

three.js 通过着色器实现热力图效果

在线预览 https://threehub.cn/#/codeMirror?navigation=ThreeJS&classify=shader&id=heatmapShader

https://threehub.cn 中还有很多案例

csharp 复制代码
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script type="importmap">
{
    "imports": {
        "three": "https://threejs.org/build/three.module.min.js",
        "three/addons/": "https://threejs.org/examples/jsm/",
        "three/examples/jsm/": "https://threejs.org/examples/jsm/",
        "gsap": "https://file.threehub.cn/js/gsap/index.js",
        "postprocessing": "https://threehub.cn/js/postprocessing.js",
        "cannon-es": "https://threehub.cn/js/cannon-es.js",
        "dat.gui": "https://threehub.cn/js/dat.gui.module.js",
        "@tweenjs/tween.js": "https://threehub.cn/js/tween.esm.js"
    }
}
</script>
<style>
    body {
        margin: 0;
        padding: 1px;
        box-sizing: border-box;
        background-color: #1f1f1f;
        display: flex;
        flex-direction: column;
        width: 100vw;
        height: 100vh;
        overflow: hidden;
    }
    #box {
        width: 100%;
        height: 100%;
    }
</style>
</head>
<body>
<div id="box"></div>
<script type="module">
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GUI } from "three/addons/libs/lil-gui.module.min.js";

const box = document.getElementById('box')

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 1000)

camera.position.set(0, 10, 10)

const renderer = new THREE.WebGLRenderer()

renderer.setSize(box.clientWidth, box.clientHeight)

box.appendChild(renderer.domElement)

new OrbitControls(camera, renderer.domElement)

animate()

function animate() {

    requestAnimationFrame(animate)

    renderer.render(scene, camera)

}

window.onresize = () => {

    renderer.setSize(box.clientWidth, box.clientHeight)

    camera.aspect = box.clientWidth / box.clientHeight

    camera.updateProjectionMatrix()

}

scene.add(new THREE.AmbientLight(0xffffff, 2), new THREE.AxesHelper(1000))

const arr = [[0., 0., 10.], [.2, .6, 5.], [.25, .7, 8.], [.33, .9, 5.], [.35, .8, 6.], [0.017, 5.311, 6.000], [-.45, .8, 4.], [-.2, -.6, 5.], [-.25, -.7, 8.], [-.33, -.9, 8.], [.35, -.45, 10.], [-.1, -.8, 10.], [.33, -.3, 5.], [-.35, .75, 6.], [.6, .4, 10.], [-.4, -.8, 4.], [.7, -.3, 6.], [.3, -.8, 8.]].map(i => new THREE.Vector3(...i))

const uniforms1 = {

    HEAT_MAX: { value: 10, type: 'number', unit: 'float' },

    PointRadius: { value: 0.42, type: 'number', unit: 'float' },

    PointsCount: { value: arr.length, type: 'number-array', unit: 'int' }, // 数量

    c1: { value: new THREE.Color(0x000000), type: 'color', unit: 'vec3' },

    c2: { value: new THREE.Color(0x000000), type: 'color', unit: 'vec3' },

    uvY: { value: 1, type: 'number', unit: 'float' },

    uvX: { value: 1, type: 'number', unit: 'float' },

    opacity: { value: 1, type: 'number', unit: 'float' }

}

const gui = new GUI()

gui.add(uniforms1.HEAT_MAX, 'value', 0, 10).name('HEAT_MAX')

gui.add(uniforms1.PointRadius, 'value', 0, 1).name('PointRadius')

gui.add(uniforms1.uvY, 'value', 0, 1).name('uvY')

gui.add(uniforms1.uvX, 'value', 0, 1).name('uvX')

gui.add(uniforms1.opacity, 'value', 0, 1).name('opacity')

gui.addColor(uniforms1.c1, 'value').name('c1')

gui.addColor(uniforms1.c2, 'value').name('c2')

const uniforms2 = {

    Points: { value: arr, type: 'vec3-array', unit: 'vec3' }

}

const uniforms = {

    ...uniforms1,

    ...uniforms2

}

const vertexShader = `
varying vec2 vUv;
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`

const fragmentShader = 'precision highp float;\n' + 'varying vec2 vUv; \n' +

    Object.keys(uniforms1).map(i => 'uniform ' + uniforms1[i].unit + ' ' + i + ';')
        .join('\n')

    + '\nuniform vec3 Points['
    + uniforms1.PointsCount.value + '];'
    +
    `
vec3 gradient(float w, vec2 uv) {
    w = pow(clamp(w, 0., 1.) * 3.14159 * .5, .9);
    return vec3(sin(w), sin(w * 2.), cos(w))* 1.1 + mix(c1, c2, w) * 1.1; 
}
void main()
{
    vec2 uv = vUv;
    uv.xy *= vec2(uvX, uvY);
    float d = 0.;
    for (int i = 0; i < PointsCount; i++) {
        vec3 v = Points[i];
        float intensity = v.z / HEAT_MAX;
        float pd = (1. - length(uv - v.xy) / PointRadius) * intensity;
        d += pow(max(0., pd), 2.);
    }
    gl_FragColor = vec4(gradient(d, uv), opacity);
} `


const shaderMaterial = new THREE.ShaderMaterial({

    uniforms,

    vertexShader,

    fragmentShader,

    transparent: true


})

const plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), shaderMaterial)

scene.add(plane)

console.log(shaderMaterial)
/**
 * 名称: 热力图
 * 来源:优雅永不过时
 * https://github.com/z2586300277
 */

</script>
</body>
</html>
相关推荐
十有八七20 小时前
Hermes Agent 自进化实现:从源码到架构的深度拆解
前端·人工智能
渐儿20 小时前
NestJS 生产级开发教程
前端
前端毕业班20 小时前
uni-app onShareAppMessage hook 原理分析
前端·javascript
gogoing20 小时前
React 分包加载优化
前端·react.js
gogoing20 小时前
Babel 配置与工具
前端·javascript
亲亲小宝宝鸭20 小时前
重新install,项目就跑不起来了?!
前端·npm
Mike117.20 小时前
GBase 8a 物化视图依赖和 DDL 风险排查记录
java·服务器·前端
蜡台21 小时前
Vue3 Hook 与 Store 状态管理:深度解析与选型指南
前端·javascript·vue.js
存在的五月雨21 小时前
项目中 Vitest 配置详解:vitest.config.ts
开发语言·javascript·vue.js
淡笑沐白21 小时前
JavaScript零基础到精通
开发语言·javascript·ecmascript