mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-20 23:04:06 +00:00
[3d] add edge threshold support (#2939)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
:backgroundImage="backgroundImage"
|
||||
:upDirection="upDirection"
|
||||
:materialMode="materialMode"
|
||||
:edgeThreshold="edgeThreshold"
|
||||
@materialModeChange="listenMaterialModeChange"
|
||||
@backgroundColorChange="listenBackgroundColorChange"
|
||||
@lightIntensityChange="listenLightIntensityChange"
|
||||
@@ -21,6 +22,7 @@
|
||||
@showPreviewChange="listenShowPreviewChange"
|
||||
@backgroundImageChange="listenBackgroundImageChange"
|
||||
@upDirectionChange="listenUpDirectionChange"
|
||||
@edgeThresholdChange="listenEdgeThresholdChange"
|
||||
/>
|
||||
<Load3DControls
|
||||
:backgroundColor="backgroundColor"
|
||||
@@ -36,6 +38,7 @@
|
||||
:upDirection="upDirection"
|
||||
:materialMode="materialMode"
|
||||
:isAnimation="false"
|
||||
:edgeThreshold="edgeThreshold"
|
||||
@updateBackgroundImage="handleBackgroundImageUpdate"
|
||||
@switchCamera="switchCamera"
|
||||
@toggleGrid="toggleGrid"
|
||||
@@ -45,6 +48,7 @@
|
||||
@updateFOV="handleUpdateFOV"
|
||||
@updateUpDirection="handleUpdateUpDirection"
|
||||
@updateMaterialMode="handleUpdateMaterialMode"
|
||||
@updateEdgeThreshold="handleUpdateEdgeThreshold"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -79,6 +83,7 @@ const hasBackgroundImage = ref(false)
|
||||
const backgroundImage = ref('')
|
||||
const upDirection = ref<UpDirection>('original')
|
||||
const materialMode = ref<MaterialMode>('original')
|
||||
const edgeThreshold = ref(85)
|
||||
|
||||
const showPreviewButton = computed(() => {
|
||||
return !props.type.includes('Preview')
|
||||
@@ -130,6 +135,12 @@ const handleUpdateFOV = (value: number) => {
|
||||
node.value.properties['FOV'] = fov.value
|
||||
}
|
||||
|
||||
const handleUpdateEdgeThreshold = (value: number) => {
|
||||
edgeThreshold.value = value
|
||||
|
||||
node.value.properties['Edge Threshold'] = edgeThreshold.value
|
||||
}
|
||||
|
||||
const handleBackgroundColorChange = (value: string) => {
|
||||
backgroundColor.value = value
|
||||
|
||||
@@ -158,6 +169,10 @@ const listenUpDirectionChange = (value: UpDirection) => {
|
||||
upDirection.value = value
|
||||
}
|
||||
|
||||
const listenEdgeThresholdChange = (value: number) => {
|
||||
edgeThreshold.value = value
|
||||
}
|
||||
|
||||
const listenBackgroundColorChange = (value: string) => {
|
||||
backgroundColor.value = value
|
||||
}
|
||||
|
||||
@@ -166,7 +166,42 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="activeCategory === 'model' && materialMode === 'lineart'"
|
||||
class="relative show-edge-threshold"
|
||||
>
|
||||
<Button
|
||||
class="p-button-rounded p-button-text"
|
||||
@click="toggleEdgeThreshold"
|
||||
>
|
||||
<i
|
||||
class="pi pi-sliders-h text-white text-lg"
|
||||
v-tooltip.right="{
|
||||
value: t('load3d.edgeThreshold'),
|
||||
showDelay: 300
|
||||
}"
|
||||
></i>
|
||||
</Button>
|
||||
<div
|
||||
v-show="showEdgeThreshold"
|
||||
class="absolute left-12 top-0 bg-black bg-opacity-50 p-4 rounded-lg shadow-lg"
|
||||
style="width: 150px"
|
||||
>
|
||||
<label class="text-white text-xs mb-1 block"
|
||||
>{{ t('load3d.edgeThreshold') }}: {{ edgeThreshold }}°</label
|
||||
>
|
||||
<Slider
|
||||
v-model="edgeThreshold"
|
||||
class="w-full"
|
||||
@change="updateEdgeThreshold"
|
||||
:min="0"
|
||||
:max="120"
|
||||
:step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="activeCategory === 'camera'" class="flex flex-col">
|
||||
<Button class="p-button-rounded p-button-text" @click="switchCamera">
|
||||
<i
|
||||
@@ -279,6 +314,7 @@ const props = defineProps<{
|
||||
upDirection: UpDirection
|
||||
materialMode: MaterialMode
|
||||
isAnimation: boolean
|
||||
edgeThreshold?: number
|
||||
}>()
|
||||
|
||||
const isMenuOpen = ref(false)
|
||||
@@ -319,6 +355,7 @@ const emit = defineEmits<{
|
||||
(e: 'updateBackgroundImage', file: File | null): void
|
||||
(e: 'updateUpDirection', direction: UpDirection): void
|
||||
(e: 'updateMaterialMode', mode: MaterialMode): void
|
||||
(e: 'updateEdgeThreshold', value: number): void
|
||||
}>()
|
||||
|
||||
const backgroundColor = ref(props.backgroundColor)
|
||||
@@ -347,6 +384,12 @@ const upDirections: UpDirection[] = [
|
||||
'+z'
|
||||
]
|
||||
const showMaterialMode = ref(false)
|
||||
const edgeThreshold = ref(props.edgeThreshold)
|
||||
const showEdgeThreshold = ref(false)
|
||||
|
||||
const toggleEdgeThreshold = () => {
|
||||
showEdgeThreshold.value = !showEdgeThreshold.value
|
||||
}
|
||||
|
||||
const materialModes = computed(() => {
|
||||
const modes: MaterialMode[] = [
|
||||
@@ -405,6 +448,10 @@ const updateFOV = () => {
|
||||
emit('updateFOV', fov.value)
|
||||
}
|
||||
|
||||
const updateEdgeThreshold = () => {
|
||||
emit('updateEdgeThreshold', edgeThreshold.value)
|
||||
}
|
||||
|
||||
const toggleUpDirection = () => {
|
||||
showUpDirection.value = !showUpDirection.value
|
||||
}
|
||||
@@ -454,6 +501,10 @@ const closeSlider = (e: MouseEvent) => {
|
||||
if (!target.closest('.show-material-mode')) {
|
||||
showMaterialMode.value = false
|
||||
}
|
||||
|
||||
if (!target.closest('.show-edge-threshold')) {
|
||||
showEdgeThreshold.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const openImagePicker = () => {
|
||||
@@ -564,6 +615,13 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.edgeThreshold,
|
||||
(newValue) => {
|
||||
edgeThreshold.value = newValue
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', closeSlider)
|
||||
})
|
||||
|
||||
@@ -31,6 +31,7 @@ const props = defineProps<{
|
||||
backgroundImage: string
|
||||
upDirection: UpDirection
|
||||
materialMode: MaterialMode
|
||||
edgeThreshold?: number
|
||||
extraListeners?: Record<string, (value: any) => void>
|
||||
}>()
|
||||
|
||||
@@ -51,6 +52,7 @@ const eventConfig = {
|
||||
backgroundImageChange: (value: string) =>
|
||||
emit('backgroundImageChange', value),
|
||||
upDirectionChange: (value: string) => emit('upDirectionChange', value),
|
||||
edgeThresholdChange: (value: number) => emit('edgeThresholdChange', value),
|
||||
modelLoadingStart: () =>
|
||||
loadingOverlayRef.value?.startLoading(t('load3d.loadingModel')),
|
||||
modelLoadingEnd: () => loadingOverlayRef.value?.endLoading(),
|
||||
@@ -71,6 +73,7 @@ watchEffect(() => {
|
||||
rawLoad3d.togglePreview(props.showPreview)
|
||||
rawLoad3d.setBackgroundImage(props.backgroundImage)
|
||||
rawLoad3d.setUpDirection(props.upDirection)
|
||||
rawLoad3d.setEdgeThreshold(props.edgeThreshold)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -95,6 +98,7 @@ const emit = defineEmits<{
|
||||
(e: 'showPreviewChange', showPreview: boolean): void
|
||||
(e: 'backgroundImageChange', backgroundImage: string): void
|
||||
(e: 'upDirectionChange', upDirection: string): void
|
||||
(e: 'edgeThresholdChange', threshold: number): void
|
||||
}>()
|
||||
|
||||
const handleEvents = (action: 'add' | 'remove') => {
|
||||
|
||||
@@ -68,11 +68,13 @@ class Load3DConfiguration {
|
||||
|
||||
this.load3d.setBackgroundColor(bgColor)
|
||||
|
||||
const lightIntensity = this.load3d.loadNodeProperty('Light Intensity', 5)
|
||||
const lightIntensity: number = Number(
|
||||
this.load3d.loadNodeProperty('Light Intensity', 5)
|
||||
)
|
||||
|
||||
this.load3d.setLightIntensity(lightIntensity)
|
||||
|
||||
const fov = this.load3d.loadNodeProperty('FOV', 35)
|
||||
const fov: number = Number(this.load3d.loadNodeProperty('FOV', 35))
|
||||
|
||||
this.load3d.setFOV(fov)
|
||||
|
||||
@@ -113,6 +115,12 @@ class Load3DConfiguration {
|
||||
|
||||
this.load3d.setMaterialMode(materialMode)
|
||||
|
||||
const edgeThreshold: number = Number(
|
||||
this.load3d.loadNodeProperty('Edge Threshold', 85)
|
||||
)
|
||||
|
||||
this.load3d.setEdgeThreshold(edgeThreshold)
|
||||
|
||||
if (isFirstLoad && cameraState && typeof cameraState === 'object') {
|
||||
try {
|
||||
this.load3d.setCameraState(cameraState)
|
||||
|
||||
@@ -233,6 +233,10 @@ class Load3d {
|
||||
)
|
||||
}
|
||||
|
||||
setEdgeThreshold(threshold: number): void {
|
||||
this.modelManager.setEdgeThreshold(threshold)
|
||||
}
|
||||
|
||||
setMaterialMode(mode: MaterialMode): void {
|
||||
this.modelManager.setMaterialMode(mode)
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ export class ModelManager implements ModelManagerInterface {
|
||||
const mesh = meshes[key]
|
||||
const parent = mesh.parent
|
||||
|
||||
let lineGeom = new THREE.EdgesGeometry(mesh.geometry, 10)
|
||||
let lineGeom = new THREE.EdgesGeometry(mesh.geometry, 85)
|
||||
|
||||
const line = new THREE.LineSegments(
|
||||
lineGeom,
|
||||
@@ -200,6 +200,76 @@ export class ModelManager implements ModelManagerInterface {
|
||||
})
|
||||
}
|
||||
|
||||
setEdgeThreshold(threshold: number): void {
|
||||
if (!this.edgesModel || !this.currentModel) {
|
||||
return
|
||||
}
|
||||
|
||||
const linesToRemove: THREE.Object3D[] = []
|
||||
this.edgesModel.traverse((child) => {
|
||||
if (
|
||||
child instanceof THREE.LineSegments ||
|
||||
child instanceof LineSegments2
|
||||
) {
|
||||
linesToRemove.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
for (const line of linesToRemove) {
|
||||
if (line.parent) {
|
||||
line.parent.remove(line)
|
||||
}
|
||||
}
|
||||
|
||||
const meshes: THREE.Mesh[] = []
|
||||
this.currentModel.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
meshes.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
for (const mesh of meshes) {
|
||||
const meshClone = mesh.clone()
|
||||
|
||||
let lineGeom = new THREE.EdgesGeometry(meshClone.geometry, threshold)
|
||||
|
||||
const line = new THREE.LineSegments(
|
||||
lineGeom,
|
||||
new THREE.LineBasicMaterial({ color: this.LIGHT_LINES })
|
||||
)
|
||||
line.position.copy(mesh.position)
|
||||
line.scale.copy(mesh.scale)
|
||||
line.rotation.copy(mesh.rotation)
|
||||
|
||||
const thickLineGeom = new LineSegmentsGeometry().fromEdgesGeometry(
|
||||
lineGeom
|
||||
)
|
||||
const thickLines = new LineSegments2(
|
||||
thickLineGeom,
|
||||
new LineMaterial({ color: this.LIGHT_LINES, linewidth: 13 })
|
||||
)
|
||||
thickLines.position.copy(mesh.position)
|
||||
thickLines.scale.copy(mesh.scale)
|
||||
thickLines.rotation.copy(mesh.rotation)
|
||||
|
||||
this.edgesModel.add(line)
|
||||
this.edgesModel.add(thickLines)
|
||||
}
|
||||
|
||||
this.edgesModel.traverse((child) => {
|
||||
if (
|
||||
child instanceof THREE.Mesh &&
|
||||
child.material &&
|
||||
child.material.resolution
|
||||
) {
|
||||
this.renderer.getSize(child.material.resolution)
|
||||
child.material.resolution.multiplyScalar(window.devicePixelRatio)
|
||||
child.material.linewidth = 1
|
||||
}
|
||||
})
|
||||
this.eventManager.emitEvent('edgeThresholdChange', threshold)
|
||||
}
|
||||
|
||||
disposeBackgroundModel(): void {
|
||||
if (this.backgroundModel) {
|
||||
if (this.backgroundModel.parent) {
|
||||
|
||||
@@ -907,6 +907,7 @@
|
||||
"model": "Model",
|
||||
"camera": "Camera",
|
||||
"light": "Light",
|
||||
"switchingMaterialMode": "Switching Material Mode..."
|
||||
"switchingMaterialMode": "Switching Material Mode...",
|
||||
"edgeThreshold": "Edge Threshold"
|
||||
}
|
||||
}
|
||||
@@ -335,6 +335,7 @@
|
||||
"load3d": {
|
||||
"backgroundColor": "Couleur de fond",
|
||||
"camera": "Caméra",
|
||||
"edgeThreshold": "Seuil de Bordure",
|
||||
"fov": "FOV",
|
||||
"light": "Lumière",
|
||||
"lightIntensity": "Intensité de la lumière",
|
||||
|
||||
@@ -335,6 +335,7 @@
|
||||
"load3d": {
|
||||
"backgroundColor": "背景色",
|
||||
"camera": "カメラ",
|
||||
"edgeThreshold": "エッジ閾値",
|
||||
"fov": "FOV",
|
||||
"light": "ライト",
|
||||
"lightIntensity": "光の強度",
|
||||
|
||||
@@ -335,6 +335,7 @@
|
||||
"load3d": {
|
||||
"backgroundColor": "배경색",
|
||||
"camera": "카메라",
|
||||
"edgeThreshold": "엣지 임계값",
|
||||
"fov": "FOV",
|
||||
"light": "빛",
|
||||
"lightIntensity": "조명 강도",
|
||||
|
||||
@@ -335,6 +335,7 @@
|
||||
"load3d": {
|
||||
"backgroundColor": "Цвет фона",
|
||||
"camera": "Камера",
|
||||
"edgeThreshold": "Пороговое значение края",
|
||||
"fov": "Угол обзора",
|
||||
"light": "Свет",
|
||||
"lightIntensity": "Интенсивность света",
|
||||
|
||||
@@ -335,6 +335,7 @@
|
||||
"load3d": {
|
||||
"backgroundColor": "背景颜色",
|
||||
"camera": "相机",
|
||||
"edgeThreshold": "边缘阈值",
|
||||
"fov": "视场",
|
||||
"light": "灯光",
|
||||
"lightIntensity": "光照强度",
|
||||
|
||||
Reference in New Issue
Block a user