WebGPU / TSL
WebGPU एक नया वेब मानक है जो GPU पर ग्राफिक्स को रेंडर करने और संगणनाएं करने के लिए एक निम्न-स्तरीय API प्रदान करता है। इसे WebGL का उत्तराधिकारी बनने के लिए डिज़ाइन किया गया है, जो बेहतर प्रदर्शन और अधिक उन्नत सुविधाएँ प्रदान करता है।
शानदार खबर यह है कि इसे अब Three.js के साथ कोडबेस में न्यूनतम परिवर्तन के साथ उपयोग करना संभव है।
इस पाठ में, हम WebGPU को Three.js और React Three Fiber के साथ उपयोग करने और नए Three Shading Language (TSL) का उपयोग करके शेडर्स लिखने का अन्वेषण करेंगे।
यदि आप शेडर्स के नए हैं, तो मैं आपको इस अध्याय के साथ जारी रखने से पहले Shaders अध्याय को पूरा करने की सलाह देता हूँ।
WebGPU Renderer
WebGL के बजाय WebGPU API का उपयोग करने के लिए, हमें WebGLRenderer के बजाय WebGPURenderer
का उपयोग करना होगा (Three.js दस्तावेज़ीकरण पर अभी तक कोई समर्पित अनुभाग नहीं)।
React Three Fiber के साथ, <Canvas>
कंपोनेंट बनाते समय, renderer की स्थापना स्वचालित रूप से की जाती है। हालांकि, हम <Canvas>
कंपोनेंट के gl
prop को एक फ़ंक्शन पास करके डिफ़ॉल्ट renderer को ओवरराइड कर सकते हैं।
App.jsx
में, हमारे पास एक <Canvas>
कंपोनेंट है जो डिफ़ॉल्ट WebGLRenderer
का उपयोग करता है। आइए इसे WebGPURenderer
का उपयोग करने के लिए संशोधित करें।
पहले, हमें WebGPURenderer
के तैयार होने तक frameloop
को रोकने की आवश्यकता है। हम इसे frameloop
prop को never
पर सेट करके कर सकते हैं।
// ... import { useState } from "react"; function App() { const [frameloop, setFrameloop] = useState("never"); return ( <> {/* ... */} <Canvas // ... frameloop={frameloop} > {/* ... */} </Canvas> </> ); } export default App;
अब, हमें Three.js के WebGPU संस्करण को इम्पोर्ट करने की आवश्यकता है:
import * as THREE from "three/webgpu";
WebGPU का उपयोग करते समय, हमें डिफ़ॉल्ट
three
मॉड्यूल के बजायthree/webgpu
मॉड्यूल का उपयोग करने की आवश्यकता है। यह इसलिए है क्योंकिWebGPURenderer
Three.js की डिफ़ॉल्ट बिल्ड में शामिल नहीं है।
इसके बाद, हम gl
prop का उपयोग करके एक नया WebGPURenderer
instance बना सकते हैं:
// ... function App() { const [frameloop, setFrameloop] = useState("never"); return ( <> {/* ... */} <Canvas // ... gl={(canvas) => { const renderer = new THREE.WebGPURenderer({ canvas, powerPreference: "high-performance", antialias: true, alpha: false, stencil: false, shadowMap: true, }); renderer.init().then(() => { setFrameloop("always"); }); return renderer; }} > {/* ... */} </Canvas> </> ); } // ...
हम एक नया WebGPURenderer
instance बनाते हैं और इसे canvas
तत्व पास करते हैं। हम renderer के लिए कुछ विकल्प भी सेट करते हैं, जैसे powerPreference
, antialias
, alpha
, stencil
, और shadowMap
। ये विकल्प WebGLRenderer
में उपयोग किए जाने वाले विकल्पों के समान होते हैं।
अंत में, renderer को इनिशियलाइज करने के लिए हम उसके init()
मेथड को कॉल करते हैं। एक बार इनिशियलाइजेशन पूर्ण हो जाने के बाद, हम frameloop
स्थिति को "always"
पर सेट कर देते हैं ताकि रेंडरिंग शुरू हो सके।
चलो देखते हैं ब्राउजर में परिणाम:
हमारा क्यूब अब WebGLRenderer
के बजाय WebGPURenderer
का उपयोग करके रेंडर किया गया है।
यह कितना आसान है! हमने सफलतापूर्वक अपने React Three Fiber एप्लिकेशन में एक WebGPURenderer
सेट किया है। आप अब उसी Three.js API का उपयोग करके 3D ऑब्जेक्ट्स को बना और हेरफेर कर सकते हैं, जैसे कि आप WebGLRenderer
के साथ करेंगे।
सबसे बड़े बदलाव शेडर्स लिखने के समय आते हैं। WebGPU API WebGL से एक अलग shading भाषा का उपयोग करता है, जिसका अर्थ है कि हमें शेडर्स को एक अलग तरीके से लिखना होगा। WGSL में GLSL के बजाय।
यहां Three Shading Language (TSL) काम आती है।
Three Shading Language
TSL एक नई शेडिंग भाषा है जिसे Three.js के साथ उपयोग करने के लिए डिज़ाइन किया गया है ताकि शेडर्स को एक अधिक उपयोगकर्ता-मैत्रीपूर्ण तरीके से एक नोड-आधारित दृष्टिकोण का उपयोग करके लिखा जा सके।
TSL का एक बड़ा लाभ यह है कि यह रेंडरर-अज्ञेयवादी है, जिसका अर्थ है कि आप विभिन्न रेंडरर्स के साथ समान शेडर्स का उपयोग कर सकते हैं, जैसे कि WebGL और WebGPU।
इससे शेडर्स को लिखना और बनाए रखना आसान हो जाता है, क्योंकि आपको दोनों शेडिंग भाषाओं के बीच के अंतरों के बारे में चिंता करने की आवश्यकता नहीं होती है।
यह भविष्य-प्रूफ भी है, क्योंकि यदि कोई नया रेंडरर जारी किया जाता है, तो हम बिना किसी परिवर्तन के समान शेडर्स का उपयोग कर सकते हैं, जब तक कि TSL इसका समर्थन करता है।
Three Shading Language अभी भी विकास में है, लेकिन यह पहले से ही Three.js के नवीनतम संस्करणों में उपलब्ध है। इसे सीखने का सबसे अच्छा तरीका और परिवर्तनों पर नज़र रखने का तरीका यह है कि आप Three Shading Language विकी पेज देखें। मैंने इसे व्यापक रूप से इसका उपयोग करना सीखा है।
नोड आधारित मटेरियल
यह समझने के लिए कि TSL के साथ शेडर्स कैसे बनाए जाते हैं, हमें समझना होगा कि नोड-आधारित दृष्टिकोण क्या होता है।
एक नोड-आधारित दृष्टिकोण में, हम ग्राफ बनाने के लिए विभिन्न नोड्स को जोड़कर शेडर्स बनाते हैं। प्रत्येक नोड एक विशिष्ट ऑपरेशन या फ़ंक्शन का प्रतिनिधित्व करता है, और नोड्स के बीच के कनेक्शन डेटा के प्रवाह का प्रतिनिधित्व करते हैं।
इस दृष्टिकोण के कई फायदे हैं, जैसे कि:
- दृश्य प्रतिनिधित्व: एक शेडर में डेटा और ऑपरेशन्स के प्रवाह को समझना और दृश्य बनाना आसान होता है।
- पुन: प्रयोज्यता: हम पुन: प्रयोज्य नोड्स बना सकते हैं जो विभिन्न शेडर्स में उपयोग किए जा सकते हैं।
- लचीलापन: हम आसानी से एक शेडर के व्यवहार को बदल सकते हैं और उसमें जोड़ सकते हैं या नोड्स को हटा सकते हैं।
- विस्तारशीलता: मौजूदा मटेरियल से फीचर्स को जोड़ना/अनुकूलित करना अब आसान है।
- अज्ञेय: TSL लक्ष्य रेंडरर के लिए उपयुक्त कोड उत्पन्न करेगा, चाहे वह WebGL (GLSL) हो या WebGPU (WGSL)।
हमारे पहले नोड-आधारित मटेरियल का कोडिंग शुरू करने से पहले, हम ऑनलाइन Three.js खेल का मैदान का उपयोग करके नोड-सिस्टम के साथ विज़ुअल रूप से प्रयोग कर सकते हैं।
Three.js खेल का मैदान खोलें और ऊपर Examples बटन पर क्लिक करें, और basic > fresnel
चुनें।
आपको दो color
नोड्स और एक float
नोड के साथ एक नोड-आधारित मटेरियल संपादक देखना चाहिए, जो कि fresnel
नोड से जुड़ा हुआ है। (Color A
, Color B
, और Fresnel Factor
)
fresnel
नोड Basic Material
के रंग से जुड़ा हुआ है जिसके परिणामस्वरूप चायदानी को एक फ्रेनल प्रभाव के साथ रंगना होता है।
परिणाम का पूर्वावलोकन करने के लिए Splitscreen
बटन का उपयोग करें।
मान लें कि हम Basic Material
की अपारदर्शिता को समय के आधार पर प्रभावित करना चाहते हैं। हम एक Timer
नोड जोड़ सकते हैं और इसे Fract
नोड से कनेक्ट कर सकते हैं ताकि यह समय को 0 पर रीसेट कर दे जब यह 1 तक पहुंच जाए। फिर हम इसे Basic Material
के opacity
इनपुट से कनेक्ट करते हैं।
हमारी चायदानी अब चुंधाने लगती है फिर गायब हो जाती है और फिर से चुंधाने लगती है।
विभिन्न नोड्स के साथ खेलने के लिए समय निकालें और देखें कि वे मटेरियल को कैसे प्रभावित करते हैं।
अब जबकि हमारे पास नोड-आधारित मटेरियल के काम करने के तरीके की एक बुनियादी समझ है, आइए देखें कि React Three Fiber में Three.js से नए नोड-आधारित मटेरियल का उपयोग कैसे किया जाता है।
React Three Fiber कार्यान्वयन
अब तक, WebGL के साथ, हम हमारे सामग्री बनाने के लिए MeshBasicMaterial, MeshStandardMaterial, या यहां तक कि कस्टम ShaderMaterial का उपयोग कर रहे थे।
जब हम WebGPU का उपयोग करते हैं, तो हमें नए सामग्री का उपयोग करने की आवश्यकता होती है जो TSL के साथ संगत होते हैं। उनके नाम उसी प्रकार के होते हैं जैसे कि हमने पहले Node
के साथ Material
से पहले उपयोग किए थे:
MeshBasicMaterial
->MeshBasicNodeMaterial
MeshStandardMaterial
->MeshStandardNodeMaterial
MeshPhysicalMaterial
->MeshPhysicalNodeMaterial
- ...
उन्हें React Three Fiber के साथ डिक्लरेटिव रूप से उपयोग करने के लिए, हमें उन्हें extend
करना होता है। App.jsx
में:
// ... import { extend } from "@react-three/fiber"; extend({ MeshBasicNodeMaterial: THREE.MeshBasicNodeMaterial, MeshStandardNodeMaterial: THREE.MeshStandardNodeMaterial, }); // ...
React Three Fiber के भविष्य के संस्करणों में, यह स्वचालित रूप से किया जा सकता है।
अब हम अपने घटकों में नई MeshBasicNodeMaterial
और MeshStandardNodeMaterial
का उपयोग कर सकते हैं।
आइए हमारे Experience
घटक में क्यूब की MeshStandardMaterial
को MeshStandardNodeMaterial
से बदलें:
<mesh> <boxGeometry args={[1, 1, 1]} /> <meshStandardNodeMaterial color="pink" /> </mesh>
हम MeshStandardNodeMaterial
का उपयोग उसी तरह कर सकते हैं जैसे हम MeshStandardMaterial
का उपयोग करते थे।
हमारा क्यूब अब MeshStandardMaterial
के बजाय MeshStandardNodeMaterial
पर निर्भर कर रहा है। अब हम सामग्री को अनुकूलित करने के लिए नोड्स का उपयोग कर सकते हैं।
रंग नोड
आइए सीखते हैं कि कैसे हम TSL का उपयोग करके अपने मैटेरियल्स को पर्सनलाइज़ करने के लिए कस्टम नोड्स बनाएं।
सबसे पहले, src/components
फोल्डर में PracticeNodeMaterial.jsx
नाम का एक नया घटक बनाएं।
export const PracticeNodeMaterial = ({ colorA = "white", colorB = "orange", }) => { return <meshStandardNodeMaterial color={colorA} />; };
और Experience.jsx
में, हमारे क्यूब को PracticeNodeMaterial
का उपयोग करते हुए एक प्लेन के साथ बदल दें:
// ... import { PracticeNodeMaterial } from "./PracticeNodeMaterial"; export const Experience = () => { return ( <> {/* ... */} <mesh rotation-x={-Math.PI / 2}> <planeGeometry args={[2, 2, 200, 200]} /> <PracticeNodeMaterial /> </mesh> </> ); };
हमारे पास PracticeNodeMaterial
के साथ एक प्लेन है।
अपने मैटेरियल को कस्टमाइज़ करने के लिए, अब हम विभिन्न नोड्स का उपयोग कर सकते हैं जो हमारे पास उपलब्ध हैं। उपलब्ध नोड्स की सूची wiki page में पाई जा सकती है।
चलिए colorNode
नोड के साथ शुरू करते हैं ताकि हम अपने मैटेरियल के रंग को बदल सकें। PracticeNodeMaterial.jsx
में:
import { color } from "three/tsl"; export const PracticeNodeMaterial = ({ colorA = "white", colorB = "orange", }) => { return <meshStandardNodeMaterial colorNode={color(colorA)} />; };
हमने colorNode
प्रोप को three/tsl
मॉड्यूल के color
नोड का उपयोग करके सेट किया। color
नोड एक रंग को एक तर्क के रूप में लेता है और एक रंग नोड को वापस करता है जिसे मैटेरियल में उपयोग किया जा सकता है।
यह हमें पहले के समान परिणाम देता है, लेकिन अब हम अपने मैटेरियल को कस्टमाइज़ करने के लिए और अधिक नोड्स जोड़ सकते हैं।
चलिए three/tsl
मॉड्यूल से mix
और uv
नोड्स को आयात करें और उन्हें प्लेन के UV कॉर्डीनेट्स पर आधारित दो रंगों को मिलाने के लिए उपयोग करें।
import { color, mix, uv } from "three/tsl"; export const PracticeNodeMaterial = ({ colorA = "white", colorB = "orange", }) => { return ( <meshStandardNodeMaterial colorNode={mix(color(colorA), color(colorB), uv())} /> ); };
यह विभिन्न नोड्स को कार्यान्वित करेगा ताकि मैटेरियल का अंतिम रंग प्राप्त हो सके। mix
नोड दो रंग और एक फैक्टर (इस मामले में, UV कॉर्डीनेट्स) लेता है और फैक्टर के आधार पर दोनों रंगों का मिश्रित रंग वापस करता है।
यह GLSL में mix
फ़ंक्शन का उपयोग करने के समान ही है, लेकिन अब हम इसे एक नोड-बेस्ड दृष्टिकोण में उपयोग कर सकते हैं। (काफी अधिक पठनीय!)
हम अब दो रंगों को प्लेन के UV कॉर्डीनेट्स के आधार पर मिश्रित देख सकते हैं।
यह अद्भुत है कि हम शून्य से शुरू नहीं कर रहे हैं। हम मौजूदा MeshStandardNodeMaterial
का उपयोग कर रहे हैं और इसमें केवल अपने कस्टम नोड्स जोड़ रहे हैं। इसका मतलब है कि MeshStandardNodeMaterial
की छायाएँ, लाइट्स, और अन्य सभी विशेषताएँ अभी भी उपलब्ध हैं।
इनलाइन नोड्स को डिक्लेयर करना बहुत सरल नोड लॉजिक के लिए ठीक है, लेकिन अधिक जटिल लॉजिक के लिए, मैं आपको नोड्स (और बाद में uniforms, और अधिक) को useMemo
हुक में डिक्लेयर करने की सिफारिश करता हूँ:
// ... import { useMemo } from "react"; export const PracticeNodeMaterial = ({ colorA = "white", colorB = "orange", }) => { const { nodes } = useMemo(() => { return { nodes: { colorNode: mix(color(colorA), color(colorB), uv()), }, }; }, []); return <meshStandardNodeMaterial {...nodes} />; };
यह बिल्कुल पहले जैसा ही करता है, लेकिन अब हम और अधिक नोड्स को nodes
ऑब्जेक्ट में जोड़ सकते हैं और उन्हें meshStandardNodeMaterial
को अधिक संगठित/सामान्य तरीके से पास कर सकते हैं।
colorA
और colorB
प्रोप्स को बदलकर, यह शेडर की पुनः संकलन का कारण नहीं बनेगा, useMemo
हुक के धन्यवाद।
चलो मैटेरियल के रंगों को बदलने के लिए controls जोड़ते हैं। Experience.jsx
में:
// ... import { useControls } from "leva"; export const Experience = () => { const { colorA, colorB } = useControls({ colorA: { value: "skyblue" }, colorB: { value: "blueviolet" }, }); return ( <> {/* ... */} <mesh rotation-x={-Math.PI / 2}> <planeGeometry args={[2, 2, 200, 200]} /> <PracticeNodeMaterial colorA={colorA} colorB={colorB} /> </mesh> </> ); };
डिफॉल्ट रंग सही ढंग से काम कर रहा है, लेकिन रंगों के अपडेट का प्रभाव नहीं पड़ता है।
यह इसलिए है क्योंकि हमें meshStandardNodeMaterial
को uniforms
के रूप में रंगों को पास करने की आवश्यकता है।
Uniforms
TSL में uniforms को घोषित करने के लिए, हम three/tsl
मॉड्यूल से uniform
node का उपयोग कर सकते हैं। uniform
node एक मान को आर्ग्युमेंट के रूप में लेता है (यह विभिन्न प्रकारों का हो सकता है जैसे float
, vec3
, vec4
, आदि) और एक यूनिफॉर्म node लौटाता है जिसे विभिन्न नोड्स में उपयोग किया जा सकता है और हमारे कंपोनेंट कोड से अपडेट किया जा सकता है।
PracticeNodeMaterial.jsx
में हार्डकोडेड रंगों को uniforms में बदलें:
// ... import { uniform } from "three/tsl"; export const PracticeNodeMaterial = ({ colorA = "white", colorB = "orange", }) => { const { nodes, uniforms } = useMemo(() => { const uniforms = { colorA: uniform(color(colorA)), colorB: uniform(color(colorB)), }; return { nodes: { colorNode: mix(uniforms.colorA, uniforms.colorB, uv()), }, uniforms, }; }, []); return <meshStandardNodeMaterial {...nodes} />; };
हम कोड के बेहतर संगठन के लिए एक uniforms
ऑब्जेक्ट घोषित करते हैं, और नोड्स के निर्माण के समय प्राप्त डिफ़ॉल्ट मान के बजाय यूनिफॉर्म मानों का उपयोग करते हैं।
उन्हें useMemo
में लौटाकर, अब हमारे कंपोनेंट में यूनिफॉर्म्स तक पहुंच है।
useFrame
में हम यूनिफॉर्म्स को अपडेट कर सकते हैं:
// ... import { useFrame } from "@react-three/fiber"; export const PracticeNodeMaterial = ({ colorA = "white", colorB = "orange", }) => { // ... useFrame(() => { uniforms.colorA.value.set(colorA); uniforms.colorB.value.set(colorB); }); return <meshStandardNodeMaterial {...nodes} />; };
जब आप एक ऑब्जेक्ट यूनिफॉर्म को अपडेट करते हैं तो
value.set
मेथड का उपयोग करें। उदाहरण के लिए,color
याvec3
यूनिफॉर्म्स।float
यूनिफॉर्म्स के लिए, आपको मान को सीधे सेट करना होगा:uniforms.opacity.value = opacity;
अब रंग सही तरीके से रियल-टाइम में अपडेट हो रहे हैं।
रंग में अधिक करने से पहले, देखते हैं कि हम कैसे अपने plane के वर्टेक्स के पोजीशन को positionNode
का उपयोग करके प्रभावित कर सकते हैं।
Position Node
positionNode
नोड हमें हमारी ज्यामिति के वर्टेक्स के पोजीशन को प्रभावित करने की अनुमति देता है।
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.