Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -147,7 +147,7 @@ def update_dimensions_on_upload(image):
|
|
| 147 |
# --- 3D Lighting Control Component ---
|
| 148 |
class LightingControl3D(gr.HTML):
|
| 149 |
"""
|
| 150 |
-
|
| 151 |
Outputs: { azimuth: number, elevation: number }
|
| 152 |
Accepts imageUrl prop to display user's uploaded image on the plane.
|
| 153 |
"""
|
|
@@ -168,7 +168,7 @@ class LightingControl3D(gr.HTML):
|
|
| 168 |
|
| 169 |
// Wait for THREE to load
|
| 170 |
const initScene = () => {
|
| 171 |
-
if (typeof THREE === 'undefined') {
|
| 172 |
setTimeout(initScene, 100);
|
| 173 |
return;
|
| 174 |
}
|
|
@@ -182,15 +182,35 @@ class LightingControl3D(gr.HTML):
|
|
| 182 |
camera.lookAt(0, 0.75, 0);
|
| 183 |
|
| 184 |
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
| 185 |
-
renderer.setSize(wrapper.clientWidth
|
| 186 |
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
|
|
|
|
|
| 187 |
wrapper.insertBefore(renderer.domElement, promptOverlay);
|
| 188 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
// Lighting
|
| 190 |
-
scene.add(new THREE.AmbientLight(0xffffff, 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
// Grid
|
| 193 |
-
|
|
|
|
|
|
|
| 194 |
|
| 195 |
// Constants
|
| 196 |
const CENTER = new THREE.Vector3(0, 0.75, 0);
|
|
@@ -246,6 +266,8 @@ class LightingControl3D(gr.HTML):
|
|
| 246 |
const planeMaterial = new THREE.MeshStandardMaterial({ map: currentTexture, side: THREE.DoubleSide, roughness: 0.5, metalness: 0 });
|
| 247 |
let targetPlane = new THREE.Mesh(new THREE.PlaneGeometry(1.2, 1.2), planeMaterial);
|
| 248 |
targetPlane.position.copy(CENTER);
|
|
|
|
|
|
|
| 249 |
scene.add(targetPlane);
|
| 250 |
|
| 251 |
// Function to update texture from image URL
|
|
@@ -258,6 +280,8 @@ class LightingControl3D(gr.HTML):
|
|
| 258 |
scene.remove(targetPlane);
|
| 259 |
targetPlane = new THREE.Mesh(new THREE.PlaneGeometry(1.2, 1.2), planeMaterial);
|
| 260 |
targetPlane.position.copy(CENTER);
|
|
|
|
|
|
|
| 261 |
scene.add(targetPlane);
|
| 262 |
return;
|
| 263 |
}
|
|
@@ -289,6 +313,8 @@ class LightingControl3D(gr.HTML):
|
|
| 289 |
planeMaterial
|
| 290 |
);
|
| 291 |
targetPlane.position.copy(CENTER);
|
|
|
|
|
|
|
| 292 |
scene.add(targetPlane);
|
| 293 |
}
|
| 294 |
}, undefined, (err) => {
|
|
@@ -307,6 +333,11 @@ class LightingControl3D(gr.HTML):
|
|
| 307 |
const bulb = new THREE.Mesh(new THREE.SphereGeometry(0.15, 16, 16), bulbMat);
|
| 308 |
lightGroup.add(bulb);
|
| 309 |
const pointLight = new THREE.PointLight(0xffffff, 5, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
lightGroup.add(pointLight);
|
| 311 |
scene.add(lightGroup);
|
| 312 |
|
|
@@ -405,6 +436,7 @@ class LightingControl3D(gr.HTML):
|
|
| 405 |
dragTarget.scale.setScalar(1.3);
|
| 406 |
dragStartMouse.copy(mouse);
|
| 407 |
canvas.style.cursor = 'grabbing';
|
|
|
|
| 408 |
}
|
| 409 |
});
|
| 410 |
|
|
@@ -482,6 +514,7 @@ class LightingControl3D(gr.HTML):
|
|
| 482 |
isDragging = false;
|
| 483 |
dragTarget = null;
|
| 484 |
canvas.style.cursor = 'default';
|
|
|
|
| 485 |
};
|
| 486 |
|
| 487 |
canvas.addEventListener('mouseup', onMouseUp);
|
|
@@ -503,6 +536,7 @@ class LightingControl3D(gr.HTML):
|
|
| 503 |
dragTarget.material.emissiveIntensity = 1.0;
|
| 504 |
dragTarget.scale.setScalar(1.3);
|
| 505 |
dragStartMouse.copy(mouse);
|
|
|
|
| 506 |
}
|
| 507 |
}, { passive: false });
|
| 508 |
|
|
@@ -550,6 +584,7 @@ class LightingControl3D(gr.HTML):
|
|
| 550 |
// Render loop
|
| 551 |
function render() {
|
| 552 |
requestAnimationFrame(render);
|
|
|
|
| 553 |
renderer.render(scene, camera);
|
| 554 |
}
|
| 555 |
render();
|
|
@@ -615,9 +650,9 @@ css = '''
|
|
| 615 |
'''
|
| 616 |
with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
|
| 617 |
gr.Markdown("""
|
| 618 |
-
# 🎬 Qwen Image Edit 2511 — 3D Lighting Control
|
| 619 |
|
| 620 |
-
Control lighting directions using the **3D viewport** or **sliders**.
|
| 621 |
Using [dx8152/Qwen-Edit-2509-Multi-Angle-Lighting] for precise lighting control.
|
| 622 |
""")
|
| 623 |
|
|
@@ -626,8 +661,8 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
|
|
| 626 |
with gr.Column(scale=1):
|
| 627 |
image = gr.Image(label="Input Image", type="pil", height=300)
|
| 628 |
|
| 629 |
-
gr.Markdown("### 🎮 3D Lighting Control")
|
| 630 |
-
gr.Markdown("*Drag the colored handles: 🟢 Azimuth (Direction), 🩷 Elevation (Height)
|
| 631 |
|
| 632 |
lighting_3d = LightingControl3D(
|
| 633 |
value={"azimuth": 0, "elevation": 0},
|
|
@@ -754,6 +789,6 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
|
|
| 754 |
)
|
| 755 |
|
| 756 |
if __name__ == "__main__":
|
| 757 |
-
head = '<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>'
|
| 758 |
css = '.fillable{max-width: 1200px !important}'
|
| 759 |
demo.launch(head=head, css=css)
|
|
|
|
| 147 |
# --- 3D Lighting Control Component ---
|
| 148 |
class LightingControl3D(gr.HTML):
|
| 149 |
"""
|
| 150 |
+
An enhanced 3D lighting control component using Three.js with orbit controls and shadows.
|
| 151 |
Outputs: { azimuth: number, elevation: number }
|
| 152 |
Accepts imageUrl prop to display user's uploaded image on the plane.
|
| 153 |
"""
|
|
|
|
| 168 |
|
| 169 |
// Wait for THREE to load
|
| 170 |
const initScene = () => {
|
| 171 |
+
if (typeof THREE === 'undefined' || typeof THREE.OrbitControls === 'undefined') {
|
| 172 |
setTimeout(initScene, 100);
|
| 173 |
return;
|
| 174 |
}
|
|
|
|
| 182 |
camera.lookAt(0, 0.75, 0);
|
| 183 |
|
| 184 |
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
| 185 |
+
renderer.setSize(wrapper.clientWidth, wrapper.clientHeight);
|
| 186 |
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
| 187 |
+
renderer.shadowMap.enabled = true;
|
| 188 |
+
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
| 189 |
wrapper.insertBefore(renderer.domElement, promptOverlay);
|
| 190 |
|
| 191 |
+
// Orbit controls
|
| 192 |
+
const controls = new THREE.OrbitControls(camera, renderer.domElement);
|
| 193 |
+
controls.target.set(0, 0.75, 0);
|
| 194 |
+
controls.enableDamping = true;
|
| 195 |
+
controls.dampingFactor = 0.05;
|
| 196 |
+
controls.update();
|
| 197 |
+
|
| 198 |
// Lighting
|
| 199 |
+
scene.add(new THREE.AmbientLight(0xffffff, 0.3));
|
| 200 |
+
|
| 201 |
+
// Ground
|
| 202 |
+
const groundGeo = new THREE.PlaneGeometry(10, 10);
|
| 203 |
+
const groundMat = new THREE.ShadowMaterial({ opacity: 0.3 });
|
| 204 |
+
const ground = new THREE.Mesh(groundGeo, groundMat);
|
| 205 |
+
ground.rotation.x = -Math.PI / 2;
|
| 206 |
+
ground.position.y = 0;
|
| 207 |
+
ground.receiveShadow = true;
|
| 208 |
+
scene.add(ground);
|
| 209 |
|
| 210 |
// Grid
|
| 211 |
+
const grid = new THREE.GridHelper(10, 20, 0x888888, 0x444444);
|
| 212 |
+
grid.position.y = 0.01;
|
| 213 |
+
scene.add(grid);
|
| 214 |
|
| 215 |
// Constants
|
| 216 |
const CENTER = new THREE.Vector3(0, 0.75, 0);
|
|
|
|
| 266 |
const planeMaterial = new THREE.MeshStandardMaterial({ map: currentTexture, side: THREE.DoubleSide, roughness: 0.5, metalness: 0 });
|
| 267 |
let targetPlane = new THREE.Mesh(new THREE.PlaneGeometry(1.2, 1.2), planeMaterial);
|
| 268 |
targetPlane.position.copy(CENTER);
|
| 269 |
+
targetPlane.castShadow = true;
|
| 270 |
+
targetPlane.receiveShadow = true;
|
| 271 |
scene.add(targetPlane);
|
| 272 |
|
| 273 |
// Function to update texture from image URL
|
|
|
|
| 280 |
scene.remove(targetPlane);
|
| 281 |
targetPlane = new THREE.Mesh(new THREE.PlaneGeometry(1.2, 1.2), planeMaterial);
|
| 282 |
targetPlane.position.copy(CENTER);
|
| 283 |
+
targetPlane.castShadow = true;
|
| 284 |
+
targetPlane.receiveShadow = true;
|
| 285 |
scene.add(targetPlane);
|
| 286 |
return;
|
| 287 |
}
|
|
|
|
| 313 |
planeMaterial
|
| 314 |
);
|
| 315 |
targetPlane.position.copy(CENTER);
|
| 316 |
+
targetPlane.castShadow = true;
|
| 317 |
+
targetPlane.receiveShadow = true;
|
| 318 |
scene.add(targetPlane);
|
| 319 |
}
|
| 320 |
}, undefined, (err) => {
|
|
|
|
| 333 |
const bulb = new THREE.Mesh(new THREE.SphereGeometry(0.15, 16, 16), bulbMat);
|
| 334 |
lightGroup.add(bulb);
|
| 335 |
const pointLight = new THREE.PointLight(0xffffff, 5, 0);
|
| 336 |
+
pointLight.castShadow = true;
|
| 337 |
+
pointLight.shadow.mapSize.width = 1024;
|
| 338 |
+
pointLight.shadow.mapSize.height = 1024;
|
| 339 |
+
pointLight.shadow.camera.near = 0.1;
|
| 340 |
+
pointLight.shadow.camera.far = 20;
|
| 341 |
lightGroup.add(pointLight);
|
| 342 |
scene.add(lightGroup);
|
| 343 |
|
|
|
|
| 436 |
dragTarget.scale.setScalar(1.3);
|
| 437 |
dragStartMouse.copy(mouse);
|
| 438 |
canvas.style.cursor = 'grabbing';
|
| 439 |
+
controls.enabled = false; // Disable orbit while dragging handles
|
| 440 |
}
|
| 441 |
});
|
| 442 |
|
|
|
|
| 514 |
isDragging = false;
|
| 515 |
dragTarget = null;
|
| 516 |
canvas.style.cursor = 'default';
|
| 517 |
+
controls.enabled = true; // Re-enable orbit
|
| 518 |
};
|
| 519 |
|
| 520 |
canvas.addEventListener('mouseup', onMouseUp);
|
|
|
|
| 536 |
dragTarget.material.emissiveIntensity = 1.0;
|
| 537 |
dragTarget.scale.setScalar(1.3);
|
| 538 |
dragStartMouse.copy(mouse);
|
| 539 |
+
controls.enabled = false;
|
| 540 |
}
|
| 541 |
}, { passive: false });
|
| 542 |
|
|
|
|
| 584 |
// Render loop
|
| 585 |
function render() {
|
| 586 |
requestAnimationFrame(render);
|
| 587 |
+
controls.update();
|
| 588 |
renderer.render(scene, camera);
|
| 589 |
}
|
| 590 |
render();
|
|
|
|
| 650 |
'''
|
| 651 |
with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
|
| 652 |
gr.Markdown("""
|
| 653 |
+
# 🎬 Qwen Image Edit 2511 — Enhanced 3D Lighting Control
|
| 654 |
|
| 655 |
+
Control lighting directions using the **3D viewport** or **sliders**. Now with orbit controls (drag to rotate view) and shadows for better visualization.
|
| 656 |
Using [dx8152/Qwen-Edit-2509-Multi-Angle-Lighting] for precise lighting control.
|
| 657 |
""")
|
| 658 |
|
|
|
|
| 661 |
with gr.Column(scale=1):
|
| 662 |
image = gr.Image(label="Input Image", type="pil", height=300)
|
| 663 |
|
| 664 |
+
gr.Markdown("### 🎮 Enhanced 3D Lighting Control")
|
| 665 |
+
gr.Markdown("*Drag the colored handles: 🟢 Azimuth (Direction), 🩷 Elevation (Height). Orbit the view by dragging the background.*")
|
| 666 |
|
| 667 |
lighting_3d = LightingControl3D(
|
| 668 |
value={"azimuth": 0, "elevation": 0},
|
|
|
|
| 789 |
)
|
| 790 |
|
| 791 |
if __name__ == "__main__":
|
| 792 |
+
head = '<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script><script src="https://cdn.jsdelivr.net/npm/three@0.128/examples/js/controls/OrbitControls.js"></script>'
|
| 793 |
css = '.fillable{max-width: 1200px !important}'
|
| 794 |
demo.launch(head=head, css=css)
|