Roman Cortes นำกุหลาบแดงเขียนไว้ในสคริปต์ JavaScript Rose Made With Code เป็นของขวัญวันวาเลนไทน์ที่ดีที่สุดที่มอบให้กับแฟนสาวของคุณโดยโปรแกรมเมอร์ที่ยอดเยี่ยม! (เคล็ดลับ: เอฟเฟกต์การดูและความเร็วจะแตกต่างกันมากภายใต้เบราว์เซอร์ที่แตกต่างกัน)
ภาพถูกสร้างขึ้นด้วยรหัสและผู้ใช้สามารถรีเฟรชหน้าและทำซ้ำกระบวนการนำเสนอของการดูดอกกุหลาบ
รหัสการใช้งานของ 3D Rose มีดังนี้:
การคัดลอกรหัสมีดังนี้: ด้วย (m = math) c = cos, s = sin, p = pow, r = random; c.width = c.height = f = 500; h = -250; ฟังก์ชั่น; p (a, b, c) {ถ้า (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; ถ้า (a*a+b*b <1) {ถ้า (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 (n)+550-j*350,1180+c (b+a)*99-j*300, .4-a*.1+p (1-b*b, -h*6)*. 15-a*b*.4+c (a+b)/5+p (c ( o*(a+1)+(b> 0? w: -w))/25), 30)*. 1*(1-b*b), o/1e3+.7-o*w*3e-6]} ถ้า (c> 32) {c = c*1.16-.15; o = 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*b*60-z/ 2-H, z, (B*B*.3+P ((1- (a*a)), 7)*. 15+.3)*b, b*.7]} o = a*(2-b)*(80-c*2); w = 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; return [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 ('สำหรับ (i = 0; i <1e4; i ++) ถ้า (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)
แน่นอนผู้ที่สนใจสามารถเข้าใจกระบวนการดำเนินการต่อไปนี้และทฤษฎีที่เกี่ยวข้อง:
ผลการนำเสนอของรหัสสามมิตินี้ Rose ใช้วิธี Monte Carlo และผู้สร้างได้ชื่นชมวิธี Monte Carlo อย่างมาก เขากล่าวว่าวิธี Monte Carlo เป็น "เครื่องมือที่ทรงพลังอย่างไม่น่าเชื่อ" ในแง่ของการเพิ่มประสิทธิภาพการทำงานและการสุ่มตัวอย่าง สำหรับวิธี Monte Carlo โปรดดูที่: วิธี Monte Carlo
การดำเนินการเฉพาะ:
รูปลักษณ์การวาดผลการแสดงผล
ฉันใช้ไดอะแกรมรูปร่างที่แตกต่างกันหลายแบบเพื่อสร้างรหัสนี้เพิ่มขึ้น มีการใช้รูปร่างทั้งหมด 31 รูป: 24 กลีบ, 4 กลีบ, 2 ใบและก้านดอก 1 ดอกและแผนภาพรูปร่างแต่ละรูปถูกแสดงในรหัส
ก่อนอื่นกำหนดช่วงการสุ่มตัวอย่าง:
ฟังก์ชั่นพื้นผิว (a, b) {// ฉันใช้ a และ b เป็นพารามิเตอร์อยู่ในช่วงตั้งแต่ 0 ถึง 1. กลับมา {x: a*50, y: b*50}; // พื้นผิวนี้จะเป็นสี่เหลี่ยมขนาด 50x50 หน่วย}จากนั้นเขียนรหัสการกำหนดรูปทรง:
var canvas = document.body.appendchild (document.createelement ("canvas")), context = canvas.getContext ("2d"), a, b, ตำแหน่ง; // ตอนนี้ฉันกำลังจะสุ่มตัวอย่างพื้นผิวที่. 1 ช่วงเวลาสำหรับพารามิเตอร์ A และ B: สำหรับ (A = 0; a <1; a += .1) b); context.fillrect (position.x, position.y, 1, 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; ถ้า ((x - x0) * (x - x0) + (y - y0) * (y - y0) <radius * radius) {//เพื่อป้องกันการล้นต้องมีการเพิ่มเงื่อนไขการสุ่มตัวอย่าง:
if (positions = surface (a, b)) {context.fillrect (position.x, position.y, 1, 1);}มีวิธีต่าง ๆ ในการกำหนดวงกลมซึ่งบางอย่างไม่จำเป็นต้องปฏิเสธการสุ่มตัวอย่าง ฉันไม่ต้องใช้อันไหนในการกำหนดวงกลมดังนั้นฉันจึงใช้วิธีอื่นเพื่อกำหนดวงกลม:
พื้นผิวฟังก์ชั่น (a, b) {// วงกลมโดยใช้ polar coordinatesvar angle = a * math.pi * 2, radius = 50, x0 = 50, y0 = 50; return {x: math.cos (มุม) * radius * b + x0, y: math.sin (มุม) * radius * b + y0};(วิธีนี้ต้องใช้การสุ่มตัวอย่างหนาแน่นสำหรับการเติมเมื่อเทียบกับวิธีการก่อนหน้านี้)
ตกลงตอนนี้ให้วงกลมเปลี่ยนรูปให้ดูเหมือนกลีบดอกมากขึ้น:
ฟังก์ชั่นพื้นผิว (a, b) {var x = a * 100, y = b * 100, radius = 50, x0 = 50, y0 = 50; ถ้า ((x - x0) * (x - x0) + (y - y0) * (y - y0) <radius * radius) {return {x: x, y: y * (1 + b)ดูเหมือนกลีบดอกกุหลาบ ที่นี่คุณสามารถลองแก้ไขค่าฟังก์ชั่นบางอย่างและรูปร่างที่น่าสนใจมากมายจะปรากฏขึ้น
ถัดไปเพิ่มสีลงไป:
ฟังก์ชั่นพื้นผิว (a, b) {var x = a * 100, y = b * 100, radius = 50, x0 = 50, y0 = 50; ถ้า ((x - x0) * (x - x0) + (y - y0) * (y - y0) <radius * radius) {return {x: x, y: y * (1 + b) / 2 เพิ่มการไล่ระดับสี: 50, b: 50};} else {return null;}} สำหรับ (a = 0; a <1; a + = .01) {สำหรับ (b = 0; b <1; b + = .001) {ถ้า (จุด = พื้นผิว (a, b)) ")"; context.fillrect (point.x, point.y, 1, 1);}}}กลีบดอกสีปรากฏขึ้น
การฉายภาพพื้นผิวและมุมมอง 3 มิติ
การกำหนดพื้นผิวสามมิตินั้นง่ายเช่นเพื่อกำหนดวัตถุท่อ:
ฟังก์ชั่นพื้นผิว (a, b) {var angle = a * math.pi * 2, radius = 100, ความยาว = 400; return {x: math.cos (มุม) * รัศมี, y: math.sin (มุม) * รัศมี, z: ความยาว - ความยาว / 2, // โดยการลบความยาว / 2 0};}จากนั้นเพิ่มมุมมองการฉาย ก่อนอื่นเราต้องกำหนดกล้อง:
ดังที่แสดงไว้ด้านบนวางกล้องในตำแหน่ง (0, 0, z) และผืนผ้าใบในระนาบ x/y จุดสุ่มตัวอย่างที่คาดการณ์ไว้บนผืนผ้าใบคือ:
var px, py, // ฉายบนผืนผ้าใบ X และ y CoordinatesPerspective = 350, halfheight = canvas.height / 2, halfwidth = canvas.width / 2, cameraz = -700; สำหรับ (a = 0; a <1; a += .001) {px = (point.x * มุมมอง) / (point.z - cameraz) + halfwidth; py = (point.y * มุมมอง) / (point.z - cameraz) + halfheight; context.fillstyle = "rgb (" + point.r + "," + point.g + " 1);}}}ผลคือ:
Z-buffer
Z-Buffer เป็นเทคนิคที่พบบ่อยมากในกราฟิกคอมพิวเตอร์ เมื่อวัตถุแรเงางาน "การกำจัดพื้นผิวที่ซ่อนอยู่" จะดำเนินการเพื่อให้ส่วนที่อยู่เบื้องหลังวัตถุที่ซ่อนอยู่จะไม่ปรากฏขึ้น
ภาพด้านบนเป็นกุหลาบที่ประมวลผลด้วยเทคโนโลยี Z-buffer (คุณจะเห็นว่ามันมีสามมิติอยู่แล้ว)
รหัสมีดังนี้:
var zbuffer = [], zbufferindex; สำหรับ (a = 0; a <1; a += .001) {สำหรับ (b = 0; b <1; b += .01) {ถ้า (จุด = พื้นผิว (a, b)) {px = math.floor (point.x / (point.z - cameraz) + halfheight); zbufferindex = py * canvas.width + px; ถ้า ((typeof zbuffer [zbufferindex] === "undefined") || (point.z <zbuffer [zbufferindex]) + point.r + "," + point.g + "," + point.b + ")";หมุน
คุณสามารถใช้วิธีการหมุนเวกเตอร์ใด ๆ ในการสร้างรหัสเพิ่มขึ้นฉันใช้การหมุนออยเลอร์ ตอนนี้หมุนวัตถุท่อที่เขียนไว้ก่อนหน้านี้เพื่อหมุนเกี่ยวกับแกน y:
ฟังก์ชั่นพื้นผิว (a, b) {var angle = a * math.pi * 2, radius = 100, ความยาว = 400, x = math.cos (มุม) * radius, y = math.sin (มุม) * รัศมี, z = b * ความยาว - ความยาว / 2, yaxisrotationangle = -.4, // 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};ผล:
วิธี Monte Carlo
เกี่ยวกับเวลาการสุ่มตัวอย่างขนาดใหญ่เกินไปและเล็กเกินไปจะทำให้เกิดประสบการณ์การมองเห็นที่แย่มากดังนั้นจึงต้องมีการตั้งค่าช่วงเวลาการสุ่มตัวอย่างที่สมเหตุสมผลและใช้วิธี Monte Carlo ที่นี่
var i; window.setInterval (function () {สำหรับ (i = 0; i <10,000; i ++) {ถ้า (จุด = พื้นผิว (math.random (), math.random ())) {px = math.floor (point.x * มุมมอง) / (point.z - cameraz) + halfheight); zbufferindex = py * canvas.width + px; if ((typeof zbuffer [zbufferindex] ==== "undefined") || (point.z <zbuffer [zbufferindex])) {zbuffer [zbufferindex] point.g + "," + point.b + ")"; context.fillrect (px, py, 1, 1);}}}}, 0);ตั้งค่า A และ B เป็นพารามิเตอร์แบบสุ่มและการเติมพื้นผิวที่สมบูรณ์ด้วยการสุ่มตัวอย่างเพียงพอ ฉันวาด 10,000 คะแนนในแต่ละครั้งและรอให้หน้าจอเสร็จสิ้นการอัปเดต
ควรสังเกตว่าหากหมายเลขสุ่มไม่ถูกต้องเอฟเฟกต์การเติมพื้นผิวจะไม่ถูกต้อง ในบางเบราว์เซอร์การดำเนินการของคณิตศาสตร์การสุ่มตัวอย่างเป็นเส้นตรงซึ่งอาจนำไปสู่ข้อผิดพลาดในเอฟเฟกต์การเติมพื้นผิว ในเวลานี้คุณต้องใช้บางอย่างเช่น Mersenne Twister (อัลกอริทึมหมายเลขสุ่ม) เพื่อทำการสุ่มตัวอย่าง PRNG คุณภาพสูงเพื่อหลีกเลี่ยงข้อผิดพลาด
เสร็จ
เพื่อให้แต่ละส่วนของดอกกุหลาบเสร็จสมบูรณ์และแสดงผลในเวลาเดียวกันคุณลักษณะจะต้องเพิ่มคุณสมบัติเพื่อตั้งค่าพารามิเตอร์สำหรับแต่ละส่วนเพื่อส่งคืนค่าสำหรับการซิงโครไนซ์ และใช้ฟังก์ชั่นเซ็กเมนต์เพื่อแสดงส่วนต่าง ๆ ของดอกกุหลาบ ตัวอย่างเช่นในส่วนของกลีบดอกฉันใช้การหมุนและการเสียรูปเพื่อสร้าง
แม้ว่าวิธีการสุ่มตัวอย่างพื้นผิวเป็นหนึ่งในวิธีที่มีชื่อเสียงและเก่าแก่ที่สุดสำหรับการสร้างกราฟิกสามมิติ แต่วิธีการเพิ่ม Monte Carlo และ Z-buffer ลงในการสุ่มตัวอย่างพื้นผิวนั้นไม่ได้เป็นเรื่องปกติ สิ่งนี้อาจไม่ได้สร้างสรรค์มากนักสำหรับการผลิตสถานการณ์จริง แต่การใช้รหัสง่าย ๆ และขนาดเล็กยังคงเป็นที่น่าพอใจ
หวังว่าบทความนี้จะสร้างแรงบันดาลใจให้ผู้ที่ชื่นชอบกราฟิกคอมพิวเตอร์ลองใช้วิธีการนำเสนอที่แตกต่างกันและสนุกไปกับมัน (Roman Cortes)
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น