feat(web): add view layer lightgroup authoring
This commit is contained in:
@@ -956,6 +956,7 @@ function Properties({ snapshot, selectedFaceIndices, selectedVertexIndices, grea
|
||||
{activeScene ? <div className="property-section" data-testid="scene-bindings-workbench"><h3>Scene Bindings</h3><output>Camera {activeScene.cameraObjectId ?? "None"} · World {activeScene.worldId ?? "None"}</output><div className="property-actions"><button type="button" disabled={!snapshot?.nodes.some((node) => node.id === activeScene.cameraObjectId && node.type === "CAMERA")} onClick={() => onCommand(animationRenderCommands.setSceneBindings(activeScene.id, { cameraObjectId: activeScene.cameraObjectId }))}>确认相机绑定</button><button type="button" disabled={!activeWorld} onClick={() => onCommand(animationRenderCommands.setSceneBindings(activeScene.id, { worldId: activeWorld?.id ?? null }))}>绑定当前世界</button></div></div> : null}
|
||||
{activeScene?.viewLayers?.length ? <div className="property-section" data-testid="scene-view-layer-settings-workbench"><h3>View Layers</h3>{activeScene.viewLayers.map((layer) => <div key={layer.name}><output>{layer.name} · {layer.useRender ? "Render" : "Disabled"} · {layer.useFreestyle ? "Freestyle" : "No Freestyle"} · {layer.samples} samples</output><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneViewLayerSettings(activeScene.id, layer.name, { useRender: !layer.useRender }))}>切换渲染</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneViewLayerSettings(activeScene.id, layer.name, { samples: Math.min(1000000, layer.samples + 1) }))}>增加采样</button></div>)}</div> : null}
|
||||
{activeScene?.viewLayers?.filter((layer) => layer.aovs?.length).map((layer) => <div className="property-section" data-testid="scene-view-layer-aov-workbench" key={`aovs-${layer.name}`}><h3>{layer.name} AOVs</h3>{layer.aovs?.map((aov) => <output key={aov.name}>{aov.name} · {aov.type === 1 ? "Color" : "Value"}</output>)}<button type="button" onClick={() => onCommand(animationRenderCommands.setSceneViewLayerAOVs(activeScene.id, layer.name, [...(layer.aovs ?? []).map((aov) => ({ name: aov.name, type: (aov.type === 1 ? 1 : 0) as 0 | 1 })), { name: `AOV_${(layer.aovs?.length ?? 0) + 1}`, type: 1 }]))}>Add Color AOV</button></div>) ?? null}
|
||||
{activeScene?.viewLayers?.filter((layer) => layer.lightgroups?.length).map((layer) => <div className="property-section" data-testid="scene-view-layer-lightgroup-workbench" key={`lightgroups-${layer.name}`}><h3>{layer.name} Lightgroups</h3>{layer.lightgroups?.map((group) => <output key={group}>{group}</output>)}<button type="button" onClick={() => onCommand(animationRenderCommands.setSceneViewLayerLightgroups(activeScene.id, layer.name, [...(layer.lightgroups ?? []), `Lightgroup_${(layer.lightgroups?.length ?? 0) + 1}`]))}>Add Lightgroup</button></div>) ?? null}
|
||||
{activeScene?.simplifySettings ? <div className="property-section" data-testid="scene-simplify-settings-workbench"><h3>Render Simplify</h3><output>Subdivision {activeScene.simplifySettings.subsurfViewport} / {activeScene.simplifySettings.subsurfRender} · Particles {activeScene.simplifySettings.particlesViewport.toFixed(2)} / {activeScene.simplifySettings.particlesRender.toFixed(2)} · Volumes {activeScene.simplifySettings.volumes.toFixed(2)}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSimplifySettings(activeScene.id, { subsurfViewport: Math.max(0, activeScene.simplifySettings!.subsurfViewport - 1) }))}>降低细分</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSimplifySettings(activeScene.id, { particlesViewport: Math.max(0, activeScene.simplifySettings!.particlesViewport - 0.1), volumes: Math.max(0, activeScene.simplifySettings!.volumes - 0.1) }))}>降低复杂度</button></div></div> : null}
|
||||
{activeFont ? <div className="property-section" data-testid="font-workbench"><h3>Font</h3><label>Text <textarea aria-label="Font body" value={fontBody} maxLength={65536} onChange={(event) => setFontBody(event.target.value)} /></label><div className="property-actions"><button type="button" disabled={fontBody === activeFont.text} onClick={() => onCommand(nonMeshGeometryCommands.setFontBody(activeFont.id, fontBody))}>Apply Text</button>{activeFont.fontProperties ? <button type="button" onClick={() => onCommand(nonMeshGeometryCommands.setFontProperties(activeFont.id, { extrude: Math.min(1000, activeFont.fontProperties!.extrude + 0.01) }))}>Increase Extrude</button> : null}</div><output>{activeFont.text?.length ?? 0} characters</output></div> : null}
|
||||
{activeVolume ? <div className="property-section" data-testid="volume-workbench"><h3>Volume</h3><output>{activeVolume.sourcePath ?? "No source path"}</output><output>{activeVolume.volumeGrids?.length ?? 0} grids</output>{activeVolume.volumeProperties ? <><output>Density {activeVolume.volumeProperties.displayDensity.toFixed(3)} · Step {activeVolume.volumeProperties.stepSize.toFixed(4)}</output><div className="property-actions"><button type="button" onClick={() => onCommand(nonMeshGeometryCommands.setVolumeProperties(activeVolume.id, activeVolume.sourcePath ?? "", Math.min(1e6, activeVolume.volumeProperties!.displayDensity + 0.1), activeVolume.volumeProperties!.interpolation, activeVolume.volumeProperties!.stepSize))}>Increase Density</button><button type="button" onClick={() => onCommand(nonMeshGeometryCommands.setVolumeProperties(activeVolume.id, activeVolume.sourcePath ?? "", activeVolume.volumeProperties!.displayDensity, activeVolume.volumeProperties!.interpolation === "LINEAR" ? "NEAREST" : "LINEAR", activeVolume.volumeProperties!.stepSize))}>Toggle Interpolation</button></div></> : <output>Volume properties unavailable</output>}</div> : null}
|
||||
|
||||
BIN
web/app/src/vendor/blender/web_engine.wasm
vendored
BIN
web/app/src/vendor/blender/web_engine.wasm
vendored
Binary file not shown.
@@ -821,6 +821,13 @@ function assertFutureCapability(payload: Extract<WebEngineRequest["command"], {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "setSceneViewLayerLightgroups": {
|
||||
const scene = currentSnapshot?.scenes.find((candidate) => candidate.id === payload.dataId);
|
||||
if (!scene || typeof payload.layerName !== "string" || payload.layerName.length === 0 || !Array.isArray(payload.lightgroups) || payload.lightgroups.length > 128) throw report("RENDER_PROPERTY_INVALID", "Scene ViewLayer lightgroup target is invalid");
|
||||
const names = new Set<string>();
|
||||
for (const name of payload.lightgroups) { if (typeof name !== "string" || name.length === 0 || new TextEncoder().encode(name).byteLength > 63 || names.has(name)) throw report("RENDER_PROPERTY_INVALID", "Scene lightgroup names must be unique and bounded"); names.add(name); }
|
||||
return;
|
||||
}
|
||||
case "setGeometryNodeGraph": {
|
||||
const snapshot = currentSnapshot;
|
||||
const availableResourceIds = new Set([
|
||||
|
||||
Reference in New Issue
Block a user