项目需求,需要自定义材质球,方便使用封装成了类,可以使用在各种项目
1.效果展示
2:实现代码
使用方式,传入初始化DOM,和初始化材质配置即可
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { LightProbeGenerator } from "three/addons/lights/LightProbeGenerator.js";
class MaterialSphere {
constructor(
dom,
materialOptions = {},
materialValue = "MeshStandardMaterial"
) {
this.dom = dom; // 保存DOM引用
this.materialOptions = materialOptions; // 保存初始材质选项
this.materialValue = materialValue; // 保存初始材质值
// 创建场景
this.scene = new THREE.Scene();
// 确保DOM元素有正确的宽高
if (!dom || dom.clientWidth === 0 || dom.clientHeight === 0) {
throw new Error("无效的DOM元素或尺寸。");
}
// 计算相机的长宽比
const aspectRatio = dom.clientWidth / dom.clientHeight;
// 创建相机
this.camera = new THREE.PerspectiveCamera(45, aspectRatio, 0.1, 10000);
// 设置相机位置
this.camera.position.set(10, 0, 0);
this.camera.lookAt(0, 0, 0);
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true }); // 启用抗锯齿
this.renderer.setSize(dom.clientWidth, dom.clientHeight); // 设置渲染器大小
this.renderer.setPixelRatio(window.devicePixelRatio); // 设置像素比
// 色调映射
this.renderer.toneMapping = THREE.NoToneMapping;
// 将渲染器的DOM元素添加到文档中
dom.appendChild(this.renderer.domElement);
// 光探测器
this.lightProbe = new THREE.LightProbe();
this.scene.add(this.lightProbe);
// 添加方向光
this.directionalLight = new THREE.DirectionalLight(0xffffff, 0.6);
this.directionalLight.position.set(800, 800, 800); // 设置平行光的位置
this.scene.add(this.directionalLight);
// 纹理贴图加载器TextureLoader
this.texLoader = new THREE.TextureLoader();
// 环境贴图
this.scene.background = new THREE.CubeTextureLoader()
.setPath("/pisa/")
.load(
["px.png", "nx.png", "py.png", "ny.png", "pz.png", "nz.png"],
(cubeTexture) => {
this.scene.background = cubeTexture; // 设置场景背景为加载的立方体贴图
this.lightProbe.copy(
LightProbeGenerator.fromCubeTexture(cubeTexture)
); // 从立方体贴图生成光探测器
const geometry = new THREE.SphereGeometry(1, 32, 32);
// 创建球体网格并加入场景
this.sphere = new THREE.Mesh(
geometry,
this.initMaterial(materialOptions)
);
// 设置球体位置
this.sphere.position.set(0, 0, 0);
// 将球体加入场景
this.scene.add(this.sphere);
},
() => {
console.log("将在加载过程中进行调用");
},
(err) => {
console.log(err);
console.log("加载错误时被调用");
}
);
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(this.camera, this.renderer.domElement);
controls.target.set(0, 0, 0); // 设置轨道控制器的观察目标为球
controls.update(); // 更新控件
controls.minDistance = 10; // 设置最小距离
controls.maxDistance = 50; // 设置最大距离
controls.enablePan = false; // 禁用平移
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener("change", () => {
this.renderer.render(this.scene, this.camera);
});
// // 创建网格地面
// this.createGridFloor()
// 绑定resize事件处理器以适应窗口大小变化
window.addEventListener("resize", () => this.onWindowResize(dom), false);
// 立即调用一次以适应初始大小
this.onWindowResize(dom);
// 开始渲染循环
this.animate();
}
initMaterial(mat) {
// 创建球体几何体
let { map, ...Options } = mat;
// 创建材质
this.material = new THREE[this.materialValue]({
envMapIntensity: 0.5, // 设置环境贴图强度
map: this.setMap(map),
...Options,
});
return this.material;
}
//更新材质属性
updateMaterial(value) {
this.materialValue = value;
this.sphere.material = this.initMaterial(this.materialOptions);
}
// 更新材质
updateMaterialOptions(newOptions) {
this.materialOptions = { ...this.materialOptions, ...newOptions };
this.sphere.material = this.initMaterial(this.materialOptions);
}
// 动态调整渲染器尺寸和相机长宽比的方法
onWindowResize(dom) {
// 更新相机的长宽比
this.camera.aspect = dom.clientWidth / dom.clientHeight;
// 更新相机的投影矩阵(这是必须的)
this.camera.updateProjectionMatrix();
// 更新渲染器的大小
this.renderer.setSize(dom.clientWidth, dom.clientHeight);
}
// 创建网格地面的方法
createGridFloor() {
const size = 20; // 网格的尺寸
const divisions = 20; // 网格的分割数
const gridHelper = new THREE.GridHelper(size, divisions);
this.scene.add(gridHelper);
}
// 设置纹理
setMap(file) {
// .load()方法加载图像,返回一个纹理对象Texture
if (!file) return "";
const texture = this.texLoader.load(file);
return texture;
}
// 设置颜色
setColor(hexColor) {
this.material.color.set(hexColor);
}
//设置属性
setProperty(property, value) {
this.material[property] = value;
}
//获取所有属性
getAllProperty() {
return this.material;
}
// 动画渲染方法
animate() {
requestAnimationFrame(() => this.animate());
this.renderer.render(this.scene, this.camera);
}
}
export default MaterialSphere;
//使用
//获取dom
// const container = document.getElementById("modeleStateContent");
// //初始化
//传入初始化材质和dom
// materialSphere = new MaterialSphere(container, initialMaterial);
//单独设定属性
// materialSphere.setProperty;
//获取所有属性
// materialSphere.getAllProperty();、
//更换所有属性
// materialSphere.updateMaterialOptions({
// color: 0xffffff, // 设置材质颜色
// roughness: 0, // 设置粗糙度
// metalness: 0.5, // 设置金属度
// opacity: 1, // 设置材质透明度
// transparent: true, // 设置材质是否透明
// side: THREE.DoubleSide, // 设置材质的两面
// depthTest: true, // 设置深度检测
// depthWrite: true, // 设置深度写入
// map: "/textures/earth.jpg",
// });