-
-
Save JanHmmr/810bc3f58b44801ea5a18025f3cc209b to your computer and use it in GitHub Desktop.
realtime from 3d old fal model
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { useContext, useState, useEffect, useRef } from 'react'; | |
| import SidebarLayout from '@/components/layout'; | |
| import { LuLock } from "react-icons/lu"; | |
| import { PageContext } from '@/utils/contexts'; | |
| import * as fal from "@fal-ai/serverless-client"; | |
| import Image from 'next/image'; | |
| import * as THREE from 'three'; | |
| import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; | |
| import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; | |
| fal.config({ | |
| proxyUrl: "/api/fal/proxy", | |
| }); | |
| const seed = Math.floor(Math.random() * 100000); | |
| const baseArgs = { | |
| sync_mode: true, | |
| strength: 0.3, | |
| seed, | |
| }; | |
| const TextureGeneration = () => { | |
| const { setauthToken, setloginModal, setupgradeModal } = useContext(PageContext); | |
| const [input, setInput] = useState(''); | |
| const [image, setImage] = useState(null); | |
| const [localImage, setLocalImage] = useState(null); | |
| const [isClient, setIsClient] = useState(false); | |
| const [modelSelectOpen, setModelSelectOpen] = useState(true); | |
| const [models, setModels] = useState([ | |
| { name: 'Model1.glb', image: '/Example1.png' }, | |
| { name: 'Model2.glb', image: '/Example2.png' }, | |
| { name: 'Model3.glb', image: '/Example3.png' }, | |
| { name: 'Model4.glb', image: '/Example4.png' }, | |
| { name: 'Model5.glb', image: '/Example5.png' }, | |
| { name: 'Model6.glb', image: '/Example6.png' }, | |
| { name: 'Model7.glb', image: '/Example7.png' }, | |
| { name: 'Model8.glb', image: '/Example8.png' }, | |
| ]); | |
| const [selectedModel, setSelectedModel] = useState(null); | |
| const canvasRef = useRef(null); | |
| const rendererRef = useRef(null); | |
| const sceneRef = useRef(null); | |
| const cameraRef = useRef(null); | |
| const controlsRef = useRef(null); | |
| const modelRef = useRef(null); | |
| useEffect(() => { | |
| setIsClient(true); | |
| }, []); | |
| useEffect(() => { | |
| if (isClient) { | |
| const canvas = canvasRef.current; | |
| const renderer = new THREE.WebGLRenderer({ canvas, preserveDrawingBuffer: true }); | |
| rendererRef.current = renderer; | |
| const scene = new THREE.Scene(); | |
| scene.background = new THREE.Color('white'); | |
| sceneRef.current = scene; | |
| const camera = new THREE.PerspectiveCamera(75, canvas.clientWidth / canvas.clientHeight, 0.1, 1000); | |
| camera.position.z = 5; | |
| cameraRef.current = camera; | |
| const controls = new OrbitControls(camera, canvas); | |
| controls.enableDamping = true; | |
| controls.dampingFactor = 0.05; | |
| controls.screenSpacePanning = false; | |
| controls.minDistance = 1; | |
| controls.maxDistance = 500; | |
| controlsRef.current = controls; | |
| // Add strong lighting | |
| const directionalLight = new THREE.DirectionalLight(0xffffff, 2); | |
| directionalLight.position.set(1, 1, 1); | |
| scene.add(directionalLight); | |
| const ambientLight = new THREE.AmbientLight(0xffffff, 0.8); | |
| scene.add(ambientLight); | |
| const pointLight1 = new THREE.PointLight(0xffffff, 1.5); | |
| pointLight1.position.set(5, 5, 5); | |
| scene.add(pointLight1); | |
| const pointLight2 = new THREE.PointLight(0xffffff, 1.5); | |
| pointLight2.position.set(-5, 5, -5); | |
| scene.add(pointLight2); | |
| const animate = () => { | |
| requestAnimationFrame(animate); | |
| controls.update(); | |
| renderer.render(scene, camera); | |
| }; | |
| animate(); | |
| return () => { | |
| renderer.dispose(); | |
| }; | |
| } | |
| }, [isClient]); | |
| useEffect(() => { | |
| if (selectedModel) { | |
| const loader = new GLTFLoader(); | |
| loader.load(selectedModel.name, (gltf) => { | |
| const model = gltf.scene; | |
| sceneRef.current.add(model); | |
| modelRef.current = model; | |
| }); | |
| } | |
| }, [selectedModel]); | |
| const { send } = fal.realtime.connect('110602490-sdxl-turbo-realtime', { | |
| connectionKey: 'realtime-3daistudio-app', | |
| clientOnly: true, | |
| onResult(result) { | |
| if (result.error) return; | |
| setImage(result.images[0].url); | |
| }, | |
| }); | |
| async function getDataUrl() { | |
| const canvas = canvasRef.current; | |
| const renderer = rendererRef.current; | |
| renderer.render(sceneRef.current, cameraRef.current); | |
| return canvas.toDataURL('image/png'); | |
| } | |
| useEffect(() => { | |
| let timeoutId; | |
| const handleChange = async () => { | |
| let dataUrl = await getDataUrl(); | |
| setLocalImage(dataUrl); | |
| if (dataUrl !== localImage) { | |
| send({ | |
| ...baseArgs, | |
| image_url: dataUrl, | |
| prompt: input, | |
| }); | |
| } | |
| }; | |
| const debouncedHandleChange = () => { | |
| clearTimeout(timeoutId); | |
| timeoutId = setTimeout(handleChange, 300); | |
| }; | |
| if (isClient && controlsRef.current) { | |
| controlsRef.current.addEventListener('change', debouncedHandleChange); | |
| } | |
| return () => { | |
| if (isClient && controlsRef.current) { | |
| controlsRef.current.removeEventListener('change', debouncedHandleChange); | |
| } | |
| }; | |
| }, [isClient, input, send, localImage]); | |
| const handleFileUpload = (event) => { | |
| const file = event.target.files[0]; | |
| const reader = new FileReader(); | |
| reader.onload = (event) => { | |
| const arrayBuffer = event.target.result; | |
| const loader = new GLTFLoader(); | |
| const scene = sceneRef.current; | |
| // Remove the existing model from the scene | |
| if (modelRef.current) { | |
| scene.remove(modelRef.current); | |
| } | |
| // Load the uploaded GLB model | |
| loader.parse(arrayBuffer, '', (gltf) => { | |
| const model = gltf.scene; | |
| scene.add(model); | |
| modelRef.current = model; | |
| setModelSelectOpen(false); | |
| }); | |
| }; | |
| reader.readAsArrayBuffer(file); | |
| }; | |
| const handleModelSelect = (model) => { | |
| setSelectedModel(model); | |
| setModelSelectOpen(false); | |
| }; | |
| return ( | |
| <SidebarLayout> | |
| <div className="relative w-full h-full flex flex-col items-center justify-center bg-[#1f1f1f] text-white"> | |
| <h1 className="text-4xl font-bold mb-8">Realtime Texture Generation</h1> | |
| <div className="flex space-x-8"> | |
| <div className="flex flex-col items-center"> | |
| <div className="w-[550px] h-[550px] border-2 border-gray-500 mb-4"> | |
| <canvas ref={canvasRef} width={550} height={550} /> | |
| </div> | |
| <input | |
| type="file" | |
| accept=".glb" | |
| onChange={handleFileUpload} | |
| className="px-4 py-2 bg-blue-500 text-white rounded-lg cursor-pointer" | |
| /> | |
| </div> | |
| <div className="flex flex-col items-center"> | |
| <div className="w-[550px] h-[550px] border-2 border-gray-500 flex items-center justify-center"> | |
| {image ? ( | |
| <Image src={image} width={550} height={550} alt="fal image" /> | |
| ) : ( | |
| <div className="animate-spin rounded-full h-20 w-20 border-t-4 border-white"></div> | |
| )} | |
| </div> | |
| <input | |
| className="px-4 py-2 border border-gray-500 bg-transparent rounded-lg w-full mt-4" | |
| value={input} | |
| onChange={(e) => { | |
| setInput(e.target.value); | |
| }} | |
| placeholder="Enter prompt" | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| {modelSelectOpen && ( | |
| <div className="fixed inset-0 flex items-center justify-center z-50 bg-black bg-opacity-50"> | |
| <div className="bg-white p-8 rounded shadow-lg w-[600px]"> | |
| <h2 className="text-2xl font-bold mb-4 text-gray-900">Select Model</h2> | |
| <div className="grid grid-cols-4 gap-4"> | |
| {models.map((model, index) => ( | |
| <div | |
| key={index} | |
| className="cursor-pointer border border-gray-300 p-2 rounded" | |
| onClick={() => handleModelSelect(model)} | |
| > | |
| <Image src={model.image} width={200} height={200} alt={model.name} /> | |
| <p className="text-center">{model.name}</p> | |
| </div> | |
| ))} | |
| </div> | |
| <div className="mt-8 flex justify-between"> | |
| <button | |
| className="px-4 py-2 bg-gray-200 text-gray-700 rounded" | |
| onClick={() => setModelSelectOpen(false)} | |
| > | |
| Cancel | |
| </button> | |
| <input | |
| type="file" | |
| accept=".glb" | |
| onChange={handleFileUpload} | |
| className="px-4 py-2 bg-blue-500 text-white rounded cursor-pointer" | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </SidebarLayout> | |
| ); | |
| }; | |
| export default TextureGeneration; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment