جلبت رومان كورتيس الورود الحمراء المكتوبة في نصوص جافا سكريبت. Rose Made with Code هي أفضل هدية عيد الحب المقدمة لصديقتك من قبل المبرمجين الرائعين! (نصيحة: سيكون تأثير المشاهدة والسرعة مختلفة تمامًا تحت متصفحات مختلفة)
يتم إنشاء الصورة بواسطة الكود ، ويمكن للمستخدم تحديث الصفحة وتكرار عملية العرض لمشاهدة الوردة.
رمز تنفيذ 3D Rose كما يلي:
نسخة الكود كما يلي: مع (m = math) c = cos ، s = sin ، p = pow ، r = عشوائي ؛ p (a ، b ، c) {if (c> 60) return [s (a*7)*(13+5/(. 2+p (b*4،4)))-s (b)*50 ، b*f+50،625+c (a*7)*(13+ 5/(. 2+p (b*4،4))))+b*400 ، a*1-b/2 ، a] ؛ a = a*2-1 ؛ b = b*2-1 ؛ if (a*a+b*b <1) {if (c> 37) {n = (j = c & 1) ؟ 6: 4 ؛ o = .5/(a+.01)+c (b*125)*3-a*300 ؛ w = b*h ؛ return [o*c (n)+w*s (n)+j*610-390 ، o*s (n) -w*c (N)+550-J*350،1180+C (B+A)*99-J*300 ، .4-A*.1+P (1-B*B ، -H*6)*. O*(A+1)+(B> 0؟ W: -W))/25) ، 30)* a*45-20 ؛ w = b*b*h ؛ z = o*s (c)+w*c (c) +620 ؛ return [o*c (c) -w*s (c) ، 28+c (b*.5)*99-b*b*60-z/ 2-H ، Z ، (B*B*.3+P ((1- (A*A)) ، 7)* 99-C (A)*120-C (B)*(-HC*4.9)+C (P (1-B ، 7))*50+C*2 ؛ z = O*S (C)+W*C (C) +700 ؛ إرجاع [O*C (C) -W*S (C) ، B*99-C (P (B ، 7))*50-C/3-Z/1.35+450 ، Z ، (1-B/1.2)*. 9+A*.1 ، p ((1-b) ، 20) /4+.05]}} setInterval ('for (i = 0 ؛ i <1e4 ؛ i ++) if (s = p (r () ، r () ، i ٪ 46/.74)) {z = s [2] ؛ x = ~~ (s [0]*f/zh) ؛ (! m [q = y*f+x] | m [q]> z) m [q] = z ، a.fillstyle = "rgb ("+~ (s [3]*h)+"،"+~ (s [4]*h)+"،"+~ (s [3]*s [3-80)+") ،
بالطبع ، يمكن للأشخاص المهتمين فهم عملية التنفيذ التالية والنظريات ذات الصلة:
يستخدم تأثير العرض التقديمي لهذا الرمز ثلاثي الأبعاد طريقة Monte Carlo ، وأشاد المبدع بشكل كبير بطريقة Monte Carlo. وقال إن طريقة مونت كارلو هي "أداة قوية بشكل لا يصدق" من حيث التحسين الوظيفي وأخذ العينات. لطريقة مونت كارلو ، يرجى الرجوع إلى: Monte Carlo Method.
عمليات محددة:
رسم أخذ العينات تأثير التأثير
لقد استخدمت مخططات شكل مختلفة متعددة لتشكيل هذه الرمز. تم استخدام ما مجموعه 31 شكلًا: 24 بتلات ، 4 سيبيال ، 2 أوراق وجذعية زهرة واحدة ، وتم تصوير كل مخطط شكل في الكود.
أولاً ، حدد نطاق أخذ العينات:
سطح الوظيفة (A ، B) {// أنا أستخدم A و B كمعلمات تراوحت من 0 إلى 1.RETURN {X: A*50 ، y: B*50} ؛ // سيكون هذا السطح مربعًا من 50 × 50 وحدة من الحجم}ثم اكتب رمز تحديد الشكل:
var canvas = document.body.appendChild (document.createElement ("canvas")) ، context = canvas.getContext ("2d") ، a ، b ، posit ؛ // الآن سأقوم بتجربة السطح عند الفواصل الزمنية .1 = 1 ؛ b += 1 ؛ ب) ؛ السياق.الآن ، جرب فاصل أخذ عينات أكثر كثافة:
كما ترون الآن ، نظرًا لأن فترات أخذ العينات تزداد كثافة وأقرب ، فإن النقاط تقترب من أعلى الكثافة ، والمسافة بين النقاط المجاورة أقل من بكسل واحد ، ولا يمكن رؤية الفاصل الزمني بالعين المجردة (انظر 0.01). من أجل عدم التسبب في الكثير من الفرق البصري ، يتم تقليل فاصل أخذ العينات. في هذا الوقت ، تم ملء منطقة الرسم (نتائج المقارنة هي 0.01 و 0.001).
بعد ذلك ، أستخدم هذه الصيغة لرسم دائرة: (x-x0)^2 + (y-y0)^2 <radius^2 ، حيث (x0 ، y0) هو مركز الدائرة:
سطح الوظيفة (a ، b) {var x = a * 100 ، y = b * 100 ، radius = 50 ، x0 = 50 ، y0 = 50 ؛ if ((x - x0) * (x - x0) + (y - y0) * باطل؛}}لمنع الفائض ، يجب إضافة حالة أخذ العينات:
if (الموضع = السطح (a ، b)) {context.fillRect (position.x ، position.y ، 1 ، 1) ؛}هناك طرق مختلفة لتحديد دائرة ، بعضها لا يتطلب رفض أخذ العينات. لست مضطرًا لاستخدام أي واحد لتحديد دائرة ، لذلك أستخدم طريقة أخرى لتحديد دائرة:
سطح الوظيفة (A ، B) {// Circle باستخدام الزنزانة القطبية الزاوية = a * math.pi * 2 ، نصف القطر = 50 ، x0 = 50 ، y0 = 50 ؛ return {x: math.cos (angle) * radius * b + x0 ، y: math.sin (angle) * radius * b + y0} ؛} ؛} ؛(تتطلب هذه الطريقة أخذ عينات كثيفة للملء مقارنة بالطريقة السابقة.)
حسنًا ، دع الدائرة الآن تشوه لجعلها تبدو أشبه ببتل:
سطح الوظيفة (a ، b) {var x = a * 100 ، y = b * 100 ، radius = 50 ، x0 = 50 ، y0 = 50 ؛ if ((x - x0) * (x - x0) + (y - y0) * (y - y0) <radius * adadius) {return {x: y: y: y *هذا يبدو وكأنه بتلة الورد. هنا يمكنك أيضًا محاولة تعديل بعض قيم الوظائف ، وستظهر العديد من الأشكال المثيرة للاهتمام.
بعد ذلك ، أضف اللون إليه:
سطح الوظيفة (a ، b) {var x = a * 100 ، y = b * 100 ، نصف قطرها = 50 ، x0 = 50 ، y0 = 50 ؛ if ((x - x0) * (x - x0) + (y - y0) * (y - y0) <radius * radius) {return {x: y: y * (1 + b) / 2 ، 100 + math. أضف gradientg: 50 ، b: 50} ؛} else {return null ؛}} لـ (a = 0 ؛ a <1 ؛ a + = .01) {for (b = 0 ؛ b <1 ؛ b + = .001) {if (point = a ، b)) {context.fillstyle = "rgb ( ")" ؛ context.fillRect (point.x ، point.y ، 1 ، 1) ؛}}}يظهر بتلة ملونة.
إسقاط السطح ثلاثي الأبعاد والمنظور
تحديد سطح ثلاثي الأبعاد أمر بسيط ، على سبيل المثال ، لتحديد كائن أنبوبي:
سطح الوظيفة (a ، b) {var angle = a * math.pi * 2 ، نصف القطر = 100 ، طول = 400 ؛ إرجاع {x: math.cos (angle) * radius ، y: math.sin (angle) * radius ، z: b * length / 2 ، // by purstrict under / 2 I hend the time at (0 ، 0) r: 0 ، g: g math. 0} ؛}ثم أضف منظور الإسقاط. أولاً نحتاج إلى تحديد الكاميرا:
كما هو موضح أعلاه ، ضع الكاميرا في وضع (0 ، 0 ، z) والقطن في المستوى x/y. نقاط أخذ العينات المتوقعة على القماش هي:
var px ، py ، // المقعور على القماش x و y coordinatespersperveser = 350 ، halfheight = canvas.height / 2 ، halfwidth = canvas.width / 2 ، cameraz = -700 ؛ for (a = 0 ؛ a <1 ؛ a += .001) {b = 0 ؛ b <1 ؛ (point.x * منظور) / (point.z - cameraz) + halfwidth ؛ py = (point.y * منظور) / (point.z - cameraz) + halfheight ؛ context.fillstyle = "rgb (" + point.r + "،" + point.g + "،" + point.b + ") ؛التأثير هو:
z-buffer
Z-Buffer هي تقنية شائعة جدًا في رسومات الكمبيوتر. عند التظليل ، يتم تنفيذ عمل "التخلص من السطح المخفي" بحيث لا يتم عرض الجزء وراء الكائنات المخفية.
الصورة أعلاه عبارة عن وردة تتم معالجتها مع تقنية Z-Buffer. (يمكنك أن ترى أن لديها بالفعل ثلاثية الأبعاد)
الرمز كما يلي:
var zbuffer = [] ، zBufferIndex ؛ for (a = 0 ؛ a <1 ؛ a += .001) {for (b = 0 ؛ b <1 ؛ b += .01) {if (point = surface (a ، b)) / (point.z - cameraz) + halfheight) ؛ zBufferIndex = py * canvas.width + px ؛ if ((typeof zBuffer [zBufferIndex] === "undefined") || + point.r + "،" + point.g + "،" + point.b + ") ؛ context.fillRect (px ، py ، 1 ، 1) ؛}}}}}تناوب
يمكنك استخدام أي طريقة دوران متجه. في إنشاء رمز الوردة ، أستخدم دوران Euler. الآن قم بتدوير الكائن الأنبوبي المكتوب مسبقًا للتدوير حول محور Y:
سطح الوظيفة (أ ، ب) {var angle = a * math.pi * 2 ، نصف قطرها = 100 ، طول = 400 ، x = math.cos (زاوية) * نصف قطرها ، y = math.sin (angle) * radius ، z = b * length / 2 ، yaxisrotationangle = -.4 ، // in radians! dotatedx = x * math.cos Math.sin (yaxisrotationangle) ، rotatedz = x * -math.sin (yaxisrotationangle) + z * math.cos (yaxisrotationangle) ؛ return {x: rotatedx ، y: y ، z: rotatedz ، r: 0 ، g: math.floor (b * 255) ، b: 0}تأثير:
طريقة مونت كارلو
فيما يتعلق بوقت أخذ العينات ، فإن كبير جدًا وصغيرة جدًا سيؤدي إلى خبرة مرئية سيئة للغاية ، لذلك يجب تعيين فاصل أخذ العينات المعقول ، ويتم استخدام طريقة مونت كارلو هنا.
var i ؛ window.setInterval (function () {for (i = 0 ؛ i <10000 ؛ i ++) {if (point = surface (math.random () ، math.random ())) {px = math.floor ((point.x * perspective) / (point.z - cameraz)+halfwidth) ؛ + halfheight) ؛ zBufferIndex = py * canvas.width + px ؛ if ((typeof zbuffer [zBufferIndex] === "undefined") || (point.z <zBuffer [zBufferIndex])) point.g + "،" + point.b + ")" ؛ context.fillRect (px ، py ، 1 ، 1) ؛}}}} ، 0) ؛قم بتعيين A و B كمعلمات عشوائية وملء السطح الكامل مع أخذ عينات كافية. أرسم 10000 نقطة في كل مرة وانتظر حتى تكمل الشاشة التحديث.
تجدر الإشارة أيضًا إلى أنه إذا كان رقم عشوائي غير صحيح ، فسيكون تأثير ملء السطح غير صحيح. في بعض المتصفحات ، يكون تنفيذ Math.Random خطيًا ، مما قد يؤدي إلى أخطاء في تأثيرات ملء السطح. في هذا الوقت ، يجب عليك استخدام شيء مثل Twister Mersenne (خوارزمية رقم عشوائي) لأداء أخذ عينات PRNG عالية الجودة لتجنب الأخطاء.
ينهي
من أجل إكمال كل جزء من الورد وتقديمه في نفس الوقت ، يجب إضافة ميزة لتعيين معلمة لكل جزء لإرجاع القيمة للمزامنة. واستخدم وظيفة الجزء لتمثيل أجزاء مختلفة من الوردة. على سبيل المثال ، في الجزء بتلة ، أستخدم الدوران والتشوه لإنشائها.
على الرغم من أن طريقة أخذ العينات السطحية هي واحدة من أشهر الأساليب وأقدمها لإنشاء رسومات ثلاثية الأبعاد ، إلا أن هذه الطريقة لإضافة Monte Carlo و Z-Buffer إلى أخذ العينات السطحية ليست شائعة. قد لا يكون هذا مبدعًا جدًا لإنتاج سيناريو الحياة الواقعية ، لكن تنفيذ الكود البسيط وحجمه لا يزال مرضيًا.
نأمل أن تلهم هذه المقالة عشاق رسومات الكمبيوتر لتجربة أساليب العرض التقديمي المختلفة والاستمتاع بها. (رومان كورتيس)
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.