برای به دست آوردن شعاع حجم نور، اساسا ما باید معادله attenuation را برای روشنایی که به نظر می رسد تیره باشد حل کنیم. ما فرض می کنیم که تاریک است ، این می تواند 0.0 یا چیزی کمی روشن تر باشد اما همچنان تاریک مانند 0.03 است. برای نشان دادن اینکه چگونه می توانیم شعاع حجم نور را محاسبه کنیم، می توانیم از یکی از توابع سخت افزاری تضعیف شده ای که ما در آموزش light casters معرفی کردیم استفاده کنیم:
آنچه که ما می خواهیم انجام دهیم، این است که معادله را برای زمانی که Flight 0.0 است، حل کنیم، هنگامی که نور در آن فاصله کاملا تاریک است. با این حال، این معادله دقیقا به مقدار 0.0 نمی رسد، بنابراین راه حل نخواهد بود. اما آنچه ما می توانیم انجام دهیم هرچند معادله 0.0 را حل نمی کند، اما آن را برای یک مقدار روشنایی که نزدیک به 0.0 است، اما هنوز آن را تیره می بینیم. مقدار روشنایی که ما برای این صحنه Demo آموزشی قابل قبول انتخاب می کنیم، 5/256 است؛ به طور پیشفرض فریم بافر 8 بیتی به 256 تقسیم می شود که می تواند بسیاری از شدت ها را بر هر جزء نشان دهد.
تابع تضعیف(attenuation ) عمدتا تاریک استفاده شده در محدوده قابل مشاهده است، بنابراین اگر ما آن را محدود به روشنایی حتی تاریک تر از 25/ 55، بکنیم حجم نور بیش از حد بزرگ می شود و در نتیجه کمتر موثر است. تا زمانی که یک کاربر نمی تواند یک قطع نور ناگهانی از منبع نور را در مرزهای حجم آن ببیند، خوب خواهد بود. البته این همیشه به نوع صحنه بستگی دارد؛ یک آستانه بالاتر روشنایی موجب کاهش حجم نور و در نتیجه کارایی بهتر می شود، اما می تواند مصنوعات قابل توجهی را تولید کند که در آن نور به نظر می رسد در یک مرز حجمی شکسته شود.
اینجا I max
عنصر رنگی ترین منبع نور است. ما از درخشان ترین مولفه نور منبع نور استفاده می کنیم، زیرا حل معادله برای شدت روشنایی نور، بهترین مقدار شعاع حجم نور را نشان می دهد.
از اینجا به بعد ما حل معادله را ادامه می دهیم:
عنصر رنگی ترین منبع نور است. ما از درخشان ترین مولفه نور منبع نور استفاده می کنیم، زیرا حل معادله برای شدت روشنایی نور، بهترین مقدار شعاع حجم نور را نشان می دهد.
از اینجا به بعد ما حل معادله را ادامه می دهیم:
آخرین معادله، یک معادله به فرم ax2 + bx + c = 0 است که ما می توانیم با استفاده از معادله درجه دوم حل کنیم:
این به ما یک معادله عمومی می دهد که به عنوان مثال به ما اجازه می دهد x را محاسبه کنیم. شعاع حجم نور برای منبع نور با توجه به پارامتر گرفته شده ثابت، خطی و درجه دوم:
این معادله تقریباً شعاع بین 1.0 و 5.0 را بر اساس بیشینه ی شدت نور بر می گرداند.
ما این شعاع را برای هر منبع نور صحنه محاسبه می کنیم و اگر یک فرگمنت در داخل منبع نور باشد فقط از آن برای محاسبه نور این منبع نور استفاده می کنیم. در زیر روشنایی به روز شده پاس نور در فرگمنت شیدراست که به حساب حجم نور محاسبه شده است. توجه داشته باشید که این رویکرد صرفا برای اهداف آموزشی انجام می شود و در یک محیط عملی قابل اجرا نیست، زیرا ما به زودی بحث خواهیم کرد:
نتایج دقیقا همانند قبل است، اما در این زمان هر نور فقط روشنایی برای منابع نور را محاسبه می کند که در آن حجم آن قرار دارد.
شما می توانید کد اصلی نسخه ی نمایشی را در اینجا پیدا کنید.
https://learnopengl.com/code_viewer_gh.php?code=src/5.advanced_lighting/8.2.deferred_shading_volumes/deferred_shading_volumes.cpp
شما می توانید کد اصلی نسخه ی نمایشی را در اینجا پیدا کنید.
https://learnopengl.com/code_viewer_gh.php?code=src/5.advanced_lighting/8.2.deferred_shading_volumes/deferred_shading_volumes.cpp
فرگمنت شیدر در بالا نشان داده شده در واقع واقعا کار نمی کند و فقط نشان می دهد که چگونه می توانیم از حجم نور برای کاهش محاسبات نور استفاده کنیم. واقعیت این است که GPU ها و GLSL شما در حلقه ها و شاخه های بهینه سازی بدی هستند. دلیل این امر این است که اجرای شیدر در GPU بسیار موازی است و اکثر معماریها نیاز دارند مجموعه ای بزرگ از thread ها کد شیدر یکسانی برای اجرا داشته باشند تا کارآمد باشند. این اغلب به این معنی است که یک شیدر همیشه تمام شاخه های یک دستور را اجرا می کند تا اطمینان حاصل شود که اجرای شیدر یکسان است، و بهینه سازی چک شعاع قبلی کاملا بی فایده است؛ ما هنوز روشنایی را برای همه منابع نور محاسبه میکنیم!
این کار برای هر منبع نور در صحنه انجام می شود و قطعات حاصل با هم ادغام می شوند. در نتیجه صحنه دقیقا مشابه همانند قبل است، اما این بار تنها بخش های مربوط به هر منبع نور را رندر می کنیم. این به طور موثر محاسبات از nr_objects * nr_lights را به nr_objects + nr_lights کاهش می دهد که باعث می شود آن را در صحنه های با تعداد زیادی از چراغ. به شدت کارآمد کند.این رویکرد باعث می شود deferred rendering برای رندر تعداد زیادی از چراغ ها مناسب باشد.
هنوز با این رویکرد مشکلی وجود دارد: face culling باید فعال باشد (در غیر این صورت ما می توانیم اثر نور را دو بار نشان دهیم) و هنگامی که فعال شود، کاربر ممکن است وارد حجم منبع نور شود در نتیجه بعد از آن حجم دیگر رندر نمی شود (به دلیل back-face culling) که این را با استفاده از ترفند Stencil Buffer برای حذف کردن تأثیر منبع نور می توان حل کرد.