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

عند وضع كائنات خارج الحافة البعيدة للمرايا واستخدام انعكاسات متعددة للأشعة (حوالي 20 انعكاسًا) نحصل على مشكال فعال.

لإنشاء توجيه ، يتم استخدام تظليل حسابي. يتم إخراج الصورة في نسيج ، والتي يتم عرضها لاحقًا على الشاشة. تستخدم الكرات الرسومية كأشكال أبسط. على بطاقة الفيديو الخاصة بي في وضع التقديم الفعلي ، تمكنت من تحقيق حوالي 20-25 إطارًا في الثانية ، وهذا فقط مع ثلاثة كائنات ومصدر ضوء واحد ، وهو أمر محزن. أردت حركة فوضوية للعديد من الأشكال المختلفة ، وكذلك مصادر إضاءة في الوقت الفعلي ، لكن هذا سيؤدي إلى تباطؤ أكبر.
بعد عدة طرق للتحسين ، قمت بتأجيل هذا النموذج باعتباره غير واعد.
الحوسبة شادر كود GLSL#version 430 core
layout( local_size_x = 32, local_size_y = 32 ) in;
layout(binding = 0, rgba8) uniform image2D IMG;
layout(binding = 1, std430) buffer InSphere {vec4 Shape_obj[];};
layout(binding = 2, std430) buffer InSphere_color {vec4 Sphere_color[];};
uniform vec2 u_InvScreenSize;
uniform float u_ScreenRatio;
uniform vec3 u_LightPosition;
uniform vec3 u_CameraPosition;
//
const vec3 ray00 = vec3(-1*u_ScreenRatio,-1, -1.2);
const vec3 ray01 = vec3(-1*u_ScreenRatio,+1, -1.2);
const vec3 ray10 = vec3(+1*u_ScreenRatio,-1, -1.2);
const vec3 ray11 = vec3(+1*u_ScreenRatio,+1, -1.2);
const ivec2 size = imageSize(IMG);
const mat3 mat_rotate = mat3(-0.5, -0.86602540378443864676372317075294, 0, 0.86602540378443864676372317075294, -0.5, 0, 0, 0, 1);
struct plane {
vec3 v_plane;
vec3 n_plane;
vec3 p_plane;
};
//
plane m[3];
int last_plane;
//----------------------------------------------------------
float ray_intersect_sphere(vec3 orig, vec3 dir, vec4 Shape_obj) {
vec3 l = Shape_obj.xyz - orig;
float tca = dot(l,dir);
float d2 = dot(l,l) - tca * tca;
if (d2 > Shape_obj.w * Shape_obj.w) {return 0;}
float thc = sqrt(Shape_obj.w * Shape_obj.w - d2);
float t0 = tca - thc;
float t1 = tca + thc;
if (t0 < 0) {t0 = t1;}
if (t0 < 0) {return 0;}
return t0;
}
//---------------------------------------------------------
'float ray_intersect_plane(in vec3 orig, in vec3 dir, inout plane p) {
vec3 tested_direction = p.v_plane - orig;
float k = dot(tested_direction, p.v_plane) / dot(dir, p.v_plane);
if (k>=0) {
vec3 p0 = orig + dir * k;
// z
if ((p0.z>-80)&&(p0.z<3)) {
p.p_plane = p0;
return length(p0-orig);
}
}
return 1000000;
}'+
//---------------------------------------------------------
bool all_obj(inout vec3 loc_eye, inout vec3 dir, inout vec3 c) {
float min_len = 1000000;
uint near_id = 0;
float len;
float min_len2 = 1000000;
int near_id2 = -1;
for (int i=0; i<3; i++) {
if (i!=last_plane) {
len = ray_intersect_plane(loc_eye, dir, m[i]);
if (len<min_len2) {
min_len2 = len;
near_id2 = i;
}
}
}
//
if (near_id2>=0) {
loc_eye = m[near_id2].p_plane;
dir = reflect(dir, m[near_id2].n_plane);
last_plane =near_id2;
return true;
}
for (uint i=0; i<Shape_obj.length(); i++) {
len = ray_intersect_sphere(loc_eye, dir, Shape_obj[i]);
if ((len>0)&&(len<min_len)) {
min_len = len;
near_id = i;
}
}
//
if (min_len>=1000000) {return false;}
vec3 hit = loc_eye + dir * min_len;
vec3 Normal = normalize(hit - Shape_obj[near_id].xyz);
vec3 to_light = u_LightPosition - hit;
float to_light_len = length(to_light);
vec3 light_dir = normalize(to_light);
float diffuse_light = max(dot(light_dir, Normal), 0.0);
c = min(c + Sphere_color[near_id].xyz * (diffuse_light*0.8+0.2),1);
return false;
}
//---------------------------------------------------------
void main(void) {
if (gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y) return;
const vec2 pos = gl_GlobalInvocationID.xy * u_InvScreenSize.xy;
vec3 dir = normalize(mix(mix(ray00, ray01, pos.y), mix(ray10, ray11, pos.y), pos.x));
vec3 c = vec3(0, 0, 0);
//
vec3 eye = vec3(u_CameraPosition);
//
m[0].v_plane = vec3(0,-5,0);
m[0].n_plane = vec3(0,1,0);
m[1].v_plane = mat_rotate * m[0].v_plane;
m[1].n_plane = mat_rotate * m[0].n_plane;
m[2].v_plane = mat_rotate * m[1].v_plane;
m[2].n_plane = mat_rotate * m[1].n_plane;
//
for (int i=0; i<20; i++) {
if (!all_obj(eye, dir, c)) {break;}
}
//
imageStore(IMG, ivec2(gl_GlobalInvocationID.xy), vec4(c,1));
}
في مقاربة أخرى ، استخدمت خاصية الدورية لنمط المشكال. يرتبط كل قمة دائمًا برقمين آخرين ، يشار هنا إلى ثلاثة رؤوس بثلاثة ألوان.
نملأ الكائن العازل بإحداثيات رؤوس المثلثات متساوية الأضلاع التي تشكل المعين.

في الشكل ، يتم استبدال الألوان بالأرقام. يرجى ملاحظة: يتم تكرار الصفوف الفردية والصفرية بنوبة واحدة. لقد قطعنا العناصر غير الضرورية ، ونعرض فقط مؤشرات قمة الرأس الضرورية ونتيجة لذلك نحصل على مسدس يمكن تحجيمه بسهولة.

بعد ذلك ، استبدل الألوان بإحداثيات النسيج من قالب الملمس الصغير.

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



فيديو(لا أعرف كيفية نحت مقطع فيديو ، أعتذر عن الجودة)
رمز التظليل بسيط بشكل لا يصدق.
GLSL Shader Code // #version 330 core layout (location = 0) in vec4 a_Position; uniform mat4 u_MVP; out vec4 v_Color; out vec2 v_TexCoords; void main() { v_TexCoords = a_Position.zw; gl_Position = u_MVP * vec4(a_Position.xy, 0, 1); } // #version 330 core precision mediump float; varying vec2 v_TexCoords; uniform sampler2D u_Texture; void main(){ gl_FragColor = texture(u_Texture, v_TexCoords); }
كان الأطفال راضين ، وعلقت في التأمل لعدة أمسيات.
→
تجريبي (EXE لنظام التشغيل Windows)