تمثيل الإضاءة : دورة OpenGL لغة c++


تمثيل الإضاءة هي استئناف ما قمنا به في خريطة الأضواء في الدرس السابق. حيث أننا قمنا بالفعل باستخدام جميع الأضواء القادمة من مصدر واحد.[1] على الرغم من أن النتائج كانت جيدة إلا أننا سوف نحتاج إلى الإضاءة لاستخدامها في مصادر متعددة .[1]في هذا الدرس سوف نناقش العديد من أنواع تمثيل الإضاءة لكي نتمكن من محاكاة أنواع مختلفة من مصادر الضوء وتحقيق مزايا العالم الحقيقي.[1] بالتالي يتم الآن مناقشة الضوء ذات الإتجاه والتعمق في مفهوم spotlight. ما يعني دمج العديد من الأدوات في المشهد الواحد.[1]


لكي تتمكن من استكمال هذا الدرس يجب عليك أولا إدراك مفاهيم ومعادلات الضوء التي قمنا بشرحها سابقًا.[1]

 


تمثيل الإضاءة ذات الإتجاه



غالبا ما تشير الأضواء ذات الاتجاه إلى أشعة الضوء القادمة من مصدر الضوء بشكل موازي للنموذج.[1] ما يعني أن جميع مصادر الإضاءة كانت قادمة من مصدر واحد مع الأخذ بعين الاعتبار مواقع مختلفة من النموذج.[1] تساعدنا الأضواء ذات الإتجاه على تمثيل الإضاءة ولأن جميع أشعة الضوء ذات الإتجاه موازية للأسطح .[1] إلا أنها لا تقدم انعكاسات دقيقة للأسطح المرادفة والمخفية عن الإشعاع المباشر.[1]

عند استخدام أضواء ذات اتجاه في تمثيل الإضاءة فإننا نستغني عن متغير position في ملف model.frag ونضع مكانه vec3 direction.[1] بالتالي سوف نقوم بإجراء تعديل على Structure الإضاءة ليصبح على النحو التالي:

struct Light {
// vec3 position; // No longer necessary when using directional lights.
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};

نجري أيضًا تعديل على متغير lightDir ليصبح على النحو التالي:

vec3 lightDir = normalize(-light.direction);

سوف تلاحظ بأننا قمنا بجعل قيمة light.direction سالبة والسبب في ذلك بأننا قمنا بإجراء المعادلة من جهة النموذج على عكس بعض المطورين الذين يفضلون إجراء المعادلات من مصدر الضوء.[1]

نقوم الآن بمضاعفة أعداد المكعبات التي قمنا بتحضيرها مسبقا. وذلك لكي نحصل على فوارق متعددة في اختلاف شدة الإضاءة.[1] بالتالي يتم تطبيق الكود التالي في المشروع وهو عبارة عن حلقة تكرارية لتمثيل 10 مكعبات باتجاهات عشوائية.[1]

for(GLuint i = 0; i < 10; i++)
{
model = glm::mat4();
model = glm::translate(model, cubePositions[i]);
GLfloat angle = 20.0f * i;
model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}

نقوم الآن بتفعيل تمثيل الإضاءة من خلال يونيفورم في حلقة while الخاصة بالمشروع على النحو التالي:

GLint lightDirPos = glGetUniformLocation(lightingShaders->Program, "light.direction");
        glUniform3f(light Dir Pos, -0.2f, -1.0f, -0.3f);
تمثيل الإضاءة
صورة يظهر فيها تمثيل الإضاءة Directional في مكتبة OpenGL.

 

 


الإضاءة النقطية (Point light)



تعد النقطية إحدى وسائل تمثيل الإضاءة على الكائنات وبالرغم من أن إضاءة Directional جيدة إلى حد ما في الفضاء إلا أن هناك تداخل في الإشعاعات سوف يطرأ عند استخدام مصادر الضوء المتعددة.[1] تعمل الإضاءة النقطية على انتشار مدى قوة الضوء على أجسام متعددة بمقدار ليس ثابت. على عكس إضاءة Directional والتي توفر كامل الانتشار بنفس المقدار على الأجسام.[1]

ظهر اصطلاح يطلق عليه attenuation وهو يعمل على نشر الضوء بنسب متفاوتة وفقا لأمور عدة منها حجم السطح ومدى القرب من اتجاه الضوء بحيث يقل الإشعاع بالتدريج كلما أبتعدنا عن المصدر.[1] يمكن استخدام معادلة attenuation  أيضا على ضبابية المشهد (جو مغبر مليء بالضباب).[1]

نقوم الآن بتنفيذ الكود التالي على structure الخاص بـ model.frag. ليصبح على النحو التالي:

struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};

الآن نقوم بتعيين الشروط والقيم بالتالي يتم التواصل مع معادلات الضباب على أنها يونيفورم. ندعوك إلى اضافة الكود التالي في المشروع.

glUniform1f(glGetUniformLocation(lightingShaders->Program, "light.constant"),1.0f);
    glUniform1f(glGetUniformLocation(lightingShaders->Program, "light.linear"),0.09);
    glUniform1f(glGetUniformLocation(lightingShaders->Program, "light.quadratic"), 0.032);

على سبيل المثال , فإن تطبيق معادلات attenuation أمر مباشر في ملف model.frag.[1] بالتالي يتم حساب القيم بناء على ضرب المتجهات بـ ambient. نستطيع إعداد تمثيل الإضاءة عن طريق احتساب المسافة distance لمصادر الضوء.[1]

نقوم أولا بإضافة المعادلة التالية في ملف model.frag.[1]

float distance = length(light.position - Position);
float attenuation = 1.0f / (light.constant + light.linear * distance +
light.quadratic * (distance * distance));
تمثيل الإضاءة
صورة يظهر فيها تفعيل Attenuation في تمثيل الإضاءة.

تلاحظ في الصورة السابقة لقد تم استقبال اشعة تمثيل الضوء بشكل جيد بدرجات متفاوتة على حسب أماكن واتجاهات كل صندوق.[1] بالتالي يمكن الاعتماد على معادلة Point light في محركات الرسم حيث أنها لا تستنزف الكثير من الموارد.[1]

 


تمثيل الإضاءة على أضواء الكشاف (Spotlight)



تعد أضواء الكشاف واحدة من طرق تمثيل الضوء في مكتبة OpenGL فهي تختلف عن الإضاءة السابقة بأنها لا تطلق الأشعة بكافة الاتجاهات وإنما تحصرها في دائرة مكثفة من المتجهات.[1] على سبيل المثال عند تشغيل كشاف ضوئي على حائط فإنك سوف تلاحظ بوجود دائرة ضوئية منبثقة في الإضاءة.[1]

يتطلب منا تطبيق تمثيل الإضاءة spotlight العديد من التعديلات على كود model.frag متمثلة بإضافة متغيرين الأول متجه direction والثاني هو زاوية cut off وهي المسؤولة عن قص الإضاءة بشكل دائري.[1]

بالتالي نعمل على إضافة المتغيرين إلى light structure:

vec3 direction;
float cutOff;

نقوم بالاتصال في هذه المتغيرات عن طريق معادلات يونيفورم التالية:

GLint lightSpotdirLoc = glGetUniformLocation(lightingShaders->Program, "light.direction");
    GLint lightSpotCutOffLoc = glGetUniformLocation(lightingShaders->Program, "light.cutOff");

    glUniform3f(lightPosLoc, camera.Position.x, camera.Position.y,camera.Position.z);
    glUniform3f(light Spot dir Loc, camera.Front.x, camera.Front.y, camera.Front.z);
    glUniform1f(lightSpotCutOffLoc, glm::cos(glm::radians(12.5f)));

الآن يتم إجراء تغيير على كود void main المتعلق بملف model.frag على النحو التالي:

vec3 lightDir = normalize(light.position - FragPos);
   
   // Check if lighting is inside the spotlight cone
   float theta = dot(lightDir, normalize(-light.direction)); 
   
   if(theta > light.cutOff) .
   {    
       // Ambient
       vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
       
       // Diffuse 
       vec3 norm = normalize(Normal);        
       float diff = max(dot(norm, lightDir), 0.0);
       vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));  
       
       // Specular
       vec3 viewDir = normalize(viewPos - FragPos);
       vec3 reflectDir = reflect(-lightDir, norm);  
       float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
       vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
       
       // Attenuation
       float distance    = length(light.position - FragPos);
       float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * (distance * distance));    

       // ambient  *= attenuation;    ambient lighting).
       diffuse  *= attenuation;
       specular *= attenuation;   
               
       color = vec4(ambient + diffuse + specular, 1.0f);  
   }
   else    .
       color = vec4(light.ambient * vec3(texture(material.diffuse, TexCoords)), 1.0f);
تمثيل الإضاءة على spotlight
صورة يظهر فيها تفعيل spotlight على كاميرا العرض في مكتبة OpenGL.

 

 

المراجع
  1. [1]^ كتاب ـــــــ offline learn OpenGL created by Joey de Vries.
  2. [2]^ مصادر مشروع Directional light ______  ملف model.frag.
  3. [3]^ مصادر مشروع Point light _________ ملف model.frag.
  4. [4]^ مصادر مشروع Spot light __________ ملف model.frag.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *