
كل مزاج جيد وانخفاض درجة الحرارة خارج النافذة. كما وعدت ، أنا نشر استمرارا لمقال عن المخادع السوبر من OpenGL الحديثة. الذي لم يقرأ الجزء الأول -
Ultramodern برنامج OpenGL. الجزء 1ربما تكون محظوظًا ويمكنني دفع جميع المواد المتبقية إلى هذا المقال ، هذا ليس مؤكدًا ...
صفيف الملمس
تمت إضافة صفيفات النسيج مرة أخرى في OpenGL 3.0 ، ولكن لسبب قليل من الناس يكتبون عنها (يتم إخفاء المعلومات بشكل موثوق من قبل الماسونيين). جميعكم معتادون على البرمجة ويعرفون ما
هي المصفوفة ، على الرغم من أنني أفضل "النهج" من الجانب الآخر.
لتقليل عدد التبديل بين القوام ، ونتيجة لذلك ، لتقليل عمليات تبديل الحالة ، يستخدم الناس
أطلسات الملمس (مادة تخزن البيانات للعديد من الكائنات). لكن الرجال الأذكياء من خرونوس طوروا بديلاً لنا - نسيج الصفيف. الآن يمكننا تخزين القوام كطبقات في هذه المجموعة ، أي أنها بديلة للأطالس. يحتوي OpenGL Wiki على وصف مختلف قليلاً عن خرائط mipmaps ، وما إلى ذلك ، ولكنه يبدو معقدًا جدًا بالنسبة لي (
link ).
تتمثل مزايا استخدام هذه الطريقة مقارنة بالأطالس في أن كل طبقة تعتبر نسيجًا منفصلاً من حيث الالتفاف والتخطيط.
ولكن مرة أخرى إلى الكباش لدينا ... مجموعة الملمس لديه ثلاثة أنواع من الهدف:
- GL_TEXTURE_1D_ARRAY
- GL_TEXTURE_2D_ARRAY
- GL_TEXTURE_CUBE_MAP_ARRAY
رمز لإنشاء مجموعة نسيج:
GLsizei width = 512; GLsizei height = 512; GLsizei layers = 3; glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &texture_array); glTextureStorage3D(texture_array, 0, GL_RGBA8, width, height, layers);
لاحظت أكثر من يقظة أننا نقوم بإنشاء مستودع للمواد ثنائية الأبعاد ، ولكن لسبب ما نستخدم مجموعة ثلاثية الأبعاد ، لا يوجد خطأ أو خطأ مطبعي. نقوم بتخزين القوام ثنائي الأبعاد ، ولكن نظرًا لوجودها في "طبقات" ، نحصل على مصفوفة ثلاثية الأبعاد (في الواقع ، يتم تخزين بيانات البيكسل وليس القوام. تحتوي المصفوفة ثلاثية الأبعاد على طبقات ثنائية الأبعاد مع بيانات البيكسل).
من السهل أن نفهم مثال الملمس 1D. كل سطر في صفيف بكسل 2D هو طبقة 1D منفصلة. يمكن أيضًا إنشاء مواد Mipmap تلقائيًا.
في هذا الصدد ، كل الصعوبات تنتهي وإضافة صورة إلى طبقة معينة بسيطة للغاية:
glTextureSubImage3D(texarray, mipmap_level, offset.x, offset.y, layer, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
عند استخدام المصفوفات ، نحتاج إلى تغيير التظليل قليلاً
#version 450 core layout (location = 0) out vec4 color; layout (location = 0) in vec2 texture_0; uniform sampler2DArray texture_array; uniform uint diffuse_layer; float getCoord(uint capacity, uint layer) { return max(0, min(float(capacity - 1), floor(float(layer) + 0.5))); } void main() { color = texture(texture_array, vec3(texture_0, getCoord(3, diffuse_layer))); }
قد يكون الخيار الأفضل هو حساب الطبقة المرغوبة خارج التظليل ، لذلك يمكننا استخدام
UBO /
SSBO (يستخدم أيضًا لنقل المصفوفات والعديد من البيانات الأخرى ، لكنه وقت آخر بطريقة أو بأخرى). إذا لم يستطع أحد انتظار
tyk_1 و
tyk_2 ، فيمكنك القراءة.
بالنسبة للأحجام ، أي GL_MAX_ARRAY_TEXTURE_LAYERS وهو 256 في OpenGL 3.3 و 2048 في OpenGL 4.5.
تجدر الإشارة إلى كائن Sampler Object (غير مرتبط بنسيج Array ، ولكنه شيء مفيد) - هذا كائن يُستخدم لضبط حالة وحدة نسيج ، بغض النظر عن الكائن المتصل حاليًا بالوحدة. يساعد في فصل حالات العينات عن كائن نسيج معين ، مما يحسن التجريد.
GLuint sampler_state = 0; glGenSamplers(1, &sampler_state); glSamplerParameteri(sampler_state, GL_TEXTURE_WRAP_S, GL_REPEAT); glSamplerParameteri(sampler_state, GL_TEXTURE_WRAP_T, GL_REPEAT); glSamplerParameteri(sampler_state, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(sampler_state, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glSamplerParameterf(sampler_state, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
لقد قمت للتو بإنشاء كائن لأخذ العينات ، وتمكين التصفية الخطية وفلتر متباين الخواص 16x لأي وحدة نسيج.
GLuint texture_unit = 0; glBindSampler(texture_unit, sampler_state);
نحن هنا نربط العينات فقط بوحدة النسيج المطلوبة ، وعندما يتوقف عن أن تكون bindim 0 المطلوبة لهذه الوحدة.
glBindSampler(texture_unit, 0);
عندما قمنا بربط جهاز أخذ العينات ، فإن إعداداته لها الأسبقية على إعدادات وحدة النسيج. النتيجة: ليست هناك حاجة لتعديل قاعدة التعليمات البرمجية الموجودة لإضافة كائنات العينات. يمكنك ترك تكوين النسيج كما هو (مع حالات العينات الخاصة به) وإضافة مجرد رمز للتحكم في كائنات العينات واستخدامها.
عندما يحين الوقت لحذف الكائن ، فإننا ببساطة نسمي هذه الوظيفة:
glDeleteSamplers(1, &sampler_state);
عرض الملمس
سأترجم هذا كـ "مؤشر نسيج (قد يكون أكثر صحة من الارتباط ، أنا xs)" ، لأنني لا أعرف أفضل ترجمة.
ما هي المؤشرات في منظور OpenGL؟
كل شيء بسيط للغاية ، وهذا مؤشر على بيانات الملمس الثابت (أي القابل للتغيير) ، كما نرى في الصورة أدناه.

في الواقع ، هذا هو كائن يشارك بيانات texel الخاصة بكائن نسيج معين ، ولأغراض القياس ، يمكننا استخدام
std :: shared_ptr من C ++ . طالما يوجد مؤشر نسيج واحد على الأقل ، فلن تتم إزالة النسيج الأصلي بواسطة برنامج التشغيل.
يتم وصف
الويكي بمزيد من التفاصيل ، فضلاً عن أنها تستحق القراءة حول أنواع النسيج والهدف (ليس من الضروري مطابقتها)
لإنشاء مؤشر ، نحتاج إلى الحصول على واصف نسيج عن طريق استدعاء
glGenTexture (لا توجد حاجة
للتهيئة ) ثم
glTextureView .
glGenTextures(1, &texture_view); glTextureView(texture_view, GL_TEXTURE_2D, source_name, internal_format, min_level, level_count, 5, 1);
يمكن أن تشير مؤشرات الملمس إلى المستوى Nth من mipmap ، وهي مفيدة للغاية ومريحة. يمكن أن تكون المؤشرات إما صفائف نسيج أو أجزاء من صفائف أو طبقة معينة في هذه المجموعة ، أو يمكن أن تكون شريحة من نسيج ثلاثي الأبعاد كنسيج ثنائي الأبعاد.
عازلة واحدة لمؤشر وقمة
حسنًا ، كل شيء سيكون سريعًا وسهلاً. في السابق ، أوصت مواصفات OpenGL
لكائن Vertex Buffer بأن يقوم المطور بتقسيم بيانات الرأس والفهرس إلى مخازن مؤقتة مختلفة ، لكن هذا ليس ضروريًا الآن (تاريخ طويل لما لا).
كل ما نحتاج إليه هو حفظ المؤشرات أمام الرؤوس ومعرفة أين تبدأ الرؤوس (بشكل أكثر دقة ، الإزاحة) ، لهذا يوجد أمر
glVertexArrayVertexBufferإليك كيف سنفعل ذلك:
GLint alignment = GL_NONE; glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment); const GLsizei ind_len = GLsizei(ind_buffer.size() * sizeof(element_t)); const GLsizei vrt_len = GLsizei(vrt_buffer.size() * sizeof(vertex_t)); const GLuint ind_len_aligned = align(ind_len, alignment); const GLuint vrt_len_aligned = align(vrt_len, alignment); GLuint buffer = GL_NONE; glCreateBuffers(1, &buffer); glNamedBufferStorage(buffer, ind_len_aligned + vrt_len_aligned, nullptr, GL_DYNAMIC_STORAGE_BIT); glNamedBufferSubData(buffer, 0, ind_len, ind_buffer.data()); glNamedBufferSubData(buffer, ind_len_aligned, vrt_len, vrt_buffer.data()); GLuint vao = GL_NONE; glCreateVertexArrays(1, &vao); glVertexArrayVertexBuffer(vao, 0, buffer, ind_len_aligned, sizeof(vertex_t)); glVertexArrayElementBuffer(vao, buffer);
التغطية بالفسيفساء وحساب التظليل
لن أخبركم عن تظليل التغطية بالفسيفساء ، نظرًا لوجود الكثير من المواد في Google حول هذا (باللغة الروسية) ، إليك بعض الدروس:
1 ،
2 ،
3 . ننتقل إلى النظر في تظليل الحسابات (bliiin ، وأيضًا الكثير من المواد ، وسأخبرك بإيجاز).
ميزة بطاقات الفيديو في عدد كبير جدا من النوى ، بطاقات الفيديو مصممة لعدد كبير من المهام الصغيرة التي يمكن القيام بها على التوازي. يتيح تظليل الحساب ، كما يوحي الاسم ، حل المشكلات التي لا تتعلق بالرسومات (غير ضرورية).
صورة ، لا أعرف ما أسميها (مثل التدفقات مجمعة).

ماذا يمكن أن نستخدم ل؟
- معالجة الصور
- بلور
- الخوارزميات القائمة على البلاط (التظليل المؤجل)
- المحاكاة
- الجسيمات
- ماء
علاوة على ذلك ، لا أرى أي سبب للكتابة ، فهناك أيضًا الكثير من المعلومات في Google ، وفيما يلي مثال بسيط للاستخدام:
فيما يلي مثال لتظليل حساب فارغ:
#version 430 layout(local_size_x = 1, local_size_y = 1) in; layout(rgba32f, binding = 0) uniform image2D img_output; void main() {
فيما يلي بعض الروابط لإلقاء نظرة أعمق على
1 و
2 و
3 و
4 .
تقديم المسار
هذا امتداد جديد (ليس جديدًا) من
NVidia ، هدفه الرئيسي هو تقديم ناقل ثنائي الأبعاد. يمكننا استخدامه للنصوص أو واجهة المستخدم ، وبما أن الرسومات متجهة ، فهي لا تعتمد على الدقة ، وهي بلا شك ميزة كبيرة وستكون واجهة المستخدم الخاصة بنا رائعة.
المفهوم الأساسي هو الاستنسل ، ثم غطاء (غطاء في الأصل). اضبط استنسل المسار ، ثم تصور وحدات البكسل.
بالنسبة للإدارة ، يتم استخدام GLuint القياسي ، ووظائف الإنشاء والحذف تحتوي على اصطلاح تسمية قياسي.
glGenPathsNV
إليك القليل حول كيفية الحصول على المسار:
- SVG أو بوستسكريبت في string'e
glPathStringNV
- مجموعة من الأوامر مع الإحداثيات المقابلة
glPathCommandsNV
ولتحديث البيانات glPathSubCommands, glPathCoords, glPathSubCoords
- الخطوط
glPathGlyphsNV, glPathGlyphRangeNV
- مجموعات خطية من المسارات الحالية (الاستيفاء من مسار أو مسارين أو أكثر)
glCopyPathNV, glInterpolatePathsNV, glCombinePathsNV
- التحول الخطي للمسار الحالي
glTransformPathNV
قائمة الأوامر القياسية:
- الانتقال إلى (س ، ص)
- وثيق مسار
- سطر إلى (س ، ص)
- منحنى تربيعي (x1 ، y1 ، x2 ، y2)
- منحنى مكعب (X1 ، Y1 ، X2 ، Y2 ، X3 ، Y3)
- منحنى سلس من الدرجة الثانية (س ، ص)
- منحنى ناعم مكعب (X1 ، Y1 ، X2 ، Y2)
- قوس إهليلجي (rx ، ry ، دوران محور x ، علم قوس كبير ، إشارة مسح ، x ، y)
إليك شكل سلسلة المسار في PostScript:
"100 180 moveto 40 10 lineto 190 120 lineto 10 120 lineto 160 10 lineto closepath” // "300 300 moveto 100 400 100 200 300 100 curveto 500 200 500 400 300 300 curveto closepath”
وهنا في SVG:
"M100,180 L40,10 L190,120 L10,120 L160,10 z” // "M300 300 C 100 400,100 200,300 100,500 200,500 400,300 300Z”
لا يزال هناك كل أنواع الكعك مع أنواع الحشوات ، الحواف ، الانحناءات:

لن أصف كل شيء هنا ، نظرًا لوجود الكثير من المواد وسوف يستغرق الأمر مقالة كاملة (إذا كانت مثيرة للاهتمام ، سأكتبها بطريقة أو بأخرى).
وهنا قائمة من تقديم البدائية
- منحنيات مكعب
- المنحنيات التربيعية
- خطوط
- الحروف الرسومية الخط
- أقواس
- اندفاعة و Endcap ستايل
إليك بعض الأكواد ، ثم هناك الكثير من النص:
هذا كل شيء.
يبدو لي أن هذا المقال جاء أقل إثارة للاهتمام وغنية بالمعلومات ، كان من الصعب تمييز الشيء الرئيسي في المادة. إذا كان شخص ما مهتمًا بمعرفة المزيد من التفاصيل ، فيمكنني تجاهل بعض مواد NVidia وارتباطاتها بالمواصفات (إذا كنت أتذكر المكان الذي حفظته فيه). أنا سعيد أيضًا بأي مساعدة في تحرير المقالة.
كما وعدت ، سأكتب المقالة التالية حول تحسين وتقليل مكالمات السحب. أود أن أطلب منك أن تكتب في التعليقات حول ماذا تريد أن تقرأ وما يهمك:
- كتابة لعبة على cocos2d-x (التدريب فقط ، لا ماء)
- ترجمة سلسلة من المقالات حول فولكان
- بعض المواضيع على OpenGL (رباعي ، وظائف جديدة)
- خوارزميات رسومات الحاسوب (الإضاءة ، انسداد محيط الشاشة الفضائية ، انعكاس شاشة الفضاء)
- خياراتك
شكرا لكم جميعا على اهتمامكم.