建筑物模型上的 热力图

This commit is contained in:
hawk86104 2023-11-08 18:06:52 +08:00
parent d1ca4e471f
commit 1f7281e217
5 changed files with 260 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

View File

@ -0,0 +1,214 @@
<script setup lang="ts">
import { useRenderLoop } from '@tresjs/core'
import CustomShaderMaterial from 'three-custom-shader-material/vanilla'
import { ref, watchEffect, watch } from 'vue';
import h337 from 'heatmap.js-fix'
import * as THREE from 'three'
const props = withDefaults(defineProps<{
model: any
bulidingsColor?: string
landColor?: string
opacity?: Number
}>(), {
bulidingsColor: '#e523ff',
landColor: '#112233',
opacity: 1.0,
})
let heatmapCanvas = null
let heatmap = null
const getRandom = (max: number, min: number) => {
return Math.round((Math.random() * (max - min + 1) + min) * 10) / 10;
}
const cW = 250
const cH = 250
const initHeatmap = () => {
heatmapCanvas = document.createElement("heatmap-canvas")
heatmapCanvas.style.position = 'absolute'
// heatmapCanvas.style.display = 'none'
heatmapCanvas.style.top = '0'
heatmapCanvas.style.left = '0'
document.body.appendChild(heatmapCanvas)
heatmap = h337.create({
container: heatmapCanvas,
width: cW,
height: cH,
blur: '.8',
radius: 10
});
return heatmap
}
const setData = (data: Array) => {
const max = 12
if (data) {
} else {
let i = 0
data = [];
while (i < 2000) {
data.push({ x: getRandom(1, cW), y: getRandom(1, cH), value: getRandom(1, 6) });
i++;
}
}
heatmap.setData({
max,
data
});
texture.needsUpdate = true
}
const texture = new THREE.Texture(initHeatmap()._renderer.canvas)
setData()
// texture.repeat.set(80000, 80000);
// texture.offset.set(-0.5, -0.5);
const CITY_UNTRIANGULATED = props.model.city
CITY_UNTRIANGULATED.renderOrder = 1001
const LANDMASS = props.model.land
const setColorMaterial = (type: any, param: string) => {
const { geometry } = LANDMASS;
geometry.computeBoundingBox()
const { max, min } = geometry.boundingBox;
geometry.deleteAttribute('uv')
geometry.deleteAttribute('normal')
const roomX = max.x - min.x
const roomY = max.y - min.y
const PuvList = []
for (let i = 0; i < geometry.attributes.position.count; i++) {
PuvList.push((geometry.attributes.position.getX(i) - min.x) / roomX)
PuvList.push((geometry.attributes.position.getY(i) - min.y) / roomY)
}
const Puvs = new Float32Array(PuvList)
geometry.setAttribute('uv', new THREE.BufferAttribute(Puvs, 2));
const material = new CustomShaderMaterial({
baseMaterial: LANDMASS.material,
vertexShader: `
varying vec2 vUv;
void main() {
csm_Position = position * vec3(1.0);
vUv = uv;
}
`,
fragmentShader: `
uniform sampler2D heightMap;
uniform float uOpacity;
varying vec2 vUv;
void main() {
csm_DiffuseColor = vec4(texture2D(heightMap, vUv.xy).rgb, uOpacity);
}
`,
silent: true,
uniforms: {
uOpacity: {
value: props.opacity
},
heightMap: {
type: 't',
value: texture
},
},
uMax: { value: max },
uMin: { value: min },
depthWrite: true,
depthTest: true,
transparent: true, //
side: THREE.DoubleSide,//
})
LANDMASS.material.dispose()
LANDMASS.material = material
}
const setEffectMaterial = () => {
const { geometry } = CITY_UNTRIANGULATED;
geometry.computeBoundingBox()
geometry.computeBoundingSphere()
const { max, min } = geometry.boundingBox;
geometry.deleteAttribute('uv')
geometry.deleteAttribute('normal')
debugger
const roomX = max.x - min.x
const roomY = max.y - min.y
const PuvList = []
for (let i = 0; i < geometry.attributes.position.count; i++) {
PuvList.push((geometry.attributes.position.getX(i) - min.x) / roomX)
PuvList.push((geometry.attributes.position.getY(i) - min.y) / roomY)
}
debugger
const Puvs = new Float32Array(PuvList)
geometry.setAttribute('uv', new THREE.BufferAttribute(Puvs, 2));
// const geometry1 = new THREE.BufferGeometry();
// // .
// //
// const vertices1 = new Float32Array([
// -1.0, -1.0, 1.0,
// 1.0, -1.0, 1.0,
// 1.0, 1.0, 1.0,
// 1.0, 1.0, 1.0,
// -1.0, 1.0, 1.0,
// -1.0, -1.0, 1.0
// ]);
// // itemSize = 3
// geometry1.setAttribute('position', new THREE.BufferAttribute(vertices1, 3));
// debugger
// CITY_UNTRIANGULATED.material.dispose()
// CITY_UNTRIANGULATED.material 使 CustomShaderMaterial
const material = new CustomShaderMaterial({
baseMaterial: CITY_UNTRIANGULATED.material,
vertexShader: `
varying vec2 vUv;
void main() {
csm_Position = position * vec3(1.0);
vUv = uv;
}
`,
fragmentShader: `
uniform sampler2D heightMap;
uniform float uOpacity;
varying vec2 vUv;
void main() {
csm_DiffuseColor = vec4(texture2D(heightMap, vUv.xy).rgb, uOpacity);
}
`,
silent: true, // Disables the default warning if true
uniforms: {
uMax: { value: max },
uMin: { value: min },
uOpacity: {
value: props.opacity
},
heightMap: {
type: 't',
value: texture
},
},
depthWrite: true,
depthTest: true,
transparent: true, //
side: THREE.DoubleSide,//
})
CITY_UNTRIANGULATED.material.dispose()
CITY_UNTRIANGULATED.material = material
}
setEffectMaterial()
setColorMaterial()
const { onLoop } = useRenderLoop()
onLoop(({ delta }) => {
})
watchEffect(() => {
// if (props.bulidingsColor) {
// CITY_UNTRIANGULATED.material.uniforms.uColor.value.setStyle(props.bulidingsColor)
// }
// if (props.landColor) {
// setColorMaterial('land', 'color')
// }
// if (props.opacity) {
// CITY_UNTRIANGULATED.material.uniforms.uOpacity.value = props.opacity
// }
});
</script>
<template>
<primitive :object="props.model.model.clone()">
</primitive>
</template>

View File

@ -19,5 +19,6 @@ export default {
{ "src": "plugins/digitalCity/preview/radars.png", "type": "img", "name": "radars", "title": "雷达" },
{ "src": "plugins/digitalCity/preview/weather.png", "type": "img", "name": "weather", "title": "天气" },
{ "src": "plugins/digitalCity/preview/heatmap.png", "type": "img", "name": "heatmap", "title": "热力图" },
{ "src": "plugins/digitalCity/preview/heatmap2.png", "type": "img", "name": "heatmap2", "title": "建筑物-热力图" },
]
}

View File

@ -0,0 +1,43 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2023-10-17 08:30:49
* @LastEditors: 地虎降天龙
* @LastEditTime: 2023-11-08 14:32:02
-->
<template>
<pagesShow :showBuildings="false">
<template v-slot:ability>
<buildingsHeatmap :model="CityFBX" v-bind="buildingState" />
<buildingsLines v-bind="buildingsLinesState" :builds="CityFBX.city" />
</template>
</pagesShow>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
import { loadCityFBX } from '../common/loadCity';
import buildingsHeatmap from '../components/buildings/buildingsHeatmap.vue';
import buildingsLines from '../components/buildings/buildingsLines.vue';
import pagesShow from '../components/pagesShow.vue'
const showbuildingsLines = ref(false)
const CityFBX = await loadCityFBX()
showbuildingsLines.value = true
const buildingsLinesState = reactive({
width: 1.0,
color: '#000',
opacity: 1.0,
show: true
})
const buildingState = reactive({
bulidingsColor: '#e523ff',
landColor: '#112233',
opacity: 0.9,
show: true,
gradient: true
})
</script>

View File

@ -4,7 +4,7 @@
* @Autor: 地虎降天龙
* @Date: 2023-11-08 10:41:23
* @LastEditors: 地虎降天龙
* @LastEditTime: 2023-11-08 11:38:37
* @LastEditTime: 2023-11-08 14:04:46
-->
<script lang="ts" setup>
import { watchEffect, defineExpose } from 'vue';
@ -89,7 +89,7 @@ const shader = {
varying vec3 cl;
void main() {
float v = abs(hValue - 1.);
gl_FragColor = vec4(cl, .8 - v * v) ;
gl_FragColor = vec4(cl, .8 - v * v*1.1) ;
}`,
uniforms: {
heightMap: {