feat(all): 后处理迁移
This commit is contained in:
parent
986da8ce42
commit
4cc239d660
@ -226,6 +226,27 @@ export default {
|
|||||||
"Post processing": "后期处理",
|
"Post processing": "后期处理",
|
||||||
postProcessing: {
|
postProcessing: {
|
||||||
"Anti-aliasing": "抗锯齿",
|
"Anti-aliasing": "抗锯齿",
|
||||||
|
"Quality Preset": "质量预设",
|
||||||
|
"Tone Mapping": "色调映射",
|
||||||
|
"Exposure": "曝光度",
|
||||||
|
"SSAO": "环境光遮蔽",
|
||||||
|
"Samples": "采样数",
|
||||||
|
"Rings": "环数",
|
||||||
|
"Bias": "偏置",
|
||||||
|
"Fade": "衰减",
|
||||||
|
"Luminance Influence": "亮度影响",
|
||||||
|
"Min Radius Scale": "最小半径缩放",
|
||||||
|
"Depth-aware Upsampling": "深度感知上采样",
|
||||||
|
"Distance Threshold": "距离阈值",
|
||||||
|
"Distance Falloff": "距离衰减",
|
||||||
|
"Range Threshold": "范围阈值",
|
||||||
|
"Range Falloff": "范围衰减",
|
||||||
|
"World Distance Threshold": "世界距离阈值",
|
||||||
|
"World Distance Falloff": "世界距离衰减",
|
||||||
|
"World Proximity Threshold": "世界邻近阈值",
|
||||||
|
"World Proximity Falloff": "世界邻近衰减",
|
||||||
|
"Colorize": "颜色化",
|
||||||
|
"AO Color": "遮蔽颜色",
|
||||||
"Outline": "描边线",
|
"Outline": "描边线",
|
||||||
"Edge Strength": "边缘强度",
|
"Edge Strength": "边缘强度",
|
||||||
"Edge Glow": "边缘发光",
|
"Edge Glow": "边缘发光",
|
||||||
@ -237,6 +258,57 @@ export default {
|
|||||||
"Radius": "半径",
|
"Radius": "半径",
|
||||||
"Threshold": "阈值",
|
"Threshold": "阈值",
|
||||||
"Strength": "强度",
|
"Strength": "强度",
|
||||||
|
"Brightness Contrast": "亮度对比度",
|
||||||
|
"Brightness": "亮度",
|
||||||
|
"Contrast": "对比度",
|
||||||
|
"Chromatic Aberration": "色差",
|
||||||
|
"Offset X": "偏移 X",
|
||||||
|
"Offset Y": "偏移 Y",
|
||||||
|
"Radial Modulation": "径向调制",
|
||||||
|
"Modulation Offset": "调制偏移",
|
||||||
|
"Color Depth": "色深",
|
||||||
|
"Bits": "位数",
|
||||||
|
"Hue Saturation": "色相饱和度",
|
||||||
|
"Hue": "色相",
|
||||||
|
"Saturation": "饱和度",
|
||||||
|
"Tilt Shift": "移轴模糊",
|
||||||
|
"Offset": "偏移",
|
||||||
|
"Rotation": "旋转",
|
||||||
|
"Focus Area": "焦点区域",
|
||||||
|
"Feather": "羽化",
|
||||||
|
"Scanline": "扫描线",
|
||||||
|
"Density": "密度",
|
||||||
|
"Scroll Speed": "滚动速度",
|
||||||
|
"Glitch": "故障",
|
||||||
|
"Glitch Mode": "故障模式",
|
||||||
|
"Sporadic": "偶发",
|
||||||
|
"Constant Mild": "持续轻微",
|
||||||
|
"Constant Wild": "持续剧烈",
|
||||||
|
"Delay Min": "延迟最小值",
|
||||||
|
"Delay Max": "延迟最大值",
|
||||||
|
"Duration Min": "持续最小值",
|
||||||
|
"Duration Max": "持续最大值",
|
||||||
|
"Strength Min": "强度最小值",
|
||||||
|
"Strength Max": "强度最大值",
|
||||||
|
"Ratio": "出现概率",
|
||||||
|
"Lens Distortion": "镜头畸变",
|
||||||
|
"Distortion X": "畸变 X",
|
||||||
|
"Distortion Y": "畸变 Y",
|
||||||
|
"Principal Point X": "主点 X",
|
||||||
|
"Principal Point Y": "主点 Y",
|
||||||
|
"Focal Length X": "焦距 X",
|
||||||
|
"Focal Length Y": "焦距 Y",
|
||||||
|
"Skew": "倾斜",
|
||||||
|
"Shock Wave": "冲击波",
|
||||||
|
"Click on scene to trigger shock wave effect": "点击场景触发冲击波效果",
|
||||||
|
"Amplitude": "振幅",
|
||||||
|
"Wave Size": "波浪大小",
|
||||||
|
"Speed": "传播速度",
|
||||||
|
"Max Radius": "最大半径",
|
||||||
|
"Click Trigger": "点击触发",
|
||||||
|
"Vignette": "暗角",
|
||||||
|
"Darkness": "暗度",
|
||||||
|
"Blend Function": "混合模式",
|
||||||
"LUT Color filter":"LUT 颜色滤镜",
|
"LUT Color filter":"LUT 颜色滤镜",
|
||||||
"Intensity":"强度",
|
"Intensity":"强度",
|
||||||
"Afterimage":"运动残影",
|
"Afterimage":"运动残影",
|
||||||
@ -245,6 +317,7 @@ export default {
|
|||||||
"Focus": "焦距",
|
"Focus": "焦距",
|
||||||
"Aperture": "孔径",
|
"Aperture": "孔径",
|
||||||
"MaxBlur": "最大模糊",
|
"MaxBlur": "最大模糊",
|
||||||
|
"Resolution Scale": "分辨率缩放",
|
||||||
"Pixelate": "像素风",
|
"Pixelate": "像素风",
|
||||||
"PixelSize": "像素大小",
|
"PixelSize": "像素大小",
|
||||||
"NormalEdgeStrength": "法向边缘强度",
|
"NormalEdgeStrength": "法向边缘强度",
|
||||||
@ -747,6 +820,7 @@ export default {
|
|||||||
Open: "开启",
|
Open: "开启",
|
||||||
Close: "关闭",
|
Close: "关闭",
|
||||||
Enable: "启用",
|
Enable: "启用",
|
||||||
|
Enabled: "启用",
|
||||||
Minimum: "最小值",
|
Minimum: "最小值",
|
||||||
Maximum: "最大值",
|
Maximum: "最大值",
|
||||||
Width: "宽度",
|
Width: "宽度",
|
||||||
|
|||||||
48
packages/editor/src/utils/common/postprocessing.ts
Normal file
48
packages/editor/src/utils/common/postprocessing.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { t } from "@/language";
|
||||||
|
|
||||||
|
// Blend mode options for post-processing blendFunction config.
|
||||||
|
const BLEND_FUNCTION_KEYS = [
|
||||||
|
"NORMAL",
|
||||||
|
"ADD",
|
||||||
|
"ALPHA",
|
||||||
|
"AVERAGE",
|
||||||
|
"COLOR",
|
||||||
|
"COLOR_BURN",
|
||||||
|
"COLOR_DODGE",
|
||||||
|
"DARKEN",
|
||||||
|
"DIFFERENCE",
|
||||||
|
"DIVIDE",
|
||||||
|
"DST",
|
||||||
|
"EXCLUSION",
|
||||||
|
"HARD_LIGHT",
|
||||||
|
"HARD_MIX",
|
||||||
|
"HUE",
|
||||||
|
"INVERT",
|
||||||
|
"INVERT_RGB",
|
||||||
|
"LIGHTEN",
|
||||||
|
"LINEAR_BURN",
|
||||||
|
"LINEAR_DODGE",
|
||||||
|
"LINEAR_LIGHT",
|
||||||
|
"LUMINOSITY",
|
||||||
|
"MULTIPLY",
|
||||||
|
"NEGATION",
|
||||||
|
"OVERLAY",
|
||||||
|
"PIN_LIGHT",
|
||||||
|
"REFLECT",
|
||||||
|
"SATURATION",
|
||||||
|
"SCREEN",
|
||||||
|
"SET",
|
||||||
|
"SOFT_LIGHT",
|
||||||
|
"SRC",
|
||||||
|
"SUBTRACT",
|
||||||
|
"VIVID_LIGHT",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const blendFunctionOptions = BLEND_FUNCTION_KEYS.map(k => ({ label: k, value: k }));
|
||||||
|
|
||||||
|
// Glitch mode options.
|
||||||
|
export const glitchModeOptions = [
|
||||||
|
{ label: t("layout.sider.postProcessing.Sporadic"), value: "SPORADIC" },
|
||||||
|
{ label: t("layout.sider.postProcessing.Constant Mild"), value: "CONSTANT_MILD" },
|
||||||
|
{ label: t("layout.sider.postProcessing.Constant Wild"), value: "CONSTANT_WILD" },
|
||||||
|
];
|
||||||
@ -3,26 +3,111 @@ import {onMounted, ref} from "vue";
|
|||||||
import { CaretForwardOutline } from "@vicons/ionicons5";
|
import { CaretForwardOutline } from "@vicons/ionicons5";
|
||||||
import { t } from "@/language";
|
import { t } from "@/language";
|
||||||
import { App } from "@astral3d/engine";
|
import { App } from "@astral3d/engine";
|
||||||
import OutLine from './effect/Sidebar.Effect.Outline.vue';
|
import OutLine from "./effect/Sidebar.Effect.Outline.vue";
|
||||||
import FXAA from './effect/Sidebar.Effect.FXAA.vue';
|
import SMAA from "./effect/Sidebar.Effect.SMAA.vue";
|
||||||
import UnrealBloom from './effect/Sidebar.Effect.UnrealBloom.vue';
|
import SSAO from "./effect/Sidebar.Effect.SSAO.vue";
|
||||||
import LUT from './effect/Sidebar.Effect.LUT.vue';
|
import UnrealBloom from "./effect/Sidebar.Effect.UnrealBloom.vue";
|
||||||
import Afterimage from './effect/Sidebar.Effect.Afterimage.vue';
|
import Bokeh from "./effect/Sidebar.Effect.Bokeh.vue";
|
||||||
import Bokeh from './effect/Sidebar.Effect.Bokeh.vue';
|
import Pixelate from "./effect/Sidebar.Effect.Pixelate.vue";
|
||||||
import Pixelate from './effect/Sidebar.Effect.Pixelate.vue';
|
import TiltShift from "./effect/Sidebar.Effect.TiltShift.vue";
|
||||||
import Halftone from './effect/Sidebar.Effect.Halftone.vue';
|
import Scanline from "./effect/Sidebar.Effect.Scanline.vue";
|
||||||
|
import BrightnessContrast from "./effect/Sidebar.Effect.BrightnessContrast.vue";
|
||||||
|
import ChromaticAberration from "./effect/Sidebar.Effect.ChromaticAberration.vue";
|
||||||
|
import ColorDepth from "./effect/Sidebar.Effect.ColorDepth.vue";
|
||||||
|
import Glitch from "./effect/Sidebar.Effect.Glitch.vue";
|
||||||
|
import HueSaturation from "./effect/Sidebar.Effect.HueSaturation.vue";
|
||||||
|
import LensDistortion from "./effect/Sidebar.Effect.LensDistortion.vue";
|
||||||
|
import ShockWave from "./effect/Sidebar.Effect.ShockWave.vue";
|
||||||
|
import ToneMapping from "./effect/Sidebar.Effect.ToneMapping.vue";
|
||||||
|
import Vignette from "./effect/Sidebar.Effect.Vignette.vue";
|
||||||
import EsTip from "@/components/es/EsTip.vue";
|
import EsTip from "@/components/es/EsTip.vue";
|
||||||
|
|
||||||
|
const effectDefaults: Record<string, any> = {
|
||||||
|
ToneMapping: { mode: "ACES_FILMIC", exposure: 1.0, blendFunction: "NORMAL" },
|
||||||
|
SMAA: { enabled: true, preset: "ULTRA" },
|
||||||
|
SSAO: {
|
||||||
|
enabled: true,
|
||||||
|
blendFunction: "MULTIPLY",
|
||||||
|
samples: 9,
|
||||||
|
rings: 7,
|
||||||
|
radius: 0.1825,
|
||||||
|
intensity: 1.0,
|
||||||
|
bias: 0.025,
|
||||||
|
fade: 0.01,
|
||||||
|
luminanceInfluence: 0.7,
|
||||||
|
minRadiusScale: 0.1,
|
||||||
|
depthAwareUpsampling: true,
|
||||||
|
resolutionScale: 0.5,
|
||||||
|
distanceThreshold: 0.97,
|
||||||
|
distanceFalloff: 0.03,
|
||||||
|
rangeThreshold: 0.0005,
|
||||||
|
rangeFalloff: 0.001,
|
||||||
|
worldDistanceThreshold: null,
|
||||||
|
worldDistanceFalloff: null,
|
||||||
|
worldProximityThreshold: null,
|
||||||
|
worldProximityFalloff: null,
|
||||||
|
colorEnabled: false,
|
||||||
|
color: "#000000",
|
||||||
|
},
|
||||||
|
TiltShift: { enabled: false, offset: 0.0, rotation: 0.0, focusArea: 0.4, feather: 0.3, blendFunction: "NORMAL" },
|
||||||
|
Scanline: { enabled: false, density: 1.25, scrollSpeed: 0.0, blendFunction: "OVERLAY" },
|
||||||
|
BrightnessContrast: { enabled: false, brightness: 0.0, contrast: 0.0, blendFunction: "SRC" },
|
||||||
|
ChromaticAberration: {
|
||||||
|
enabled: false,
|
||||||
|
offset: { x: 0.002, y: 0.002 },
|
||||||
|
radialModulation: false,
|
||||||
|
modulationOffset: 0.15,
|
||||||
|
blendFunction: "NORMAL",
|
||||||
|
},
|
||||||
|
ColorDepth: { enabled: false, bits: 16, blendFunction: "NORMAL" },
|
||||||
|
Glitch: {
|
||||||
|
enabled: false,
|
||||||
|
chromaticAberrationOffset: null,
|
||||||
|
delay: { min: 1.5, max: 3.5 },
|
||||||
|
duration: { min: 0.6, max: 1.0 },
|
||||||
|
strength: { min: 0.3, max: 1.0 },
|
||||||
|
mode: "SPORADIC",
|
||||||
|
ratio: 0.85,
|
||||||
|
blendFunction: "NORMAL",
|
||||||
|
},
|
||||||
|
HueSaturation: { enabled: false, hue: 0.0, saturation: 0.0, blendFunction: "SRC" },
|
||||||
|
LensDistortion: {
|
||||||
|
enabled: false,
|
||||||
|
distortion: { x: 0.0, y: 0.0 },
|
||||||
|
principalPoint: { x: 0.0, y: 0.0 },
|
||||||
|
focalLength: { x: 1.0, y: 1.0 },
|
||||||
|
skew: 0.0,
|
||||||
|
},
|
||||||
|
ShockWave: { enabled: false, amplitude: 0.05, waveSize: 0.2, speed: 2.0, maxRadius: 1.0, clickTrigger: true },
|
||||||
|
Vignette: { enabled: false, offset: 0.5, darkness: 0.5, blendFunction: "NORMAL" },
|
||||||
|
};
|
||||||
|
|
||||||
|
// 兼容旧项目配置缺失 effect 子项,避免子组件 setup 阶段 JSON.parse(undefined)
|
||||||
|
function ensureEffectDefaults() {
|
||||||
|
if (App.project.getKey("effect") === undefined) {
|
||||||
|
App.project.setKey("effect", { enabled: false }, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.entries(effectDefaults).forEach(([name, config]) => {
|
||||||
|
const key = `effect.${name}`;
|
||||||
|
if (App.project.getKey(key) === undefined) {
|
||||||
|
App.project.setKey(key, JSON.parse(JSON.stringify(config)), false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureEffectDefaults();
|
||||||
|
|
||||||
const effectEnabled = ref(App.project.getKey("effect.enabled"));
|
const effectEnabled = ref(App.project.getKey("effect.enabled"));
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const viewerLoaded = () => {
|
const viewerLoaded = () => {
|
||||||
effectEnabled.value = App.project.getKey("effect.enabled");
|
effectEnabled.value = App.project.getKey("effect.enabled");
|
||||||
|
|
||||||
window.viewer.removeEventListener('loaded', viewerLoaded);
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
}
|
};
|
||||||
window.viewer.addEventListener('loaded', viewerLoaded);
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
})
|
});
|
||||||
|
|
||||||
function handleEffectEnabledChange(value: boolean) {
|
function handleEffectEnabledChange(value: boolean) {
|
||||||
App.project.setKey("effect.enabled", value);
|
App.project.setKey("effect.enabled", value);
|
||||||
@ -31,7 +116,7 @@ function handleEffectEnabledChange(value:boolean){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h4>{{ t('layout.sider.Post processing') }}</h4>
|
<h4>{{ t("layout.sider.Post processing") }}</h4>
|
||||||
<n-switch v-model:value="effectEnabled" @update:value="handleEffectEnabledChange">
|
<n-switch v-model:value="effectEnabled" @update:value="handleEffectEnabledChange">
|
||||||
<template #checked>
|
<template #checked>
|
||||||
{{ t("other.Open") }}
|
{{ t("other.Open") }}
|
||||||
@ -44,7 +129,12 @@ function handleEffectEnabledChange(value:boolean){
|
|||||||
|
|
||||||
<n-divider class="!my-3" />
|
<n-divider class="!my-3" />
|
||||||
|
|
||||||
<n-collapse display-directive="show" :default-expanded-names="['Anti-aliasing','Outline','UnrealBloom']">
|
<!-- ToneMapping:色调映射 -->
|
||||||
|
<div class="px-2 mb-3">
|
||||||
|
<ToneMapping :effect-enabled="effectEnabled" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<n-collapse display-directive="show" :default-expanded-names="['Anti-aliasing', 'Outline']">
|
||||||
<template #arrow>
|
<template #arrow>
|
||||||
<n-icon>
|
<n-icon>
|
||||||
<CaretForwardOutline />
|
<CaretForwardOutline />
|
||||||
@ -53,10 +143,14 @@ function handleEffectEnabledChange(value:boolean){
|
|||||||
|
|
||||||
<!-- 抗锯齿 -->
|
<!-- 抗锯齿 -->
|
||||||
<n-collapse-item :title="t('layout.sider.postProcessing[\'Anti-aliasing\']')" name="Anti-aliasing">
|
<n-collapse-item :title="t('layout.sider.postProcessing[\'Anti-aliasing\']')" name="Anti-aliasing">
|
||||||
<FXAA :effect-enabled="effectEnabled" />
|
<SMAA :effect-enabled="effectEnabled" />
|
||||||
</n-collapse-item>
|
</n-collapse-item>
|
||||||
|
|
||||||
<!-- Outline:描边线 -->
|
<!-- Outline:描边线 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.SSAO')" name="SSAO">
|
||||||
|
<SSAO :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
<n-collapse-item :title="t('layout.sider.postProcessing.Outline')" name="Outline">
|
<n-collapse-item :title="t('layout.sider.postProcessing.Outline')" name="Outline">
|
||||||
<OutLine :effect-enabled="effectEnabled" />
|
<OutLine :effect-enabled="effectEnabled" />
|
||||||
</n-collapse-item>
|
</n-collapse-item>
|
||||||
@ -66,40 +160,74 @@ function handleEffectEnabledChange(value:boolean){
|
|||||||
<UnrealBloom :effect-enabled="effectEnabled" />
|
<UnrealBloom :effect-enabled="effectEnabled" />
|
||||||
</n-collapse-item>
|
</n-collapse-item>
|
||||||
|
|
||||||
<!-- LUT:颜色滤镜 -->
|
|
||||||
<n-collapse-item :title="t('layout.sider.postProcessing.LUT Color filter')" name="LUT">
|
|
||||||
<LUT :effect-enabled="effectEnabled" />
|
|
||||||
</n-collapse-item>
|
|
||||||
|
|
||||||
<!-- 运动残影 -->
|
|
||||||
<n-collapse-item :title="t('layout.sider.postProcessing.Afterimage')" name="Afterimage">
|
|
||||||
<Afterimage :effect-enabled="effectEnabled" />
|
|
||||||
</n-collapse-item>
|
|
||||||
|
|
||||||
<!-- Bokeh:变焦 -->
|
<!-- Bokeh:变焦 -->
|
||||||
<n-collapse-item :title="t('layout.sider.postProcessing.Bokeh')" name="Bokeh">
|
<n-collapse-item :title="t('layout.sider.postProcessing.Bokeh')" name="Bokeh">
|
||||||
<Bokeh :effect-enabled="effectEnabled" />
|
<Bokeh :effect-enabled="effectEnabled" />
|
||||||
</n-collapse-item>
|
</n-collapse-item>
|
||||||
|
|
||||||
<!-- Pixelate:像素风 -->
|
<!-- Pixelate:像素风 -->
|
||||||
<n-collapse-item name="Pixelate">
|
<n-collapse-item :title="t(`layout.sider.postProcessing.Pixelate`)" name="Pixelate">
|
||||||
|
<Pixelate :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- TiltShift:移轴模糊 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Tilt Shift')" name="TiltShift">
|
||||||
|
<TiltShift :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- Scanline:扫描线 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Scanline')" name="Scanline">
|
||||||
|
<Scanline :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- BrightnessContrast:亮度对比度 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Brightness Contrast')" name="BrightnessContrast">
|
||||||
|
<BrightnessContrast :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- ChromaticAberration:色差 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Chromatic Aberration')" name="ChromaticAberration">
|
||||||
|
<ChromaticAberration :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- ColorDepth:色深 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Color Depth')" name="ColorDepth">
|
||||||
|
<ColorDepth :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- Glitch:故障 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Glitch')" name="Glitch">
|
||||||
|
<Glitch :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- HueSaturation:色相饱和度 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Hue Saturation')" name="HueSaturation">
|
||||||
|
<HueSaturation :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- LensDistortion:镜头畸变 -->
|
||||||
|
<n-collapse-item :title="t('layout.sider.postProcessing.Lens Distortion')" name="LensDistortion">
|
||||||
|
<LensDistortion :effect-enabled="effectEnabled" />
|
||||||
|
</n-collapse-item>
|
||||||
|
|
||||||
|
<!-- ShockWave:冲击波 -->
|
||||||
|
<n-collapse-item name="ShockWave">
|
||||||
<template #header>
|
<template #header>
|
||||||
<n-text>
|
<n-text>
|
||||||
<EsTip class="!justify-start" :content="t(`layout.sider.postProcessing.Pixelate`)">
|
<EsTip class="!justify-start" :content="t(`layout.sider.postProcessing.Shock Wave`)">
|
||||||
{{ t(`layout.sider.postProcessing.Use a solid color background to achieve the best rendering effect`) }}
|
{{ t(`layout.sider.postProcessing.Click on scene to trigger shock wave effect`) }}
|
||||||
</EsTip>
|
</EsTip>
|
||||||
</n-text>
|
</n-text>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<Pixelate :effect-enabled="effectEnabled" />
|
<ShockWave :effect-enabled="effectEnabled" />
|
||||||
</n-collapse-item>
|
</n-collapse-item>
|
||||||
|
|
||||||
<!-- Halftone:半色调 -->
|
<!-- Vignette:晕影 -->
|
||||||
<n-collapse-item :title="t('layout.sider.postProcessing.Halftoning')" name="Halftoning">
|
<n-collapse-item :title="t('layout.sider.postProcessing.Vignette')" name="Vignette">
|
||||||
<Halftone :effect-enabled="effectEnabled" />
|
<Vignette :effect-enabled="effectEnabled" />
|
||||||
</n-collapse-item>
|
</n-collapse-item>
|
||||||
</n-collapse>
|
</n-collapse>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less"></style>
|
||||||
</style>
|
|
||||||
@ -28,7 +28,7 @@ function handleAfterimageConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="afterimage.enabled" :disabled="!effectEnabled" @update:checked="handleAfterimageConfigChange"/>
|
<n-checkbox size="small" v-model:checked="afterimage.enabled" :disabled="!effectEnabled" @update:checked="handleAfterimageConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -46,3 +46,4 @@ function handleAfterimageConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ function handleBokehConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="bokeh.enabled" :disabled="!effectEnabled" @update:checked="handleBokehConfigChange"/>
|
<n-checkbox size="small" v-model:checked="bokeh.enabled" :disabled="!effectEnabled" @update:checked="handleBokehConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -63,3 +63,4 @@ function handleBokehConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const bc = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.BrightnessContrast"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !bc.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(bc, App.project.getKey("effect.BrightnessContrast"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.BrightnessContrast`, toRaw(bc));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="bc.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 亮度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Brightness`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="bc.brightness" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 对比度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Contrast`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="bc.contrast" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select size="small" v-model:value="bc.blendFunction" :options="blendFunctionOptions" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const ca = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.ChromaticAberration"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !ca.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(ca, App.project.getKey("effect.ChromaticAberration"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.ChromaticAberration`, toRaw(ca));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="ca.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 偏移 X -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Offset X`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ca.offset.x" :step="0.001" :min="0" :max="0.05" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 偏移 Y -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Offset Y`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ca.offset.y" :step="0.001" :min="0" :max="0.05" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 径向调制 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Radial Modulation`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="ca.radialModulation" :disabled="disabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 调制偏移 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Modulation Offset`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ca.modulationOffset" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select size="small" v-model:value="ca.blendFunction" :options="blendFunctionOptions" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const colorDepth = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.ColorDepth"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !colorDepth.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(colorDepth, App.project.getKey("effect.ColorDepth"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.ColorDepth`, toRaw(colorDepth));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="colorDepth.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 色深位数 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Bits`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="colorDepth.bits" :step="1" :min="1" :max="32" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select v-model:value="colorDepth.blendFunction" :options="blendFunctionOptions" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ function handleFXAAConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="faxx.enabled" :disabled="!effectEnabled" @update:checked="handleFXAAConfigChange"/>
|
<n-checkbox size="small" v-model:checked="faxx.enabled" :disabled="!effectEnabled" @update:checked="handleFXAAConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -37,3 +37,4 @@ function handleFXAAConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,121 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions, glitchModeOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const glitch = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.Glitch"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !glitch.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(glitch, App.project.getKey("effect.Glitch"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.Glitch`, toRaw(glitch));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="glitch.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 故障模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Glitch Mode`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select v-model:value="glitch.mode" :options="glitchModeOptions" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 延迟最小值 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Delay Min`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="glitch.delay.min" :step="0.1" :min="0" :max="5" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 延迟最大值 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Delay Max`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="glitch.delay.max" :step="0.1" :min="0" :max="10" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 持续时间最小值 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Duration Min`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="glitch.duration.min" :step="0.1" :min="0" :max="2" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 持续时间最大值 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Duration Max`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="glitch.duration.max" :step="0.1" :min="0" :max="5" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 强度最小值 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Strength Min`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="glitch.strength.min" :step="0.1" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 强度最大值 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Strength Max`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="glitch.strength.max" :step="0.1" :min="0" :max="2" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 故障比率 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Ratio`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="glitch.ratio" :step="0.05" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select
|
||||||
|
size="small"
|
||||||
|
v-model:value="glitch.blendFunction"
|
||||||
|
:options="blendFunctionOptions"
|
||||||
|
:disabled="disabled"
|
||||||
|
@update:value="handleConfigChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ function handleHalftoneConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="halftone.enabled" :disabled="!effectEnabled" @update:checked="handleHalftoneConfigChange"/>
|
<n-checkbox size="small" v-model:checked="halftone.enabled" :disabled="!effectEnabled" @update:checked="handleHalftoneConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -121,3 +121,4 @@ function handleHalftoneConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const hueSat = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.HueSaturation"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !hueSat.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(hueSat, App.project.getKey("effect.HueSaturation"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.HueSaturation`, toRaw(hueSat));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="hueSat.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 色相 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Hue`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="hueSat.hue" :step="0.01" :min="-3.14" :max="3.14" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 饱和度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Saturation`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="hueSat.saturation" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select v-model:value="hueSat.blendFunction" :options="blendFunctionOptions" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ function handleLUTConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="lut.enabled" :disabled="!effectEnabled" @update:checked="handleLUTConfigChange"/>
|
<n-checkbox size="small" v-model:checked="lut.enabled" :disabled="!effectEnabled" @update:checked="handleLUTConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -56,3 +56,4 @@ function handleLUTConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,98 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const lens = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.LensDistortion"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !lens.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(lens, App.project.getKey("effect.LensDistortion"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.LensDistortion`, toRaw(lens));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="lens.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 畸变 X -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Distortion X`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="lens.distortion.x" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 畸变 Y -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Distortion Y`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="lens.distortion.y" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主点 X -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Principal Point X`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="lens.principalPoint.x" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主点 Y -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Principal Point Y`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="lens.principalPoint.y" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 焦距 X -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Focal Length X`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="lens.focalLength.x" :step="0.1" :min="0.1" :max="5" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 焦距 Y -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Focal Length Y`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="lens.focalLength.y" :step="0.1" :min="0.1" :max="5" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 倾斜 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Skew`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="lens.skew" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ function handleOutlineConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="outline.enabled" :disabled="!effectEnabled" @update:checked="handleOutlineConfigChange"/>
|
<n-checkbox size="small" v-model:checked="outline.enabled" :disabled="!effectEnabled" @update:checked="handleOutlineConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -86,3 +86,4 @@ function handleOutlineConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ function handlePixelateConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="pixelate.enabled" :disabled="!effectEnabled" @update:checked="handlePixelateConfigChange"/>
|
<n-checkbox size="small" v-model:checked="pixelate.enabled" :disabled="!effectEnabled" @update:checked="handlePixelateConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -62,3 +62,4 @@ function handlePixelateConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,62 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// SMAA (Subpixel Morphological Anti-Aliasing) 替代 FXAA
|
||||||
|
const smaa = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.SMAA"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !smaa.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(smaa, App.project.getKey("effect.SMAA"));
|
||||||
|
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSMAAConfigChange() {
|
||||||
|
App.project.setKey(`effect.SMAA`, toRaw(smaa));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="smaa.enabled" :disabled="!effectEnabled" @update:checked="handleSMAAConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 质量预设 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Quality Preset`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select
|
||||||
|
v-model:value="smaa.preset"
|
||||||
|
:disabled="disabled"
|
||||||
|
@update:value="handleSMAAConfigChange"
|
||||||
|
:options="[
|
||||||
|
{ label: 'Low', value: 'LOW' },
|
||||||
|
{ label: 'Medium', value: 'MEDIUM' },
|
||||||
|
{ label: 'High', value: 'HIGH' },
|
||||||
|
{ label: 'Ultra', value: 'ULTRA' },
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,208 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const ssao = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.SSAO"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !ssao.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(ssao, App.project.getKey("effect.SSAO"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 世界空间阈值允许为空,这里在提交前归一化,避免 NaN 污染配置
|
||||||
|
function normalizeOptionalNumber(value: unknown): number | null {
|
||||||
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
ssao.worldDistanceThreshold = normalizeOptionalNumber(ssao.worldDistanceThreshold);
|
||||||
|
ssao.worldDistanceFalloff = normalizeOptionalNumber(ssao.worldDistanceFalloff);
|
||||||
|
ssao.worldProximityThreshold = normalizeOptionalNumber(ssao.worldProximityThreshold);
|
||||||
|
ssao.worldProximityFalloff = normalizeOptionalNumber(ssao.worldProximityFalloff);
|
||||||
|
|
||||||
|
App.project.setKey("effect.SSAO", toRaw(ssao));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="ssao.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select size="small" v-model:value="ssao.blendFunction" :options="blendFunctionOptions" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Samples`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.samples" :step="1" :min="1" :max="64" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Rings`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.rings" :step="1" :min="1" :max="32" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Radius`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.radius" :step="0.001" :min="0.01" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Strength`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.intensity" :step="0.01" :min="0" :max="5" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Bias`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.bias" :step="0.001" :min="0" :max="0.1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Fade`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.fade" :step="0.001" :min="0" :max="0.1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Luminance Influence`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.luminanceInfluence" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Min Radius Scale`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.minRadiusScale" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Depth-aware Upsampling`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="ssao.depthAwareUpsampling" :disabled="disabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Resolution Scale`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.resolutionScale" :step="0.05" :min="0.1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Distance Threshold`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.distanceThreshold" :step="0.001" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Distance Falloff`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.distanceFalloff" :step="0.001" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Range Threshold`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.rangeThreshold" :step="0.0001" :min="0" :max="0.02" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Range Falloff`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="ssao.rangeFalloff" :step="0.0001" :min="0" :max="0.02" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.World Distance Threshold`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-input-number v-model:value="ssao.worldDistanceThreshold" size="small" :min="0" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.World Distance Falloff`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-input-number v-model:value="ssao.worldDistanceFalloff" size="small" :min="0" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.World Proximity Threshold`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-input-number v-model:value="ssao.worldProximityThreshold" size="small" :min="0" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.World Proximity Falloff`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-input-number v-model:value="ssao.worldProximityFalloff" size="small" :min="0" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Colorize`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="ssao.colorEnabled" :disabled="disabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.AO Color`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-color-picker
|
||||||
|
v-model:value="ssao.color"
|
||||||
|
:show-alpha="false"
|
||||||
|
:modes="['hex']"
|
||||||
|
size="small"
|
||||||
|
:disabled="disabled || !ssao.colorEnabled"
|
||||||
|
@update:value="handleConfigChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const scanline = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.Scanline"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !scanline.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(scanline, App.project.getKey("effect.Scanline"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.Scanline`, toRaw(scanline));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="scanline.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 密度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Density`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="scanline.density" :step="0.05" :min="0.1" :max="5" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 滚动速度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Scroll Speed`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="scanline.scrollSpeed" :step="0.01" :min="0" :max="2" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select
|
||||||
|
size="small"
|
||||||
|
v-model:value="scanline.blendFunction"
|
||||||
|
:options="blendFunctionOptions"
|
||||||
|
:disabled="disabled"
|
||||||
|
@update:value="handleConfigChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const shockWave = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.ShockWave"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !shockWave.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(shockWave, App.project.getKey("effect.ShockWave"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.ShockWave`, toRaw(shockWave));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="shockWave.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 振幅 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Amplitude`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="shockWave.amplitude" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 波浪大小 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Wave Size`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="shockWave.waveSize" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 速度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Speed`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="shockWave.speed" :step="0.1" :min="0.1" :max="10" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 最大半径 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Max Radius`) }}</span>
|
||||||
|
<div>
|
||||||
|
<EsInputNumber
|
||||||
|
v-model:value="shockWave.maxRadius"
|
||||||
|
:show-button="false"
|
||||||
|
:decimal="1"
|
||||||
|
:min="0"
|
||||||
|
:max="100"
|
||||||
|
size="small"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="handleConfigChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 点击触发 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Click Trigger`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="shockWave.clickTrigger" :disabled="disabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
effectEnabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const tiltShift = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.TiltShift"))));
|
||||||
|
const disabled = computed(() => !props.effectEnabled || !tiltShift.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(tiltShift, App.project.getKey("effect.TiltShift"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.TiltShift`, toRaw(tiltShift));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="tiltShift.enabled" :disabled="!effectEnabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 焦点偏移 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Offset`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="tiltShift.offset" :step="0.01" :min="-1" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 旋转角度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Rotation`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="tiltShift.rotation" :step="0.01" :min="0" :max="6.28" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 焦点区域 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Focus Area`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="tiltShift.focusArea" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 羽化 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Feather`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="tiltShift.feather" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select
|
||||||
|
size="small"
|
||||||
|
v-model:value="tiltShift.blendFunction"
|
||||||
|
:options="blendFunctionOptions"
|
||||||
|
:disabled="disabled"
|
||||||
|
@update:value="handleConfigChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { h, onMounted, reactive, toRaw, VNode } from "vue";
|
||||||
|
import { SelectOption, NTooltip } from "naive-ui";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
const defaultToneMapping = {
|
||||||
|
mode: "ACES_FILMIC",
|
||||||
|
exposure: 1,
|
||||||
|
blendFunction: "NORMAL",
|
||||||
|
};
|
||||||
|
|
||||||
|
const toneMapping = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.ToneMapping") || defaultToneMapping)));
|
||||||
|
|
||||||
|
// 色调映射模式选项
|
||||||
|
const toneMappingModeOptions = [
|
||||||
|
{ label: "Linear", value: "LINEAR", tooltip: "线性映射,保持原始颜色" },
|
||||||
|
{ label: "Reinhard", value: "REINHARD", tooltip: "Reinhard 映射,柔和的高光压缩" },
|
||||||
|
{ label: "Reinhard2", value: "REINHARD2", tooltip: "改进的 Reinhard 映射" },
|
||||||
|
{ label: "Optimized Cineon", value: "OPTIMIZED_CINEON", tooltip: "优化的电影风格映射" },
|
||||||
|
{ label: "ACES Filmic", value: "ACES_FILMIC", tooltip: "电影工业标准 ACES 映射" },
|
||||||
|
{ label: "AgX", value: "AGX", tooltip: "AgX 映射,适合户外场景" },
|
||||||
|
{ label: "Neutral", value: "NEUTRAL", tooltip: "中性映射,平衡的色调" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const renderToneMappingOption = ({ node, option }: { node: VNode; option: SelectOption }) => {
|
||||||
|
return h(NTooltip, null, {
|
||||||
|
trigger: () => node,
|
||||||
|
default: () => (option as any).tooltip || option.label,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(toneMapping, App.project.getKey("effect.ToneMapping") || defaultToneMapping);
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.ToneMapping`, toRaw(toneMapping));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- 色调映射模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.rendererConfig.Tone mapping`) || "色调映射" }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select
|
||||||
|
v-model:value="toneMapping.mode"
|
||||||
|
:options="toneMappingModeOptions"
|
||||||
|
:render-option="renderToneMappingOption"
|
||||||
|
size="small"
|
||||||
|
@update:value="handleConfigChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 曝光度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Exposure`) || "曝光度" }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="toneMapping.exposure" :step="0.01" :min="0.1" :max="3" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select size="small" v-model:value="toneMapping.blendFunction" :options="blendFunctionOptions" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ function handleUnrealBloomConfigChange(){
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-config-item">
|
<div class="sidebar-config-item">
|
||||||
<span>{{ t(`other.Enable`) }}</span>
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
<div>
|
<div>
|
||||||
<n-checkbox size="small" v-model:checked="unrealBloom.enabled" :disabled="!effectEnabled" @update:checked="handleUnrealBloomConfigChange"/>
|
<n-checkbox size="small" v-model:checked="unrealBloom.enabled" :disabled="!effectEnabled" @update:checked="handleUnrealBloomConfigChange"/>
|
||||||
</div>
|
</div>
|
||||||
@ -62,3 +62,4 @@ function handleUnrealBloomConfigChange(){
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, reactive, toRaw } from "vue";
|
||||||
|
import { t } from "@/language";
|
||||||
|
import { App, Utils } from "@astral3d/engine";
|
||||||
|
import { blendFunctionOptions } from "../../../../../utils/common/postprocessing";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
effectEnabled: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const vignette = reactive(JSON.parse(JSON.stringify(App.project.getKey("effect.Vignette"))));
|
||||||
|
const disabled = computed(() => !vignette.enabled);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const viewerLoaded = () => {
|
||||||
|
Utils.deepAssign(vignette, App.project.getKey("effect.Vignette"));
|
||||||
|
window.viewer.removeEventListener("loaded", viewerLoaded);
|
||||||
|
};
|
||||||
|
window.viewer.addEventListener("loaded", viewerLoaded);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleConfigChange() {
|
||||||
|
App.project.setKey(`effect.Vignette`, toRaw(vignette));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`other.Enabled`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-checkbox size="small" v-model:checked="vignette.enabled" @update:checked="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 偏移 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t("layout.sider.postProcessing.Offset") }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="vignette.offset" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 暗度 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t("layout.sider.postProcessing.Darkness") }}</span>
|
||||||
|
<div>
|
||||||
|
<n-slider v-model:value="vignette.darkness" :step="0.01" :min="0" :max="1" :disabled="disabled" @update:value="handleConfigChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 混合模式 -->
|
||||||
|
<div class="sidebar-config-item">
|
||||||
|
<span>{{ t(`layout.sider.postProcessing.Blend Function`) }}</span>
|
||||||
|
<div>
|
||||||
|
<n-select
|
||||||
|
size="small"
|
||||||
|
v-model:value="vignette.blendFunction"
|
||||||
|
:options="blendFunctionOptions"
|
||||||
|
:disabled="disabled"
|
||||||
|
@update:value="handleConfigChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -41,6 +41,46 @@ export const defaultProjectInfo = (): IAppProject.Info => ({
|
|||||||
// 后处理
|
// 后处理
|
||||||
effect: {
|
effect: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
// 色调映射 (ToneMappingEffect)
|
||||||
|
ToneMapping: {
|
||||||
|
// 色调映射模式:LINEAR, REINHARD, REINHARD2, OPTIMIZED_CINEON, ACES_FILMIC, AGX, NEUTRAL
|
||||||
|
mode: "ACES_FILMIC",
|
||||||
|
// 曝光度
|
||||||
|
exposure: 1.0,
|
||||||
|
// 混合模式
|
||||||
|
blendFunction: "NORMAL"
|
||||||
|
},
|
||||||
|
// 抗锯齿 (SMAAEffect)
|
||||||
|
SMAA: {
|
||||||
|
enabled: true,
|
||||||
|
// 质量预设: LOW, MEDIUM, HIGH, ULTRA
|
||||||
|
preset: "ULTRA"
|
||||||
|
},
|
||||||
|
// 环境光遮蔽 (SSAOEffect)
|
||||||
|
SSAO: {
|
||||||
|
enabled: true,
|
||||||
|
blendFunction: "MULTIPLY",
|
||||||
|
samples: 9,
|
||||||
|
rings: 7,
|
||||||
|
radius: 0.1825,
|
||||||
|
intensity: 1.0,
|
||||||
|
bias: 0.025,
|
||||||
|
fade: 0.01,
|
||||||
|
luminanceInfluence: 0.7,
|
||||||
|
minRadiusScale: 0.1,
|
||||||
|
depthAwareUpsampling: true,
|
||||||
|
resolutionScale: 0.5,
|
||||||
|
distanceThreshold: 0.97,
|
||||||
|
distanceFalloff: 0.03,
|
||||||
|
rangeThreshold: 0.0005,
|
||||||
|
rangeFalloff: 0.001,
|
||||||
|
worldDistanceThreshold: null,
|
||||||
|
worldDistanceFalloff: null,
|
||||||
|
worldProximityThreshold: null,
|
||||||
|
worldProximityFalloff: null,
|
||||||
|
colorEnabled: false,
|
||||||
|
color: "#000000",
|
||||||
|
},
|
||||||
// 描边线
|
// 描边线
|
||||||
Outline: {
|
Outline: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -57,7 +97,14 @@ export const defaultProjectInfo = (): IAppProject.Info => ({
|
|||||||
// 可见边缘的颜色
|
// 可见边缘的颜色
|
||||||
visibleEdgeColor: "#ffee00",
|
visibleEdgeColor: "#ffee00",
|
||||||
// 不可见边缘的颜色
|
// 不可见边缘的颜色
|
||||||
hiddenEdgeColor: "#ff6a00"
|
hiddenEdgeColor: "#ff6a00",
|
||||||
|
// Astral postprocessing 兼容字段
|
||||||
|
pulseSpeed: 0.0,
|
||||||
|
xRay: true,
|
||||||
|
blur: true,
|
||||||
|
kernelSize: 1,
|
||||||
|
multisampling: 4,
|
||||||
|
blendFunction: "SCREEN"
|
||||||
},
|
},
|
||||||
// 抗锯齿
|
// 抗锯齿
|
||||||
FXAA: {
|
FXAA: {
|
||||||
@ -71,7 +118,14 @@ export const defaultProjectInfo = (): IAppProject.Info => ({
|
|||||||
// 光晕强度
|
// 光晕强度
|
||||||
strength: 1,
|
strength: 1,
|
||||||
// 光晕半径
|
// 光晕半径
|
||||||
radius: 0
|
radius: 0,
|
||||||
|
// Astral postprocessing 兼容字段
|
||||||
|
intensity: 1.0,
|
||||||
|
luminanceThreshold: 0.9,
|
||||||
|
luminanceSmoothing: 0.025,
|
||||||
|
levels: 8,
|
||||||
|
mipmapBlur: true,
|
||||||
|
blendFunction: "SCREEN"
|
||||||
},
|
},
|
||||||
// 背景虚化
|
// 背景虚化
|
||||||
Bokeh: {
|
Bokeh: {
|
||||||
@ -81,7 +135,12 @@ export const defaultProjectInfo = (): IAppProject.Info => ({
|
|||||||
// 孔径,类似相机孔径调节
|
// 孔径,类似相机孔径调节
|
||||||
aperture: 0.00005,
|
aperture: 0.00005,
|
||||||
// 最大模糊程度
|
// 最大模糊程度
|
||||||
maxblur: 0.01
|
maxblur: 0.01,
|
||||||
|
// Astral postprocessing 兼容字段
|
||||||
|
focusDistance: 10.0,
|
||||||
|
focusRange: 5.0,
|
||||||
|
bokehScale: 2.0,
|
||||||
|
resolutionScale: 0.5
|
||||||
},
|
},
|
||||||
// 像素风
|
// 像素风
|
||||||
Pixelate: {
|
Pixelate: {
|
||||||
@ -92,6 +151,87 @@ export const defaultProjectInfo = (): IAppProject.Info => ({
|
|||||||
normalEdgeStrength: 0.3,
|
normalEdgeStrength: 0.3,
|
||||||
// 深度边缘强度
|
// 深度边缘强度
|
||||||
depthEdgeStrength: 0.4,
|
depthEdgeStrength: 0.4,
|
||||||
|
// Astral postprocessing 兼容字段
|
||||||
|
granularity: 6,
|
||||||
|
},
|
||||||
|
// 移轴模糊 (TiltShiftEffect)
|
||||||
|
TiltShift: {
|
||||||
|
enabled: false,
|
||||||
|
offset: 0.0,
|
||||||
|
rotation: 0.0,
|
||||||
|
focusArea: 0.4,
|
||||||
|
feather: 0.3,
|
||||||
|
blendFunction: "NORMAL"
|
||||||
|
},
|
||||||
|
// 扫描线 (ScanlineEffect)
|
||||||
|
Scanline: {
|
||||||
|
enabled: false,
|
||||||
|
density: 1.25,
|
||||||
|
scrollSpeed: 0.0,
|
||||||
|
blendFunction: "OVERLAY"
|
||||||
|
},
|
||||||
|
// 亮度对比度 (BrightnessContrastEffect)
|
||||||
|
BrightnessContrast: {
|
||||||
|
enabled: false,
|
||||||
|
brightness: 0.0,
|
||||||
|
contrast: 0.0,
|
||||||
|
blendFunction: "SRC"
|
||||||
|
},
|
||||||
|
// 色差 (ChromaticAberrationEffect)
|
||||||
|
ChromaticAberration: {
|
||||||
|
enabled: false,
|
||||||
|
offset: { x: 0.002, y: 0.002 },
|
||||||
|
radialModulation: false,
|
||||||
|
modulationOffset: 0.15,
|
||||||
|
blendFunction: "NORMAL"
|
||||||
|
},
|
||||||
|
// 色深 (ColorDepthEffect)
|
||||||
|
ColorDepth: {
|
||||||
|
enabled: false,
|
||||||
|
bits: 16,
|
||||||
|
blendFunction: "NORMAL"
|
||||||
|
},
|
||||||
|
// 故障 (GlitchEffect)
|
||||||
|
Glitch: {
|
||||||
|
enabled: false,
|
||||||
|
chromaticAberrationOffset: null,
|
||||||
|
delay: { min: 1.5, max: 3.5 },
|
||||||
|
duration: { min: 0.6, max: 1.0 },
|
||||||
|
strength: { min: 0.3, max: 1.0 },
|
||||||
|
mode: "SPORADIC",
|
||||||
|
ratio: 0.85,
|
||||||
|
blendFunction: "NORMAL"
|
||||||
|
},
|
||||||
|
// 色相饱和度 (HueSaturationEffect)
|
||||||
|
HueSaturation: {
|
||||||
|
enabled: false,
|
||||||
|
hue: 0.0,
|
||||||
|
saturation: 0.0,
|
||||||
|
blendFunction: "SRC"
|
||||||
|
},
|
||||||
|
// 镜头畸变 (LensDistortionEffect)
|
||||||
|
LensDistortion: {
|
||||||
|
enabled: false,
|
||||||
|
distortion: { x: 0.0, y: 0.0 },
|
||||||
|
principalPoint: { x: 0.0, y: 0.0 },
|
||||||
|
focalLength: { x: 1.0, y: 1.0 },
|
||||||
|
skew: 0.0
|
||||||
|
},
|
||||||
|
// 冲击波 (ShockWaveEffect)
|
||||||
|
ShockWave: {
|
||||||
|
enabled: false,
|
||||||
|
amplitude: 0.05,
|
||||||
|
waveSize: 0.2,
|
||||||
|
speed: 2.0,
|
||||||
|
maxRadius: 1.0,
|
||||||
|
clickTrigger: true
|
||||||
|
},
|
||||||
|
// 暗角 (VignetteEffect)
|
||||||
|
Vignette: {
|
||||||
|
enabled: false,
|
||||||
|
offset: 0.5,
|
||||||
|
darkness: 0.5,
|
||||||
|
blendFunction: "NORMAL"
|
||||||
},
|
},
|
||||||
// 半色调
|
// 半色调
|
||||||
Halftone: {
|
Halftone: {
|
||||||
@ -223,7 +363,12 @@ class Project {
|
|||||||
* @param {string} key 可以多层级,需用.分割,如a.b.c
|
* @param {string} key 可以多层级,需用.分割,如a.b.c
|
||||||
*/
|
*/
|
||||||
getKey(key: string): any {
|
getKey(key: string): any {
|
||||||
return getNestedProperty(this.info, key);
|
const value = getNestedProperty(this.info, key);
|
||||||
|
if (value !== undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getNestedProperty(defaultProjectInfo(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user