برمجة الألوان : دورة OpenGL لغة c++ الدرس الثالث عشر


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

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

لو أردنا التعبير عن لون كورال في معادلة الرسم سوف نقوم باستخدام مكتبة متجهات glm على النحو التالي:

glm::vec3 coral(1.0f, 0.5f, 0.31f);

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

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


 


برمجة الألوان



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

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

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

 


مكونات الإضاءة

  1. مصدر الضوء.
  2. جسم قابل لاستقبال الإنعكاس.
  3. نتيجة الانعكاس.


يمكن اختصار جميع ما ذكر في الكود التالي:

glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor;

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

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

glm::vec3 lightColor(0.0f, 1.0f, 0.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor;

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

 

يمكنك الحصول على Header خاص في كاميرا اوبن جل قبل البدء في تطبيق الأمثلة , وذلك لكي تسهل عملية فهم الكود الجديد.[3]

 

 


تطبيق برمجة الألوان



لكي نتمكن من برمجة الألوان لا بد لنا من المرور في ملفات GLSL وخاصة مرحلة fragment shader.[1] سوف نحتاجه هو كائن موجود مسبقا ليتم تطبيق المعادلات عليه.[1] في حال كنت لا تجد أي إحداث لتمثيل عمليات الرسم يمكنك مشاهدة المراجع في المرفق أدناه.[2]

بحسب المصادر المرفقة لدينا سوف يتم إلغاء وجود متغيرات texture من ملف vertex Shader بالتالي يمكنك إلغاؤها مع الإبقاء على نظام الإحداثيات كما هو. ولأننا نريد إضافة lamp cube مكعب مضيء سوف نقوم بتوليد VAO جديدة لتلك المهمة وخاصة عند برمجة الألوان والأضواء.

نذهب الآن إلى مشروع OpenGL ونقوم بتعيين ملفات VAO من جديد لتصبح على النحو التالي.

GLuint lightVAO;
    glGenVertexArrays(1, &lightVAO);
    glBindVertexArray(lightVAO);
    
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glBind Vertex Array(0);

لا يتصف الكود بالصعوبة في بداية برمجة الألوان والأضواء. بالتالي لن يتم إعداد النسيج Texture أو مصفوفات indices على الإطلاق. سوف نتجه الآن إلى ملفات shaders لكي نتمكن من إضافة يونيفورم خاص. سوف يتضمن ذلك متغيرين الأول يشير إلى لون النموذج والثاني يشير إلى نموذج الضوء.

 

يعمل كل من الضوء وكائن الجسم المطبق عليه بمعادلات وملفات مختلفة من vertex shader و fragment shader. بالتالي تحتاج إلى إضافة أربع ملفات shader في هذا الدرس.

 


إعداد ملفات GLSL



لكي نتمكن من إعداد ملفات GLSL يجب أن ندرك بأن كل من الضوء والنموذج يحتويان على إحداثيات مختلفة ونماذج ظلال مستقلة عن بعضها البعض. بالتالي قد يتطلب الأمر إضافة ملفات مستقلة. وفي البداية سنعمل على إضافة ملفي lamp.frag و lamp.vs.

ملف lamp.vs

#version 330 core


layout (location = 0) in vec3 position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;


void main()
{
   gl_Position = projection * view * model * vec4(position, 1.0f);
}

بما أننا نريد برمجة الألوان في نظام الإحداثيات الجديد فإن صفات الضوء يجب أن تحتوي أيضًا على إحداثيات منظور الإسقاط كما تم إرفاقها في الكود.

ملف lamp.frag

#version 330 core


out vec4 color;

void main()
{
  color = vec4(1.0f); 
}

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

ملف lighting.vs

#version 330 core


layout (location = 0) in vec3 position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;


void main()
{
   gl_Position = projection * view * model * vec4(position, 1.0f);
}

 

ملف lighting.frag

#version 330 core


out vec4 color;
uniform vec3 objectColor;
uniform vec3 lightColor;


void main()
{
   color = vec4(lightColor * objectColor, 1.0f);
}

نلاحظ في الكود السابق أن ملفات lamp ليست سوى ضوء لا يمتلك أي معادلات خاصة من ملفات GLSL. بينما يشير الكائن إلى صفات مختلفة يكتسبها من مصادر الضوء المحيطة , وبالتالي نحن في صدد كتابة الأوامر المتعلقة بمزج الكائنات في كود المشروع.

lightingShaders = new OurShaders("C:/Users/Mmutawe/source/repos/Test OpenGL/Test OpenGL/shaders/lighting.vs", "C:/Users/Mmutawe/source/repos/Test OpenGL/Test OpenGL/shaders/lighting.frag");
lampShaders = new OurShaders("C:/Users/Mmutawe/source/repos/Test OpenGL/Test OpenGL/shaders/lamp.vs", "C:/Users/Mmutawe/source/repos/Test OpenGL/Test OpenGL/shaders/lamp.frag");

 

لقد قمنا باستدعاء جميع ملفات GLSL من خلال Class قمنا بإضافته مسبقًا . في حال وجدت بعض الصعوبات في تفعيل ملفات GLSL ندعوك لقراءة الدرس الثامن من أجزاء الدورة.

 


إعداد النموذج (Model)



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

GLuint modelVAO;
glGenVertexArrays(1, &modelVAO);
glGenBuffers(1, &VBO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBind Vertex Array(modelVAO);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBind Vertex Array(0);

وفي منطقة الاستدعاء يتم تطبيق الكود التالي:

//******************************************Model code*****************************************************
    lightingShaders->Use();
    GLint object Color Loc = glGetUniformLocation(lightingShaders->Program, "objectColor");
    GLint light Color Loc = glGetUniformLocation(lightingShaders->Program, "lightColor");
    glUniform3f(object Color Loc, 1.0f, 0.5f, 0.31f);
    glUniform3f(light ColorLoc, 1.0f, 0.5f, 1.0f);

    // Create camera 
    glm::mat4 view(1.0);
    view = camera.GetViewMatrix();
    glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)screen Width / (GLfloat)scrnHeight, 0.1f, 100.0f);
    // Get the uniform locations
    GLint modelLoc = glGetUniformLocation(lightingShaders->Program, "model");
    GLint viewLoc = glGetUniformLocation(lightingShaders->Program, "view");
    GLint projLoc = glGetUniformLocation(lightingShaders->Program, "projection");
    // Pass the matrices to the shader
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    // Draw the container (using container's vertex attributes)
    glBind Vertex Array(VAO);
    glm::mat4 model(1.0);
    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertex Array(0);
    //***********************************************************************************************************

عند محاولة تفعيل المشروع الآن ستجد النتائج التالية:

برمجة الألوان
صورة يظهر من خلالها تفعيل مكعب قبل تطبيق معادلات الضوء عليه.

 

لا بأس في حال قررت عرض الشاشة باللون الأسود ليتم البدء في عملية الإنارة. glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

 


إعداد نموذج الإضاءة



لكي نتمكن من إعداد نموذج الإضاءة يتوجب علينا تعريف متغير يقوم بتحديد موقع النموذج في مكان العرض. لذلك سوف نقوم بتفعيل متجه أعلى كود المشروع.

glm::vec3 lightPos(1.2f, 1.0f, 2.0f);

 

الآن في منطقة إعداد الكائن سوف نعمل على نسخ كود نموذج الإضاءة ليصبح على النحو التالي:

GLuint lightVAO;
glGenVertexArrays(1, &lightVAO);
glBind Vertex Array(lightVAO);
// We only need to bind to the VBO (to link it with glVertexAttribPointer), no need to fill it; the VBO's data already contains all we need.
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// Set the vertex attributes (only position data for the lamp))
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBind Vertex Array(0);

بينما يتم تمثيله على الرسم 3D عن طريق الكود التالي:

// Also draw the lamp object, again binding the appropriate shader
    lampShaders->Use();
    // Get location objects for the matrices on the lamp shader (these could be different on a different shader)
    modelLoc = glGetUniformLocation(lampShaders->Program, "model");
    viewLoc = glGetUniformLocation(lampShaders->Program, "view");
    projLoc = glGetUniformLocation(lampShaders->Program, "projection");
    // Set matrices
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
    model = glm::mat4(1.0);
    model = glm::translate(model, lightPos);
    model = glm::scale(model, glm::vec3(0.2f)); // Make it a smaller cube
    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
    // Draw the light object (using light's vertex attributes)
    glBindVertex Array(lightVAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertex Array(0);

 

برمجة الألوان
صورة يظهر من خلالها برمجة الألوان والإضاءة في مكتبة OpenGL.

 

في حال عدم تحرك الشاشة لا تنسى استدعاء كائن الكاميرا في كل من حركة الفأرة ولوحة المفاتيح. تستطيع العودة إلى مصادر الكود في أسفل المراجع.

 

 

 

المراجع
  1. [1]^ كتاب ـــــــ offline learn OpenGL created by Joey de Vries.
  2. [2]^ احداثيات النموذج.
  3. [3]^كائن الكاميرا.
  4. [4]^ كود المشروع من المصادر.

 

اترك تعليقاً

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