{
هاها، لقد تمت ترجمة هذين الدرسين منذ فترة طويلة، لكن لم يتم نشرهما بعد، لقد انتظر الجميع لفترة طويلة (هل من أحد ينتظر بعد الآن؟)
شفافية بسيطة
ترتبط الغالبية العظمى من المؤثرات الخاصة في OpenGL بنوع من خلط (الألوان).
يتم تعريف خلط الألوان على أنه دمج لون بكسل معين مع لون البكسل المقابل له المرسوم على الشاشة.
تعتمد كيفية دمج اللونين على قيم مكونات قناة ألفا للون، و/أو وظيفة مزج الألوان المستخدمة.
ألفا عادة ما يكون مكون اللون الرابع في نهاية قيمة اللون.
استخدمنا في الدروس السابقة GL_RGB لتحديد مكونات اللون الثلاثة.
يمكن لـ GL_RGBA المقابل تحديد قيمة مكون ألفا.
وللمضي قدمًا، يمكننا استخدام glColor4f() بدلاً من glColor3f().
يتفق معظم الناس على أن مكون ألفا يمثل شفافية المادة.
وهذا يعني أن قيمة ألفا 0.0 تمثل مادة شفافة تمامًا.
تمثل قيمة ألفا 1.0 مادة معتمة تمامًا.
صيغة خلط الألوان
إذا لم تكن مهتمًا بالرياضيات وتريد فقط معرفة كيفية تحقيق الشفافية، فتخط هذا القسم.
إذا كنت تريد فهمًا أعمق لكيفية عمل خلط (الألوان)، فيجب أن يكون هذا القسم مناسبًا لك.
『إضافة CKER: الأمر ليس صعبًا في الواقع ^-^. الصيغة في المقالة الأصلية هي كما يلي، دع CKER تتحدث عنها مرة أخرى.
في الواقع، المبدأ الأساسي للخلط هو فصل لون كل بكسل ولون خلفية الصورة المراد فصلهما وفقًا لقواعد RGB.
وفقًا لـ - مكون لون RGB للصورة * قيمة ألفا + مكون لون RGB للخلفية * (قيمة 1 ألفا)
- بعد الخلط بهذه الصيغة البسيطة، يتم أخيرًا إعادة دمج مكونات RGB التي تم الحصول عليها عن طريق الخلط. 』
الصيغة هي كما يلي:
(Rs Sr + Rd Dr، Gs Sg + Gd Dg، Bs Sb + Bd Db، As Sa + Ad Da)
يقوم برنامج OpenGL بحساب نتيجة خلط الألوان لهذين البكسلين وفقًا للصيغة المذكورة أعلاه.
تمثل الأحرف الصغيرة s وr وحدات البكسل المصدر والبكسلات المستهدفة على التوالي. الحرفان الكبيران S وD هما عوامل خلط الألوان المقابلة.
تحدد هذه كيفية مزج الألوان لتلك البكسلات.
في معظم الحالات، تكون قيم خلط ألفا لكل قناة لون هي نفسها.
بهذه الطريقة، لدينا (As، As، As، As) للبكسل المصدر،
البكسلات المستهدفة هي 1، 1، 1، 1) - (As، As، As، As).
تصبح الصيغة أعلاه كما يلي:
(Rs As + Rd (1 - As)، Gs As + Gd (1 - As)، Bs As + Bs (1 - As)، As + Ad (1 - As))
تنتج هذه الصيغة تأثيرًا شفافًا/شفافًا.
خلط الألوان في برنامج OpenGL
تشبه خطوات تنفيذ خلط الألوان في OpenGL عملية OpenGL التي ذكرناها من قبل.
ثم قم بتعيين الصيغة وإيقاف تشغيل ذاكرة التخزين المؤقت لعمق الكتابة عند رسم كائنات شفافة.
لأننا نريد رسم الجسم خلف شكل شبه شفاف.
هذه ليست الطريقة الصحيحة لمزج الألوان، لكنها تعمل بشكل جيد في معظم الأحيان في المشاريع البسيطة.
إضافة روي مارتينز: يجب أن تكون عملية مزج الألوان الصحيحة هي رسم المشهد بأكمله أولاً ثم رسم الرسومات الشفافة.
ويتم رسمها بترتيب عكسي للمخزن المؤقت للعمق (يتم رسم الكائنات الأبعد أولاً).
ضع في اعتبارك أن مزج ألفا لمضلعين (1 و2) سيؤدي إلى نتائج مختلفة.
(هنا يفترض أن المضلع 1 هو الأقرب إلى المراقب، فالعملية الصحيحة يجب أن ترسم المضلع 2 أولاً، ثم ترسم المضلع 1.
وكما ترون على أرض الواقع،
الضوء القادم من خلف هذين المضلعين <الشفافين> يمر دائمًا عبر المضلع 2 أولاً.
ثم يمر عبر المضلع 1، ويصل في النهاية إلى عيون المراقب. )
عند تمكين التخزين المؤقت العميق، يجب عليك فرز الرسومات الشفافة حسب العمق،
وارسم هذه الكائنات الشفافة بعد رسم جميع المشاهد. وإلا سوف تحصل على نتائج غير صحيحة.
أعلم أنه من المؤلم القيام بذلك في بعض الأحيان، لكن هذه هي الطريقة الصحيحة للقيام بذلك.
سوف نستخدم الكود من الدرس 7.
ابدأ بإضافة متغيرين جديدين في بداية الكود. لقد أعدت كتابة الكود بأكمله من أجل الوضوح.
}
فار
h_RC: HGLRC؛ // سياق العرض (جدول وصف التظليل).
h_DC: HDC // سياق الجهاز (جدول وصف الجهاز)
h_Wnd: HWND؛ // مقبض النافذة
h_Instance: HINST; // مثيل البرنامج (مثيل).
المفاتيح: صفيف [0..255] منطقي؛ // صفيف لإجراءات لوحة المفاتيح
ضوء: منطقي // مصدر الضوء تشغيل/إيقاف
مزيج: منطقي؛ // إيقاف/تشغيل المزج (جديد)
lp : Boolean; // هل تم الضغط على المفتاح L؟
fp : منطقية؛ // هل تم الضغط على المفتاح F؟
bp: منطقية؛ // هل تم الضغط على المفتاح B (جديد)؟
xrot : GLfloat;
yrot : GLfloat؛ // Y التناوب
xspeed : GLfloat؛ // X سرعة الدوران
yspeed : GLfloat؛ // Y سرعة الدوران
z : GLfloat = -5.0 f;
LightAmbient: Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0); // معلمات الإضاءة المحيطة (جديد)
LightDiffuse: Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0); // معلمات الضوء المنتشرة (جديد)
LightPosition: Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0); // موضع مصدر الضوء (جديد)
عامل التصفية: GLuint؛ // نوع المرشح
نسيج: صفيف [0..2] من GLuint؛ // مساحة تخزين لثلاث مواد
PROcedure glGenTextures(n: GLsizei; var contexts: GLuint);
opengl32;
الإجراء glBindTexture(target: GLenum;texture: GLuint);
opengl32;
وظيفة gluBuild2DMipmaps (الهدف: GLenum؛ المكونات، العرض، الارتفاع: GLint؛
التنسيق، النوع: GLenum؛ البيانات: المؤشر): عدد صحيح؛ اسم glu32 الخارجي؛
'gluBuild2DMipmaps';
{
ثم انتقل للأسفل إلى LoadGLTextures().
ابحث عن ما إذا كان (TextureImage[0]=LoadBMP('Data/Crate.bmp'))
هذا الخط. نحن الآن نستخدم نسيج زجاجي ملون بدلاً من نسيج الصندوق الخشبي من الدرس السابق.
if (TextureImage[0]=LoadBMP("Data/glass.bmp")); // تحميل الصورة النقطية الزجاجية (معدلة)
}
الوظيفة LoadTexture: boolean; // قم بتحميل الصورة النقطية وتحويلها إلى نسيج
فار
الحالة: منطقية؛
TextureImage : Array[0..1] Of PTAUX_RGBImageRec;
يبدأ
الحالة := خطأ؛
ZeroMemory(@TextureImage, sizeof(TextureImage)); // اضبط المؤشر على NULL
TextureImage[0] := LoadBMP('Walls.bmp');
إذا TextureImage[0] <> Nil إذن
يبدأ
الحالة := TRUE؛ // اضبط الحالة على TRUE
glGenTextures(1, الملمس[0]); // إنشاء نسيج
// إنشاء أقرب خريطة مرشح
glBindTexture(GL_TEXTURE_2D, الملمس[0]);
// توليد الملمس
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data);
glBindTexture(GL_TEXTURE_2D, الملمس[1]); // استخدم نسيجًا نموذجيًا تم إنشاؤه من بيانات الصورة النقطية
// توليد الملمس
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // التصفية الخطية
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// إنشاء نسيج MipMapped
glBindTexture(GL_TEXTURE_2D, الملمس[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST // (جديد) ؛
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0].sizeX,
TextureImage[0].sizey، GL_RGB، GL_UNSIGNED_BYTE،
TextureImage[0].data); //(جديد) }
نهاية؛
إذا تم تعيينه (TextureImage[0]) ثم // ما إذا كان النسيج موجودًا أم لا
إذا تم تعيينه (TextureImage[0].data) ثم // ما إذا كانت صورة النسيج موجودة أم لا
TextureImage[0].data := Nil; // حرر الذاكرة التي تشغلها صورة النسيج
TextureImage[0] := Nil; // حرر بنية الصورة
النتيجة: = الحالة // حالة العودة
نهاية؛
{
أضف السطرين التاليين إلى قسم التعليمات البرمجية glInit().
يرسم السطر الأول هذا الكائن بكامل سطوعه ويمنحه مزج ألفا بنسبة 50% (شبه شفاف).
عند تشغيل خيار المزج، سيكون هذا الكائن شفافًا بنسبة 50%.
يحدد السطر الثاني نوع المزج المستخدم.
أضيفت بواسطة روي مارتينز:
قيمة قناة ألفا 0.0 تعني أن مادة الكائن شفافة تمامًا.
1.0 يعني معتم تمامًا.
}
الإجراء glInit(); // ابدأ جميع إعدادات OpenGL هنا
يبدأ
إذا (لم يتم تحميل النص) ثم // اتصل بالروتين الفرعي لتحميل النسيج
خروج؛ // إذا فشل التحميل، قم بالخروج
glEnable(GL_TEXTURE_2D); // تمكين تعيين النسيج
glShadeModel(GL_SMOOTH); // تمكين تجانس الظل
glClearColor(0.0, 0.0, 0.0, 0.0); // خلفية سوداء
glClearDepth(1.0); // تعيين المخزن المؤقت للعمق
glEnable(GL_DEPTH_TEST); // تمكين اختبار العمق
glDepthFunc(GL_LESS); // نوع اختبار العمق الذي تم إجراؤه
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // حساب إسقاط المنظور الأمثل للغاية
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]); // ضبط الإضاءة المحيطة
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]); // ضبط الضوء المنتشر
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // موضع مصدر الضوء
glEnable(GL_LIGHT1); // تمكين مصدر الضوء رقم 1
glColor4f(1.0, 1.0, 1.0, 0.5); // سطوع كامل، مزج ألفا بنسبة 50% (جديد)
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // دالة مزج شفافة تعتمد على قيمة قناة ألفا للبكسل المصدر (جديد)
نهاية؛
{ابحث عن مقتطف الكود التالي بالقرب من نهاية الدرس 7.
إذا كانت المفاتيح [VK_LEFT] إذن // هل يتم الضغط على مفتاح الاتجاه الأيسر؟
yspeed := yspeed - 0.01; //إذا كانت الإجابة بنعم، فقم بتقليل yspeed
باتباع الكود أعلاه، نضيف الكود التالي.
تراقب هذه الخطوط ما إذا تم الضغط على المفتاح B.
إذا كان الأمر كذلك، فإن الكمبيوتر يتحقق لمعرفة ما إذا كان خيار المزج قيد التشغيل.
ثم اضبطه على الحالة المعاكسة.
}
إذا (المفاتيح [ord('B')] وليس bp) ثم // تم الضغط على المفتاح B وكانت bp خاطئة؟
يبدأ
bp := TRUE; // إذا كانت الإجابة بنعم، فسيتم ضبط bp على TRUE
مزيج := غير مزيج // تبديل خيارات المزج إلى TRUE / FALSE
إذا (مزج) إذن // هل المزج قيد التشغيل؟
يبدأ
glEnable(GL_BLEND); // تشغيل المزج
glDisable(GL_DEPTH_TEST); // إيقاف تشغيل اختبار العمق
نهاية
غير ذلك // غير ذلك
يبدأ
glDisable(GL_BLEND); // إيقاف تشغيل المزج
glEnable(GL_DEPTH_TEST); // تشغيل اختبار العمق
نهاية؛
نهاية؛
إذا (ليست مفاتيح[ord('B')]) إذن // هل تم تحرير المفتاح B؟
يبدأ
bp := FALSE; // إذا كانت الإجابة بنعم، فاضبط bp على FALSE
نهاية؛
{
ولكن كيف يمكنك تحديد لون المزيج عند استخدام رسم خرائط النسيج؟ الأمر بسيط للغاية.
عند ضبط وضع النسيج، يتم تحديد لون كل بكسل من نسيج النسيج بواسطة معلمة قناة ألفا.
يتم الحصول عليها عن طريق ضرب لون البكسل الحالي.
على سبيل المثال، اللون المرسوم هو (0.5، 0.6، 0.4)،
سنضرب الألوان ببعضها لنحصل على (0.5، 0.6، 0.4، 0.2)
(عندما لا يتم تحديد معلمة ألفا، تكون القيمة الافتراضية صفر).
هذا كل شيء! يعد تنفيذ مزج Alpha في OpenGL أمرًا بسيطًا للغاية!
}
{
المذكرة الأصلية (13/11/99)
تم تعديل كود خلط الألوان الخاص بي (NeHe) لجعل الكائنات المعروضة تبدو أكثر واقعية.
سيؤدي استخدام معلمة ألفا لمزج وحدات البكسل المصدر وبكسلات الوجهة في نفس الوقت إلى ظهور الآثار الاصطناعية للكائن بشكل واضح.
سيؤدي ذلك إلى جعل الجزء الخلفي من الجسم يبدو أغمق على طول الجوانب.
في الأساس سوف يبدو الكائن غريبًا.
قد لا تكون طريقة مزج الألوان التي استخدمتها هي الأفضل، لكنها ناجحة.
مع تمكين الأضواء، تبدو الأشياء واقعية.
شكرًا لتوم على تقديم الكود الأصلي. طريقة مزج الألوان التي استخدمها صحيحة.
ولكن الكائن لا يبدو جذابا كما هو متوقع :)
تم تعديل الكود مرة أخرى بسبب معالجة المشكلات المتعلقة بوظيفة glDepthMask() على بعض بطاقات الرسومات.
لا يبدو أن هذا الأمر فعال جدًا عند تمكين أو تعطيل اختبار المخزن المؤقت للعمق على بعض البطاقات،
لذلك قمت بتحويل الكود لتمكين أو تعطيل اختبار المخزن المؤقت للعمق إلى glEnable وglDisable من الطراز القديم.
مزج ألفا لخرائط النسيج
يمكن قراءة معلمة ألفا المستخدمة لخريطة النسيج من خريطة المشكلة تمامًا مثل اللون.
الطريقة هي كما يلي، تحتاج إلى تحميل المادة المطلوبة والحصول على معلمة ألفا الخاصة بها في نفس الوقت.
ثم استخدم تنسيق الألوان GL_RGBA عند استدعاء glTexImage2D().
}