Skip to content

92. 实战:Three.js Editor(九)

Published:

这节我们来写最后一块功能:

2025-05-17 19.17.56.gif

物体属性的编辑,比如 geometry、material。

创建一个新组件:

Properties/Info.jsx

import { useThreeStore } from "../../store";

function Info() {

    const { selectedObj } = useThreeStore();

    return <div className='Info'>
        { selectedObj?.isMesh ?
            <div>
                <div>几何体: {selectedObj.geometry.type}</div>
                <div>材质: {selectedObj.material.type}</div>
            </div>
            : null
        }
    </div>
}

export default Info;

从 store 取出 selectedObj,如果它是 mesh,就分别展示下几何体、材质。

在 Properties/index.jsx 引入下:

image.png

看下效果:

2025-05-17 20.19.13.gif

这样,切换选中对象的时候,就会在 Info 组件里展示详细信息。

我们来做属性的展示和编辑:

我们只实现部分属性,其他属性的编辑也是一样,可以自己扩展

首先,我们要在 store 里添加一个修改 material 的方法:

image.png

和之前修改 position 差不多,只不过这次修改的是 material

updateMaterial(name, info) {
    set(state => {
        return {
            data: {
                ...state.data,
                meshArr: state.data.meshArr.map(mesh => {
                    if(mesh.name === name) {                                
                        mesh.props.material = {
                            ...mesh.props.material,
                            ...info
                        }
                    }
                    return mesh;
                })
            }
        }
    })
},

然后改下 Properties/Info.jsx

用 Form 来展示属性,编辑之后调用 updateMaterial 来更新。

image.png

这里我们用 Form 来展示属性,设置初始数据,编辑后用 updateMaterial 更新 store 里的数据。

import { ColorPicker, Form, Input } from "antd";
import { useThreeStore } from "../../store";

function Info() {

    const { selectedObj, updateMaterial } = useThreeStore();

    function handleValuesChange(changeValues) {
        const colorStr = changeValues.color.toHexString();

        updateMaterial(selectedObj.name, {
            color: colorStr
        });
    }
    return <div className='Info' style={{margin: 20}}>
        { selectedObj?.isMesh ?
            <Form
                initialValues={{
                    color: selectedObj.material.color.getHexString()
                }}
                onValuesChange={handleValuesChange}
            >
                <Form.Item label="材质颜色" name="color">
                    <ColorPicker/>
                </Form.Item>
            </Form>
            : null
        }
    </div>
}

export default Info;

先把之前的 json 注释去掉:

image.png

看下效果:

2025-05-17 22.34.34.gif

可以看到,store 里已经改了。

但是渲染的时候没有设置,我们改一下:

image.png

mesh.material.color = new THREE.Color(color);

渲染的时候设置材质颜色为最新的颜色。

试一下:

2025-05-17 22.36.43.gif

这样,属性修改就完成了。

其余的属性也是一样的,大家可以自己扩展。

现在有个问题:

2025-05-17 22.50.52.gif

切换选中的对象的时候,表单颜色没有跟着变。

这个同步下就好了:

image.png

const [form] = useForm();
    
useEffect(() => {
    if(selectedObj?.isMesh) {
        form.setFieldValue('color', selectedObj.material.color.getHexString())
    }
}, [selectedObj]);

用 useForm 的 api 来操作表单。

在 selectedObj 变化的时候,设置 color 的值为选中的物体的材质颜色。

2025-05-17 22.53.34.gif

案例代码上传了小册仓库

总结

这节我们实现了属性编辑。

其实就是选中对象的时候,把它的信息展示出来。

然后可以通过表单修改属性的值,把它同步更改到 json。

这样再次渲染的时候,修改的属性就生效了。

各种属性的编辑原理都一样。

评论