• 作者:老汪软件技巧
  • 发表时间:2024-11-17 04:01
  • 浏览量:

EdgeSplitModifier 是 Three.js 中用于分割网格的边缘,以便对具有较大角度的相邻面进行处理,使它们拥有独立的法线,解决法线平滑和光照不自然的问题。这个修饰符常用于在模型中创建硬边效果,特别是在需要表现出锐利边缘的几何体(例如机械零件、建筑等)时。

EdgeSplitModifier 有一个方法


    EdgeSplitModifier()
    创建一个新的EdgeSplitModifier对象。
    // 创建一个 IcosahedronGeometry 几何体
    const geometry = new THREE.IcosahedronGeometry(10, 3);
    // 创建一个 MeshPhongMaterial 材质
    const material = new THREE.MeshPhongMaterial({ color: 0x00ff00, flatShading: true });
    const mesh = new THREE.Mesh(geometry, material);  // 使用修改后的几何体创建网格
    mesh.castShadow = true;
    mesh.receiveShadow = true;
    // 将网格添加到场景中
    scene.add(mesh);
    // 从上方照射的白色平行光,强度为 0.5。
    const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
    directionalLight.position.set(0, 50, 0);
    directionalLight.castShadow = true; 
    scene.add( directionalLight );
    // 添加环境光来补充场景的整体光照 使得反光物体能显示
    const ambientLight = new THREE.AmbientLight(0x404040); // 环境光
    scene.add(ambientLight);

方法

主要作用分割边缘:控制切割角度:法线处理:适用场景:观察效果:

在 3D 图形学中,硬边(Hard Edges)指的是一个几何体中相邻的两个面之间具有显著的角度差,从而形成一种明显的锐利边界效果。这种边界通常使几何体看起来更加棱角分明,而不是光滑连续的。在示例中 当 cutOffAngle 接近 180 时边角会滑些,为0时边角较明显

    // 声明一些变量,包括材质、修改器、网格和基础几何体
    let map, modifier, mesh, baseGeometry;
    // 参数配置对象,控制是否应用平滑着色、边缘分割、切割角度等
    const params = {
        smoothShading: true,        // 是否启用平滑着色
        edgeSplit: true,            // 是否启用边缘分割
        cutOffAngle: 20,            // 切割角度,单位为度
        showMap: false,             // 是否显示纹理贴图
        tryKeepNormals: true,       // 是否保留法线
    };
    // 添加环境光,提供基础的光照
    scene.add( new THREE.HemisphereLight( 0xffffff, 0x444444, 3 ) );
    // 使用 OBJLoader 加载一个 Cerberus 模型
    new OBJLoader().load(
        'https://raw.githubusercontent.com/mrdoob/three.js/refs/heads/master/examples/models/obj/cerberus/Cerberus.obj',
        function ( group ) {
            // 获取加载的模型的几何体
            const cerberus = group.children[ 0 ];
            const modelGeometry = cerberus.geometry;
            // 初始化边缘分割修改器
            modifier = new EdgeSplitModifier();
            // 合并几何体的重复顶点(优化几何体)
            baseGeometry = BufferGeometryUtils.mergeVertices( modelGeometry );
            // 创建网格并设置初始材质
            mesh = new THREE.Mesh( getGeometry(), new THREE.MeshStandardMaterial() );
            // 根据平滑着色选项设置材质的 flatShading 属性
            mesh.material.flatShading = ! params.smoothShading;
            // 旋转模型,使其正确朝向
            mesh.rotateY( - Math.PI / 2 );
            // 设置模型的缩放和位移
            mesh.scale.set( 3.5, 3.5, 3.5 );
            mesh.translateZ( 1.5 );
            // 将网格添加到场景中
            scene.add( mesh );
            // 如果设置了显示纹理,并且纹理已经加载,应用纹理到网格
            if ( map !== undefined && params.showMap ) {

评价人生价值的方法有_灭火的基本方法有_

mesh.material.map = map; mesh.material.needsUpdate = true; } // 执行渲染 render(); } ); // 加载纹理贴图 new THREE.TextureLoader().load( 'https://raw.githubusercontent.com/mrdoob/three.js/refs/heads/master/examples/models/obj/cerberus/Cerberus_A.jpg', function ( texture ) { // 加载纹理并设置颜色空间 map = texture; map.colorSpace = THREE.SRGBColorSpace; // 如果网格已经创建,并且需要显示纹理,更新网格的材质 if ( mesh !== undefined && params.showMap ) { mesh.material.map = map; mesh.material.needsUpdate = true; } }); // 更新网格的几何体和材质 function updateMesh() { // 切换切割角度的值(0 或 180) params.cutOffAngle = params.cutOffAngle == 0 ? 180 : 0; // 如果网格存在,更新其几何体和材质 if ( mesh !== undefined ) { // 获取新的几何体 mesh.geometry = getGeometry(); // 检查材质是否需要更新 let needsUpdate = mesh.material.flatShading === params.smoothShading; // 根据平滑着色参数调整材质的 flatShading 属性 mesh.material.flatShading = params.smoothShading === false; // 如果纹理存在,并且显示纹理的选项被启用,更新纹理 if ( map !== undefined ) { needsUpdate = needsUpdate || mesh.material.map !== ( params.showMap ? map : null ); mesh.material.map = params.showMap ? map : null; } // 更新材质 mesh.material.needsUpdate = needsUpdate; } } // 绑定 DOM 元素点击事件,点击时更新网格 DOMEl.onclick = () => { updateMesh(); } // 根据参数选择是否应用边缘分割,返回相应的几何体 function getGeometry() { let geometry; // 如果启用了边缘分割,应用 EdgeSplitModifier if ( params.edgeSplit ) { geometry = modifier.modify( baseGeometry, params.cutOffAngle * Math.PI / 180, // 将角度转为弧度 params.tryKeepNormals // 保留法线选项 ); } else { geometry = baseGeometry; // 否则使用原始几何体 } return geometry; }