# Mesh实体

 `MeshEntity` 是由 实体`Entity` 和 `MeshModule` 模块组合而成的新的实体。

 [MeshEntity](https://vjmap.com/map3d/api/classes/MeshEntity.html) =  [Entity](https://vjmap.com/map3d/api/classes/Entity.html) + [MeshModule](https://vjmap.com/map3d/api/classes/MeshModule.html) 

 ## 常用方法


 `MeshEntity` 是由 实体`Entity` 派生而来。具体 [Entity](https://vjmap.com/map3d/api/classes/Entity.html) 的所有属性和方法。同时也具有[MeshModule](https://vjmap.com/map3d/api/classes/MeshModule.html)  的相关方法。


|方法|描述|
|:---|:---|
|[mesh](https://vjmap.com/map3d/api/classes/MeshEntity.html#mesh)|mesh对象|
|[rawMaterial](https://vjmap.com/map3d/api/classes/MeshModule.html#rawMaterial)|`rawMaterial()` 获取最开始的原生材质，为空表示没有修改过。⚠️ `.d.ts` 在 `MeshEntity` 上声明的是 `nativeMaterial`，但运行时混入的是 `rawMaterial`（`meshEnt.nativeMaterial` 为 `undefined`）；TS 中需 `(meshEnt as any).rawMaterial()`|
|[useMaterial](https://vjmap.com/map3d/api/classes/MeshEntity.html#useMaterial)|获取替换后的正使用的材质，为空表示没有修改过|
|[material](https://vjmap.com/map3d/api/classes/MeshEntity.html#material)|获取原材质的**克隆副本**（getter，首次访问时克隆）。⚠️ 只是副本、不会自动挂到 mesh 上：改完后需 `meshEnt.replaceMaterial(meshEnt.material)` 才生效|
|[addEdges](https://vjmap.com/map3d/api/classes/MeshEntity.html#addEdges)|增加模型边框线|
|[clearEdges](https://vjmap.com/map3d/api/classes/MeshEntity.html#clearEdges)|移除模型边框线|
|[getEdges](https://vjmap.com/map3d/api/classes/MeshEntity.html#getEdges)|获取模型边框线|
|[replaceMaterial](https://vjmap.com/map3d/api/classes/MeshEntity.html#replaceMaterial)|替换材质|
|[resetMaterial](https://vjmap.com/map3d/api/classes/MeshEntity.html#resetMaterial)|恢复材质|
|[setHeatmapDataMaterial](https://vjmap.com/map3d/api/classes/MeshEntity.html#setHeatmapDataMaterial)|设置热力图数据分析材质|
|[isHighlight](https://vjmap.com/map3d/api/classes/MeshEntity.html#isHighlight)|是否高亮|
|[setHighlight](https://vjmap.com/map3d/api/classes/MeshEntity.html#setHighlight)|设置高亮|
|[clearHighlight](https://vjmap.com/map3d/api/classes/MeshEntity.html#clearHighlight)|清除高亮|
|[highlightMaterial](https://vjmap.com/map3d/api/classes/MeshEntity.html#highlightMaterial)|获取高亮材质|
|[setOpacity](https://vjmap.com/map3d/api/classes/MeshEntity.html#setOpacity)|设置透明度|
|[opacityMaterial](https://vjmap.com/map3d/api/classes/MeshEntity.html#opacityMaterial)|获取透明度材质|
|[clearHighlight](https://vjmap.com/map3d/api/classes/MeshEntity.html#clearHighlight)|清除高亮|
   

## 使用示例


### 创建一个MeshEntity
```js
const box = new THREE.Mesh(
    new THREE.BoxGeometry(3, 3, 3),
    new THREE.MeshStandardMaterial({ color: 0xff0000 })
);
let meshEnt = new vjmap3d.MeshEntity(box);
meshEnt.addTo(app);
```

### 给实体增加事件模块
```js
// 增加一个事件模块，用来高亮提示
meshEnt.add(vjmap3d.EventModule, {
    clickHighlight: true,
    highlightOpacity: 0.2,
    hoverSelect: true,
    hoverHtmlText: "我是MeshEntity",
    clickHtmlText: `您点击我了！`,
    popupOptions: {
        anchor: "bottom"
    }
});
```

### 生成热力图数据分析材质
```js
// 获取实体的外包盒
let box3d = meshEnt.getBoundingBox(false);
let pointNum = 10; // 模拟十个点的业务数据
let data = []
let size = new THREE.Vector3();
box3d.getSize(size)
for(let k = 0 ; k < pointNum; k++) {
    data.push({
        x: box3d.min.x + Math.random() * size.x,
        y: box3d.min.y + Math.random() * size.y,
        z: box3d.min.z + Math.random() * size.z,
        value: Math.random() * 100
    })
}
// 设置热力图数据分析材质
await meshEnt.setHeatmapDataMaterial({
    data,
})
// 还原成原来的材质
meshEnt.resetMaterial();
```

> ⚠️ `setHeatmapDataMaterial` 是**异步**方法，返回 `Promise<{ lut, material, reset }>`——必须 `await` 后 `mesh.material` 才被替换成返回的材质（webgl 下是 `ShaderMaterial`，webgpu 下是 TSL 的 `VolumeBoxMaterial` 节点材质）；不 await 立即读材质还是旧值（内部走 worker 插值计算）。
>
> - 内部走 `replaceMaterial`：若实体此时**处于高亮**（`isHighlight()` 为 true），只记录不替换，`mesh.material` 要等 `clearHighlight()` 后才换成热力图材质。
> - `segmentX/segmentY/segmentZ` 运行时默认都是 **10**（`.d.ts` 注释写的"默认20"与运行时不符）。

<mapFrame>
<pre>
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    }
})
//
 const box = new THREE.Mesh(
    new THREE.BoxGeometry(3, 3, 3),
    new THREE.MeshStandardMaterial({ color: 0xff0000 })
);
let meshEnt = new vjmap3d.MeshEntity(box);
meshEnt.addTo(app);
meshEnt.add(vjmap3d.EventModule, {
    clickHighlight: true,
    highlightOpacity: 0.2,
    hoverSelect: true,
    hoverHtmlText: "我是MeshEntity",
    clickHtmlText: `您点击我了！`,
    popupOptions: {
        anchor: "bottom"
    }
});
// 
let control = new vjmap3d.ButtonGroupControl({
    buttons: [
        {
            id: "id1",
            html: "数据热力图",
            style: {
                width: "100px"
            },
            onclick: async () => {
                // 获取实体的外包盒
                let box3d = meshEnt.getBoundingBox(false);
                let pointNum = 10; // 模拟十个点的业务数据
                let data = []
                let size = new THREE.Vector3();
                box3d.getSize(size)
                for(let k = 0 ; k < pointNum; k++) {
                    data.push({
                        x: box3d.min.x + Math.random() * size.x,
                        y: box3d.min.y + Math.random() * size.y,
                        z: box3d.min.z + Math.random() * size.z,
                        value: Math.random() * 100
                    })
                }
                // 设置热力图数据分析材质
                await meshEnt.setHeatmapDataMaterial({
                    data,
                })
            }
        },{
            id: "id2",
            html: "取消热力图",
            style: {
                width: "100px"
            },
            onclick: async () => {
                // 还原成原来的材质
                meshEnt.resetMaterial();
            }
        }
    ]
});
app.addControl(control, "top-right");
</pre>
</mapFrame>
