webGL.js封装的代码。
const THREE = window.THREE;
// webGL对象配置
export const webglOBJ = {
renderDom: null,
Scene: null, // 场景
camera: null, // 摄像头
renderer: null, // 渲染器
senceAdd (objList = []) {
objList.forEach(v => {
webglOBJ.Scene.add(v);
});
},
// 创建场景
createSence (renderDom) {
this.renderDom = renderDom;
webglOBJ.Scene = new THREE.Scene();
return webglOBJ.Scene;
},
// 创建摄像机
createCamera ({innerWidth, innerHeight, position} = {}) {
const { width, height } = this.renderDom.getBoundingClientRect();
let camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
camera.position.x = -50;
camera.position.y = 30;
camera.position.z = 50;
camera.lookAt(webglOBJ.Scene.position); // 视角
webglOBJ.camera = camera; // 视角
return webglOBJ.camera;
},
createRenderer () {
let renderer = new THREE.WebGLRenderer();
const {width, height} = this.renderDom.getBoundingClientRect();
renderer.setSize(width, height);
renderer.setClearColor(new THREE.Color(0xcccccc));
renderer.shadowMap.enabled = true;
this.renderDom.appendChild(renderer.domElement);
webglOBJ.renderer = renderer;
return webglOBJ.renderer;
},
createPlane (textureLoaderUrl, textureNormalUrl) {
let planeGeometry = new THREE.PlaneGeometry(60, 60, 1, 1); // 平面网格
let textureLoader = new THREE.TextureLoader();
let texture = textureLoader.load(textureLoaderUrl);
let textureNormal = textureLoader.load(textureNormalUrl);
// 加载高光贴图
let planeMaterial = new THREE.MeshPhongMaterial({
// specular: 0xff0000,//高光部分的颜色
shininess: 30, //高光部分的亮度,默认30
map: texture, // 普通纹理贴图
roughness: 0.3,
lightMap: textureNormal,
// normalMap: textureNormal, //法线贴图
bumpScale: 3
}); // 材质对象Material
// let planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
let plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.name = '平面物体ID=' + 1;
plane.position.y = 0;
plane.position.z = 0;
plane.receiveShadow = true;
return plane;
},
createBoxGeometry (textureLoaderUrl, {x, y, z}) {
// 创建立方体
let textureLoader = new THREE.TextureLoader();
let textureNormal = textureLoader.load(textureLoaderUrl);
let boxGeometry = new THREE.BoxGeometry(10, 10, 10, 200);
let texture1 = textureLoader.load(textureLoaderUrl);
let boxGeometryMaterial = new THREE.MeshLambertMaterial({
// specular: 0xff0000,//高光部分的颜色
shininess: 10, //高光部分的亮度,默认30
normalScale: new THREE.Vector2(2.2, 2.2),
map: texture1, // 普通纹理贴图
normalMap: textureNormal, //法线贴图
bumpMap: textureNormal,
bumpScale: 0.3
});
let box = new THREE.Mesh(boxGeometry, boxGeometryMaterial);
box.name = '正方物体ID=' + 2;
box.position.x = x;
box.position.y = y;
box.position.z = z;
box.castShadow = true;
return box;
},
// 点光源
createSpotLight () {
// 点光源
let spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-60, 40, -20);
spotLight.castShadow = true;
return spotLight;
},
// 平行光
createDirectionalLight (target) {
// 平行光
let directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(-90, 80, -20);
// 方向光指向对象网格模型mesh2,可以不设置,默认的位置是0,0,0
// directionalLight.target = target;
return directionalLight;
},
// 环境光
createAmbient (color = 0x444444) {
let ambient = new THREE.AmbientLight(color);
// ambient.castShadow = true;
return ambient;
},
createDatGui () {
let gui = {
bump: 0.03,
animation: false,
};
let datGui = new dat.GUI();
//将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)
datGui.add(gui, "bump", -1, 1).onChange(function (e) {
box.material.bumpScale = e;
});
datGui.add(gui, "animation");
return datGui;
},
// 创建控制轴
createControls () {
let controls = new THREE.OrbitControls(webglOBJ.camera, webglOBJ.renderDom);
return controls;
},
// 创建帮助
createAxisHelper () {
let axisHelper = new THREE.AxisHelper(250);
return axisHelper;
},
// 初始化webGL对象
webglRender (Scene, camera) {
webglOBJ.renderer.render(Scene, camera);
window.requestAnimationFrame(webglOBJ.webglRender);
}
};
/**
* 添加标签:dom方式
* @param {*} targePosition :需要传递当前标签的位置
* @param {*} targetId :标签对应的dom的唯一ID,暂且用时间戳代替,避免重复
* @param {*} innerHTML :标签对应html
*/
export function labelTag (camera, targePosition, targetId, innerHTML, webGLdom) {
const { width, height } = webGLdom.getBoundingClientRect();
let worldVector = new THREE.Vector3(targePosition.x, targePosition.y, targePosition.z);
let vector = worldVector.project(camera);
let halfWidth = width / 2,
halfHeight = height / 2;
let x = Math.round(vector.x * halfWidth + halfWidth);
let y = Math.round(-vector.y * halfHeight + halfHeight);
/**
* 更新立方体元素位置
*/
let div = document.getElementById(targetId);
div.style.left = x + 'px';
div.style.top = y + 'px';
// div.innerHTML = `uuid:${innerHTML.uuid}`;
}
vue中引用:
<template>
<div>
<div class="three-box_wrapper"></div>
<div :id="`sign${idx + 1}`" style="position: absolute;" v-for="(v, idx) in labels" :key="idx">
<div class="sign" :uuid="v.uuid">
<div class="name">我是标签1</div>
<div class="data">数据: {{v.uuid}}</div>
</div>
</div>
</div>
</template>
<script>
import {webglOBJ, labelTag} from '@/utils/webGL/webGL.js';
export default {
name: 'threeBox',
data () {
return {
labels: []
};
},
mounted () {
this.int();
},
methods: {
createLabel () {
},
int () {
const imgBG = require('./img.jpg');
const webGLdom = document.querySelector('.three-box_wrapper');
const sence = webglOBJ.createSence(webGLdom);
const camera = webglOBJ.createCamera();
const renderer = webglOBJ.createRenderer();
const plane = webglOBJ.createPlane(imgBG, imgBG);
const boxGeometry = webglOBJ.createBoxGeometry(imgBG, {x: 10, y: 5, z: 10});
const boxGeometry1 = webglOBJ.createBoxGeometry(imgBG, {x: -10, y: 5, z: 10});
const spotLight = webglOBJ.createSpotLight();
const directionalLight = webglOBJ.createDirectionalLight(boxGeometry);
const ambient = webglOBJ.createAmbient();
const datGui = webglOBJ.createDatGui();
const controls = webglOBJ.createControls();
const axisHelper = webglOBJ.createAxisHelper();
// 将对象添加到场景中去
webglOBJ.senceAdd([plane, boxGeometry, boxGeometry1, spotLight, directionalLight, ambient, datGui, controls, axisHelper]);
// webglOBJ.webglRender(sence, camera, renderer);
console.log(sence, 'sence');
const vm = this;
function render(html) {
vm.labels = sence.children.filter(v => v.type == 'Mesh');
vm.$nextTick(() => {
sence.children.forEach((val, idx) => {
if (val.type == 'Mesh') {
const {x, y, z} = val.position;
labelTag(camera, {x, y, z}, `sign${idx + 1}`, val, webGLdom);
}
});
});
renderer.render(sence, camera);
requestAnimationFrame(render);
};
render();
// 监听点击事件查看点击的元素
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
// 点击了哪个模型
function clickEvent() {
if (event.target.tagName == 'CANVAS') {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
sence.updateMatrixWorld(true);
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
raycaster.setFromCamera(mouse, camera);
// 获取raycaster直线和所有模型相交的数组集合
let intersects = raycaster.intersectObjects(sence.children, true);
if (intersects[0]) {
console.log(intersects[0]);
}
}
}
window.addEventListener('click', clickEvent, false);
}
}
};
</script>
<style lang="scss" scoped>
.three-box_wrapper {
position: relative;
width: 100%;
height: 800px;
border: 1px solid #ccc;
}
div[id *= "sign"] {
width: 250px;
height: 100px;
background: rgba(0, 0, 0, .65);
.sign{
div {
color: #fff;
text-align: left;
padding: 0 5px;
}
}
}
</style>