三维前端文档
1.整体流程图
2.实现步骤
-
创建本地数据库
connect.onupgradeneeded = function (event) { console.log("数据库更新") db = event.target.result; // 判断是否有这个表 if (!db.objectStoreNames.contains('person')) { // 创建表 var objectStore; objectStore = db.createObjectStore('person', { // 主键 keyPath: 'id' }); // 创建索引 objectStore.createIndex('blob', 'blob', { // 是否唯一 unique: false }); objectStore.createIndex('name', 'name', { // 是否唯一 unique: true }); } } -
查找本地模型
function find(storename, key, callback) {
let store = db.transaction(storename, 'readwrite').objectStore(storename);
let request = store.get(key);
request.onerror = function () {
console.error('getDataByKey error');
};
request.onsuccess = function (e) {
// 查到了
if (result) {
var url = URL.createObjectURL(result.blob)
THREE.DRACOLoader.setDecoderPath('three/examples/js/libs/draco/gltf/'); //设置解压库文件路径
var dracoLoader = new THREE.DRACOLoader();
gltfloader.setDRACOLoader(dracoLoader);
gltfloader.load(url, function (gltf) {
// 清理 blob协议缓存
// URL.revokeObjectURL(url)
scene.add(gltf.scene)
setCameraHide(false);
addCameraImg()
gltf.scene.position.set(-5, 0, 0);
setTimeout(() => {
renderDailog();
console.log('渲染结束', new Date());
}, 10)
if (callback) {
callback(result);
}
});
} else {
console.log('没查到');
console.log('开始下载', new Date());
xhr.send();
}
}
}
- 下载模型
var xhr = new XMLHttpRequest(),
blob;
xhr.open("GET", url, true);
// Set the responseType to blob
xhr.responseType = "blob";
xhr.addEventListener("load", function () {
if (xhr.status === 200) {
console.log('下载结束', new Date());
// File as response
blob = xhr.response;
addData('person', {
id: 'parkwh',
blob: blob
}, () => {
console.log('添加成功-开始查询')
find('person', 'parkwh', () => {
console.log('查找结束')
})
})
// Put the received blob into IndexedDB
// putElephantInDb(blob);
}
}, false);
- 添加indexDb
function addData(storename, data, callback) {
let store = db.transaction(storename, 'readwrite').objectStore(storename);
let request = store.add(data);
request.onerror = function () {
console.error('add添加数据库中已有该数据')
};
request.onsuccess = function () {
console.log('add添加数据已存入数据库')
callback();
};
}
- gltfLoader加载模型,模型添加至场景,设置模型初始位置
var url = URL.createObjectURL(result.blob)
// let loader = new THREE.GLTFLoader();
THREE.DRACOLoader.setDecoderPath('three/examples/js/libs/draco/gltf/'); //设置解压库文件路径
var dracoLoader = new THREE.DRACOLoader();
gltfloader.setDRACOLoader(dracoLoader);
gltfloader.load(url, function (gltf) {
// 清理 blob协议缓存
// URL.revokeObjectURL(url)
scene.add(gltf.scene)
setCameraHide(false);
addCameraImg()
gltf.scene.position.set(-5, 0, 0);
setTimeout(() => {
renderDailog();
console.log('渲染结束', new Date());
}, 10)
if (callback) {
callback(result);
}
});
}
- 通知主程序点位坐标
const renderDailog = () => {
let ad = [];
if (!scene) return null;
const arr = scene.children.find((d) => d.type === 'Scene');
const text = arr.children.find((d) => d.name === "warning");
const dataS = [];
if (text && text.children) {
text.children.map((li) => {
li.getWorldPosition(worldVector);
// 特殊情况下,局部坐标等于世界坐标
// var worldVector = boxMesh.position.clone();
// 世界坐标转标准设备坐标,standardVector是WebGL标准设备坐标
// .project()方法提取相机参数的视图矩阵、投影矩阵对世界坐标进行变换
const standardVector = worldVector.project(camera);
const a = width / 2;
const b = height / 2;
const x = Math.round(standardVector.x * a + a); // 模型标签x坐标,单位像素
const y = Math.round(-standardVector.y * b + b); // 模型标签y坐标,单位像素
li.domTop = y;
li.domLeft = x;
dataS.push({
name: li.name.replace('dw-', '').replace('dw_', ''),
domTop: li.domTop,
domLeft: li.domLeft,
});
});
}
sendMessage('dailog', dataS);
};
const sendMessage = (title, obj) => {
var data = {
name: title,
data: obj,
};
window.parent.postMessage(data, '*'); //window.postMessage
};
- 摄像头隐藏
const setCameraHide = (bool) => {
if (!scene) return;
const sce = scene.children.find(d => d.type === "Scene")
if (!sce) return;
const obj = sce.children.find(d => d.name === "cameras")
if (!obj) return;
if (bool) {
obj.children.map((d) => {
if (bool.data[d.name.replace('sxt_', '').replace('sxt-', '')]) {
d.children?.map((li) => {
li.visible = true;
})
}
})
} else {
obj.children.map((d) => {
d.children?.map((li) => {
li.visible = bool;
})
})
}
}
- 入口隐藏
const addCameraImg = () => {
if (!scene) return;
const sce = scene.children.find(d => d.type === "Scene")
console.log(sce, '----')
if (!sce) return;
const cameras = sce.children.find(d => d.name === "cameras")
if (!cameras) return;
const warnings = sce.children.find(d => d.name === "warning")
const titles = sce.children.find(d => d.name === "文字")
warnings?.children.map((d) => {
d.material.visible = false;
})
titles?.children.map((d) => {
// d.material.visible = false;
d.children?.map((li) => {
li.material.visible = false;
})
setTitle(d)
})
console.log(cameraData, 'cameraData')
cameras?.children.map((d) => {
d.material.visible = false;
setLabel(d);
})
cameras?.children.map((d) => {
d.children?.map((li) => {
li.visible = false;
})
})
}
- 自定义摄像头/入口
const setLabel = (onjectValue) => {
var labelDiv = document.createElement('div')
labelDiv.className = 'label';
labelDiv.name = onjectValue.name;
labelDiv.ondblclick = cameraClick;
var earthLabel = new THREE.CSS2DObject(labelDiv)
onjectValue.add(earthLabel)
}
const setTitle = (onjectValue) => {
const arr =
[
{
code: 'fftl', name: '浮法脱硫'
},
{
code: "cc1", name: '仓储1'
},
{
code: "cc2", name: '仓储2'
},
{
code: "dd500", name: '电子500T'
},
{
code: "dmrx", name: '镀膜二线'
},
{
code: "dmsx", name: '镀膜三线'
},
{
code: "dmyx", name: '镀膜一线'
},
{
code: "dz200", name: '电子200T'
},
{
code: "dzcy", name: '电子储运'
},
{
code: "dztltx", name: '电子脱硫脱硝'
},
{
code: "ff500", name: '浮法500T'
},
{
code: "ff600", name: '浮法600T'
},
{
code: "ff700", name: '浮法700T'
},
{
code: "ff900", name: '浮法900T'
},
{
code: "trqzq", name: '天然气制氢'
},
{
code: "yqdqz", name: '一期氮氢站'
},
{
code: "dz", name: '氮站'
},
{
code: "dztl", name: '电子脱硫'
},
{
code: "dztx", name: '电子脱硝'
},
]
const obj = arr.find((d) => d.code === onjectValue.name)
if (obj && obj.name) {
var labelDiv = document.createElement('div')
labelDiv.className = 'title';
labelDiv.innerText = obj.name;
labelDiv.id = obj.code;
labelDiv.name = onjectValue.name;
labelDiv.ondblclick = enterLine;
var earthLabel = new THREE.CSS2DObject(labelDiv)
onjectValue.add(earthLabel)
}
}
- 设置灯光/相机/渲染器
const setLight = () => {
//环境光
var ambient = new THREE.AmbientLight(0xC4C4C4, 1);
var point = new THREE.PointLight(0xC4C4C4, 1);
var point1 = new THREE.PointLight(0xC4C4C4, 1);
var point2 = new THREE.PointLight(0xC4C4C4, 1);
// 点光源
point.position.set(-15.432835578918457, 37.574790954589844, 77.27122497558594); // 点光源位置
point1.position.set(356.2715148925781, 127.52357482910156, -142.99517822265625); // 点光源位置
point2.position.set(-54.23904037475586, 28.659584045410156, -59.19256591796875); // 点光源位置
scene.add(point); // 点光源添加到场景中
scene.add(point1); // 点光源添加到场景中
scene.add(point2); // 点光源添加到场景中
// 环境光
// scene.add(ambient);
};
/**
* 相机设置
*/
const setCamera = () => {
camera.position.set(11.582765074860337, 80.84475536367229, 154.73173390246936); // 设置相机位置
camera.lookAt(new THREE.Vector3(0, 0, 0)); // 设置相机方向(指向的场景对象)
};
/**
* 创建渲染器对象
*/
const setRender = () => {
renderer.shadowMap.enabled = false;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(width, height); // 设置渲染区域尺寸
// renderer.setClearColor(0x000000, 1); // 设置背景颜色
document.body.appendChild(renderer.domElement); // body元素中插入canvas对象
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(width, height);
labelRenderer.domElement.style.position = "absolute";
labelRenderer.domElement.style.top = 0;
document.body.appendChild(labelRenderer.domElement);
};
- 增加双击事件/划过事件
function dbclick(event) {
if (!scene) return;
if (!scene.children.find((d) => d.type === 'Scene')) return;
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const arr = scene.children.find((d) => d.type === 'Scene');
}
function mouseover(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const arr = scene.children.find((d) => d.type === 'Scene');
const text = arr.children.find((d) => d.name === '文字');
var intersects = raycaster.intersectObjects(text.children, true);
if (intersects.length > 0) {
selectObj && (selectObj.material.color = oldColor);
selectObj = intersects[0].object;
var {
r,
g,
b
} = {
...selectObj.material.color
};
oldColor = new THREE.Color(r, g, b);
selectObj.material.color.set('#b97751');
selectObj.material.needsUpdate = true;
} else {
selectObj && (selectObj.material.color = oldColor);
}
}