Render Target
عند استخدام React Three Fiber، نقوم ببساطة بإضافة مكون Canvas
ووضع مشهدنا ثلاثي الأبعاد داخله ليتم عرضه على الشاشة.
إذا كان لديك بعض الخبرة مع Three.js، فأنت تعلم أننا نحتاج أولاً إلى إنشاء WebGLRenderer
ثم نستدعي renderer.render(scene, camera)
لعرض المشهد على الشاشة.
لحسن الحظ، يقوم React Three Fiber بكل هذا تلقائيًا، ولكن في حالات الاستخدام المتقدمة، من المهم معرفة كيفية عمله.
دور renderer هو معالجة المشهد ثلاثي الأبعاد لإنشاء الصورة ثنائية الأبعاد التي نراها على الشاشة.
افتراضيًا، يكون مخرج renderer مضبوطًا على مكون Canvas
ويُعرض على الشاشة، ولكن يمكننا أيضًا إخراجه كملمس (عبر WebGLRenderTarget
).
لأول وهلة قد يبدو الأمر نظريًا بعض الشيء، فلنرى كيف يعمل في الممارسة العملية وبأي طرق إبداعية يمكننا استخدامه.
كاميرا أمنية
لفهم كيفية عمل Render Targets وما يمكننا فعله بها، أعددت مشهدًا ثلاثي الأبعاد يحتوي على:
- نموذج غرفة معيشة ثلاثي الأبعاد بواسطة Alex Safayan CC-BY عبر Poly Pizza
- أفاتار Ready Player Me (كما نستخدمه في دروس البورتفوليو) يشاهد سبونج بوب سكوير بانتس على التلفاز
- جهاز تحكم عن بعد ثنائي الأبعاد يحتوي على أزرار متعددة
والهدف هو إنشاء نظام مراقبة من خلال عرض المشهد من منظور كاميرا أمنية على التلفاز.
التحويل إلى النسيج (Texture) في المشهد
لتحويل مشهدنا الحالي إلى نسيج، سنحتاج إلى إنشاء Render Target.
بفضل مكتبة Drei، يمكننا بسهولة إنشاء Render Target باستخدام الخطاف useFBO
:
// ... import { useFBO } from "@react-three/drei"; export const Experience = () => { const cornerRenderTarget = useFBO(); // ... };
إذا كنت تريد معرفة كيفية إنشاء Render Target من البداية، يمكنك الاطلاع على الكود المصدري للخطاف
useFBO
هنا. من الجيد أن تعرف كيف تعمل الأشياء في العمق.
الآن بعد أن أصبح لدينا Render Target، نحتاج إلى إخبار العارض (renderer) لتحويل scene
باستخدام camera
.
كل هذه الكائنات متوفرة في حالة الجذر في تطبيق React Three Fiber الخاص بنا. وهذا هو الكائن الذي يُعاد بواسطة الخطاف useThree
.
الخاصية
gl
هي العارض (renderer).
لكن، بما أننا نريد عرض ما يحدث في الوقت الحقيقي على التلفاز، سنقوم بالعملية مع كل إطار باستخدام الخطاف useFrame
.
تشمل وظيفة الاسترجاع (callback) حالة الجذر لكي نتمكن من الوصول مباشرة إلى متغيراتنا منها:
// ... import { useFrame } from "@react-three/fiber"; export const Experience = () => { // ... useFrame(({ gl, camera, scene }) => { gl.setRenderTarget(cornerRenderTarget); gl.render(scene, camera); gl.setRenderTarget(null); }); // ... };
ما نقوم به هنا هو:
- تعيين Render Target كمخرج الـ العارض (renderer)
- تحويل
scene
باستخدامcamera
ولأن مخرج الـ العارض (renderer) تم تعيينه إلى Render Target، فسيقوم بتحويل المشهد إليه - تعيين مخرج الـ العارض (renderer) إلى
null
لتحويل المشهد مرة أخرى إلى اللوحة
الآن بعد أن أصبح لدينا Render Target، نحتاج إلى عرضه على التلفاز. دعونا نضف مرجع للمادة التي تقوم حالياً بعرض الفيديو:
// ... import { useRef } from "react"; export const Experience = () => { // ... const tvMaterial = useRef(); // ... return ( <> {/* ... */} <group position-y={-0.5}> <group> <Sky /> <Avatar rotation-y={Math.PI} scale={0.45} position-z={0.34} /> <Gltf src="models/Room.glb" scale={0.3} rotation-y={-Math.PI / 2} /> <mesh position-x={0.055} position-y={0.48} position-z={-0.601}> <planeGeometry args={[0.63, 0.44]} /> <meshBasicMaterial ref={tvMaterial} /> </mesh> </group> </group> {/* ... */} </> ); };
ثم يمكننا استخدام الخطاف useFrame
لتحديث خاصية map
للمادة باستخدام Render Target الخاص بنا:
// ... export const Experience = () => { // ... useFrame(({ gl, camera, scene }) => { // ... tvMaterial.current.map = cornerRenderTarget.texture; }); // ... };
يمكننا الآن رؤية عرض الكاميرا الأمنية على التلفاز لكن شاشة التلفاز في مشهد الكاميرا الأمنية فارغة.
هذا لأننا عندما نقوم بتحويل المشهد إلى Render Target، تكون شاشتنا فارغة.
تأثير Inception
لرؤية عرض كاميرا الأمان داخل شاشة التلفاز لشاشة التلفاز 🤯، نحتاج إلى:
- إنشاء هدف render آخر (سنطلق عليه
bufferRenderTarget
) - اجعل المشهد يُعرض عليه
- قم بإرفاقه بـ material شاشة التلفاز
- اجعل المشهد يُعرض على
cornerRenderTarget
- قم بإرفاقه بـ material التلفاز
// ... export const Experience = () => { const bufferRenderTarget = useFBO(); // ... useFrame(({ gl, camera, scene }) => { gl.setRenderTarget(bufferRenderTarget); gl.render(scene, camera); tvMaterial.current.map = bufferRenderTarget.texture; gl.setRenderTarget(cornerRenderTarget); gl.render(scene, camera); gl.setRenderTarget(null); tvMaterial.current.map = cornerRenderTarget.texture; }); // ... };
قد يبدو الأمر مخيفًا ولكنه في الواقع بسيط جدًا. فقط فكر فيما يحدث في كل خطوة.
الآن مشهدنا يُعرض بشكل لا نهائي داخل شاشة التلفاز!
حتى لو كان هذا هو التأثير الأكثر واقعية الذي يمكننا إنشاؤه، إلا أنه ليس الأكثر إبداعًا. دعنا نزيل تأثير inception ونعرض Spongebob Squarepants على الشاشة بدلاً من ذلك:
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.