سؤال

أقوم حاليًا بتطبيق رسم خرائط لضوضاء Perlin 3D باستخدام Tader Model 4 (DirectX 10 HLSL). إن توليد الضوضاء بحد ذاته ليس مشكلة كبيرة (هناك الكثير من البرامج التعليمية والرموز حولها) ولكن ما لم أجده هو مشتقات تحليلية لضوضاء Perlin ثلاثية الأبعاد.

المواقع الوحيدة التي تأخذ المشتقات في الاعتبار موقع Ińigo Quilez وعلاقة مناقشة gamedev.net. المشكلة هي أنه في الرابط الأول ، تعتمد الضوضاء على القيمة ، وليس على أساس التدرج (وهو أمر متطلب بالنسبة لي) ، في الرابط الثاني ، لا يوجد سوى مشتق ضجيج ثنائي التدرج.

لاحظ أنني لا أبحث عن مشتقات رقمية لأن تلك التي تتطلب 4 عينات من الضوضاء المجاورة لتوليدها وهذا هو الكثير من النفقات العامة.

هل قام أي شخص بحساب هذه المشتقات؟ هل هناك تطبيق مرجعي يستخدمها؟

هل كانت مفيدة؟

المحلول

لم أتمكن من العثور على حل على الويب اليوم ، لذلك حاولت استخلاصه.

أولاً ، يتم تعريف رموز ضوضاء Perlin ثلاثية الأبعاد.

الرموز

افترض أن ضوضاء Perlin ثلاثية الأبعاد يتم حسابها بواسطة الاستيفاء الثلاثية

n = Lerp(
        Lerp(
            Lerp(dot000, dot100, u),
            Lerp(dot010, dot110, u),
            v), 
        Lerp(
            Lerp(dot001, dot101, u), 
            Lerp(dot011, dot111, u),
            v),
        w)

أين u, v, w هي عوامل الاستيفاء من قبل كثير الحدود الكنسي لإحداثيات الكسر (أي ، تحسن ضوضاء Perlin):

x0 = frac(x)
y0 = frac(y)
z0 = frac(z)
x1 = x0 - 1
y1 = y0 - 1
z1 = z0 - 1

u = x0 * x0 * x0 * (x0 * (6 * x0 - 15) + 10)
v = y0 * y0 * y0 * (y0 * (6 * y0 - 15) + 10)
w = z0 * z0 * z0 * (z0 * (6 * z0 - 15) + 10)

و dot___S هي منتجات نقطة من ناقلات التدرج (gx___, gy___, gz___)S في نقاط شعرية وإحداثيات الكسر:

dot000 = gx000 * x0 + gy000 * y0 + gz000 * z0
dot100 = gx100 * x1 + gy100 * y0 + gz100 * z0
dot010 = gx010 * x0 + gy010 * y1 + gz010 * z0
dot110 = gx110 * x1 + gy110 * y1 + gz110 * z0
dot001 = gx001 * x0 + gy001 * y0 + gz001 * z1
dot101 = gx101 * x1 + gy101 * y0 + gz101 * z1
dot011 = gx011 * x0 + gy011 * y1 + gz011 * z1
dot111 = gx111 * x1 + gy111 * y1 + gz111 * z1

حساب المشتقات

أولاً ، حساب مشتقات u, v و w

u' = 30 * x0 * x0 * (x0 - 1) * (x0 - 1)
v' = 30 * y0 * y0 * (y0 - 1) * (y0 - 1)
w' = 30 * z0 * z0 * (z0 - 1) * (z0 - 1)

عن طريق التوسع n مع Lerp(a, b, t) = a + (b - a) * t,

n = dot000 
  + u(dot100 - dot000)
  + v(dot010 - dot000)
  + w(dot001 - dot000)
  + uv(dot110 - dot010 - dot100 + dot000)
  + uw(dot101 - dot001 - dot100 + dot000)
  + vw(dot011 - dot001 - dot010 + dot000)
  + uvw(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)

ثم خذ مشتقات جزئية n,

nx = gx000
   + u'  (dot100 - dot000)
   + u   (gx100 - gx000)
   + v   (gx010 - gx000)
   + w   (gx001 - gx000)
   + u'v (dot110 - dot010 - dot100 + dot000)
   + uv  (gx110 - gx010 - gx100 + gx000)
   + u'w (dot101 - dot001 - dot100 + dot000)
   + uw  (gx101 - gx001 - gx100 - gx000)
   + vw  (gx011 - gx001 - gx010 + gx000)
   + u'vw(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
   + uvw (gx111 - gx011 - gx101 + gx001 - gx110 + gx010 + gx100 - gx000)

,

ny = gy000
   + u   (gy100 - gy000)
   + v'  (dot010 - dot000)
   + v   (gy010 - gy000)
   + w   (gy001 - gy000)
   + uv' (dot110 - dot010 - dot100 + dot000)
   + uv  (gy110 - gy010 - gy100 + gy000)
   + uw  (gy101 - gy001 - gy100 + gy000)
   + v'w (dot011 - dot001 - dot010 + dot000)
   + vw  (gy011 - gy001 - gy010 + gy000)
   + uv'w(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
   + uvw (gy111 - gy011 - gy101 + gy001 - gy110 + gy010 + gy100 - gy000)

,

nz = gz000
   + u   (gz100 - gz000)
   + v   (gz010 - gz000)
   + w'  (dot001 - dot000)
   + w   (gz001 - gz000)
   + uv  (gz110 - gz010 - gz100 + gz000)
   + uw' (dot101 - dot001 - dot100 + dot000)
   + uw  (gz101 - gz001 - gz100 + gz000)
   + vw' (dot011 - dot001 - dot010 + dot000)
   + vw  (gz011 - gz001 - gz010 + gz000)
   + uvw'(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
   + uvw (gz111 - gz011 - gz101 + gz001 - gz110 + gz010 + gz100 - gz000)

ثم (nx, ny, nz) هو متجه التدرج (المشتقات الجزئية) لوظيفة الضوضاء.

تحسين

يمكن أخذ بعض التعبير الفرعي الشائع في الحسبان ، إذا لم يتمكن المترجمات من التعامل معها. فمثلا:

uv = u * v
vw = v * w
uw = u * w
uvw = uv * w

المعاملات في الموسعة n يتم إعادة استخدامها عدة مرات. يمكن حسابها بواسطة:

k0 = dot100 - dot000
k1 = dot010 - dot000
k2 = dot001 - dot000
k3 = dot110 - dot010 - k0
k4 = dot101 - dot001 - k0
k5 = dot011 - dot001 - k1
k6 = (dot111 - dot011) - (dot101 - dot001) - k3

كما أن المشتقات لها معاملات مماثلة ،

gxk0 = gx100 - gx000
gxk1 = gx010 - gx000
...

حساب n يمكن استخدام النموذج الموسع مع k0, ... k6 كذلك.

الكلمات الأخيرة

تم التحقق من هذا الحل مقابل طريقة الفرق المركزي.

على الرغم من أن هذا الحل يبدو خرقاء ، إلا أن تجربتي (وحدة المعالجة المركزية فقط ، SSE) أظهرت أن هذه المشتقات من خلال هذا الحل لا تتحمل سوى 50 ٪ وقت إضافي لحساب عينة ضوضاء بيرلين ثلاثية الأبعاد.

سيحتاج الفرق المحدود على الأقل إلى 300 ٪ من الوقت الإضافي (القيام 3 عينات إضافية) أو 600 ٪ (القيام 6 عينات للفرق المركزي).

لذلك ، هذا الحل أفضل في الأداء ، ويجب أن يكون أيضًا أكثر استقرارًا عدديًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top