เมื่อไม่กี่วันก่อนผมไปทำธุรกิจและเห็นแผงตรวจสอบเหนือศีรษะบนเครื่องบิน นอกจากจะเล่นละครโทรทัศน์และโฆษณาแล้ว ยังจะเปลี่ยนมาใช้ระบบตรวจสอบการนำทางเครื่องบินเป็นระยะๆ ระบบรู้สึกหยาบเล็กน้อย ดังนั้นฉันจึงสร้างระบบการตรวจสอบเวอร์ชันอัปเกรดโดยใช้ HT สำหรับเว็บ การสาธิตค่อนข้างดี ดังนั้นฉันจึงอยากแบ่งปันกับคุณเพื่อให้เราได้เรียนรู้จากกันและกัน
การสาธิต
กระบวนการดำเนินการเอฟเฟกต์เดินผ่านก้อนเมฆ
เพื่อให้ได้เอฟเฟ็กต์ของเครื่องบินที่บินผ่านก้อนเมฆ ปัญหาแรกที่ฉันพบคือการบินของเครื่องบินเป็นชั้นๆ ซึ่งเรียกกันทั่วไปว่าเอฟเฟ็กต์เปอร์สเป็คทีฟ ในภาพนี้ ฉันใช้ช่องเมฆและพื้นหลังของเมฆเพื่อไหลด้วยความเร็วที่แตกต่างกัน เพื่อสร้างเอฟเฟ็กต์เปอร์สเปคทีฟ A แบบบิน
ฉันนำเสนอเมฆในรูปแบบของพื้นผิว แต่เพียงพื้นผิวเท่านั้นที่จะบังท้องฟ้าและเครื่องบิน ซึ่งจะส่งผลต่อรูปลักษณ์และความรู้สึกของเครื่องบินที่กำลังบินอย่างมาก ดังนั้นฉันจึงเปิดความโปร่งใสและความทึบขององค์ประกอบกราฟิกที่เกี่ยวข้อง และ กำหนดระดับความโปร่งใสต่างๆ สำหรับพื้นหลังคลาวด์และช่องคลาวด์ ไม่เพียงแต่เพิ่มความรู้สึกเป็นชั้นๆ เท่านั้น แต่ยังทำให้ผู้คนมองเห็นภาพลวงตาของเมฆที่ลอยผ่านไปต่อหน้าต่อตาพวกเขาอีกด้วย
ช่องคลาวด์ใช้ประเภท ht.Polyline การปรับขนาดช่องสัญญาณจะขยายสัดส่วนของแกน Y ทำให้ช่องสัญญาณคลาวด์มีพื้นที่แนวตั้งที่ใหญ่ขึ้น การตั้งค่าสำเนาย้อนกลับแบบย้อนกลับช่วยให้สามารถแสดงพื้นผิวภายในช่องสัญญาณคลาวด์ได้ หากเครื่องบินอยู่ในอากาศ การเดินทางผ่านทะเลเมฆ พื้นหลังเมฆจะใช้ประเภท ht.Node และมีการตั้งค่าให้แสดงเป็นพื้นหลังเมฆเพียงพื้นผิวเดียว
เอฟเฟกต์การไหลของเมฆโดยรวมทำได้โดยใช้การชดเชยออฟเซ็ต และการชดเชยพื้นผิวของพื้นผิวดั้งเดิมหรือพื้นผิวดั้งเดิมที่สอดคล้องกันจะเปลี่ยนไปเพื่อให้ได้เอฟเฟกต์ของเครื่องบินที่เดินทางผ่านเมฆ รหัสมีดังนี้:
var i = 1, p = 0;setInterval(() => { i -= 0.1; p += 0.005; cloud.s('shape3d.uv.offset', [i, 0]); cloudBackground.s(' all.uv.offset', [p, 0]);}, 100);
เอฟเฟกต์การยกชน
แม้ว่าจะบรรลุผลเหมือนเครื่องบินที่บินผ่านเมฆ แต่หากเครื่องบินบินตรงเท่านั้นก็จะลดความรู้สึกที่แท้จริงในการบินด้วย ฉันเชื่อว่าเพื่อน ๆ ที่บินบนเครื่องบินจะต้องพบกับความปั่นป่วนที่เกิดจากการไหลของอากาศและบ่อยครั้ง รู้สึกถึงความปั่นป่วนที่เกิดจากการบินของเครื่องบิน การขึ้นลงระหว่างทางนั้นเป็นเพราะเส้นทางของเครื่องบินไม่ ht-animation.js
ถูกกำหนดไว้ที่ระดับความสูงที่แน่นอนเสมอไป - เพื่อให้เกิดเอฟเฟกต์เป็นหลุมเป็นบ่อของเครื่องบิน
dm.enableAnimation(20);plane.setAnimation({ back1: { จาก: 0, ถึง: 160, การค่อยๆ เปลี่ยน: 'Cubic.easeInOut', ระยะเวลา: 8000, ถัดไป: up1, onUpdate: ฟังก์ชั่น (ค่า) { value = parseInt( ค่า); var p3 = this.p3(); this.p3(ค่า, p3[1], p3[2]); }, //...ละเว้นการเริ่มต้นที่คล้ายกัน: [back1]});ข้อจำกัดมุมมองเซกเตอร์ทรงกลม
หลังจากเอฟเฟ็กต์การบินสมบูรณ์แบบ ฉันพบปัญหาที่ยากขึ้น เพราะแม้ว่าเครื่องบินจะบินผ่านทะเลเมฆจริง ๆ แต่ก็บินอยู่ในช่องเท่านั้น และพื้นหลังก็เป็นเพียงพื้นผิวเรียบ ดังนั้นเมื่อ มุมมองถึงระดับหนึ่ง เมื่อถึงระดับนี้ จะรู้สึกถึงความไม่สอดคล้องกันและความไม่สมจริงอย่างมาก และจำเป็นต้องมีการจำกัดมุมมองเพื่อปรับมุมมองภายในช่วงที่กำหนด
โดยทั่วไปแล้ว ข้อจำกัดในการรับชมจะจำกัดสายตาและศูนย์กลางของ g3d เพื่อนๆ ที่ไม่ค่อยมีความรู้เกี่ยวกับเรื่องนี้มากนัก สามารถอ่านคู่มือ 3D ได้จากเว็บไซต์ทางการของ hightopo ซึ่งมีคำแนะนำโดยละเอียด ฉันจะไม่ลงรายละเอียดที่นี่ ช่วงมุมฉันตัดสินใจแก้ไขตำแหน่งกึ่งกลางรหัสเป็นดังนี้:
g3d.addPropertyChangeListener(e => { // จุดศูนย์กลางคงที่ถ้า (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = ศูนย์กลาง[2];
จากนั้นให้จำกัด eye ไว้ที่ช่วงหนึ่งแล้วคุณก็ทำเสร็จแล้ว อย่างไรก็ตาม ในตอนแรกฉันจำกัด eye ไว้ที่ช่องว่างลูกบาศก์ แต่เอฟเฟกต์การโต้ตอบนั้นไม่เหมาะ เมื่อพิจารณาว่าในการโต้ตอบเริ่มต้นของ g3d , เมาส์ เมื่อลากและแพนเพื่อเปลี่ยนมุมมอง ดวงตาจะเคลื่อนที่บนพื้นผิวทรงกลมโดยให้ศูนย์กลางเป็นจุดศูนย์กลาง ดังนั้นฉันจึงตัดสินใจขุดพื้นที่จำกัดสำหรับดวงตาออกจากลูกบอลซึ่งเป็นเซกเตอร์ทรงกลม สำหรับผู้ที่ไม่เข้าใจดี คุณสามารถดูภาพนี้:
ขีดจำกัดการรับชมรูปพัดทรงกลมต้องใช้พารามิเตอร์ทั้งหมดสามตัว ได้แก่ แกนอ้างอิงตรงกลาง มุมระหว่างแกนกลางกับขอบด้านนอก และรัศมีที่จำกัดของลูกบอล สามารถกำหนดแกนอ้างอิงส่วนกลางได้ตาม เส้นต่อที่เชื่อมระหว่างตาเริ่มต้นกับจุดศูนย์กลาง และรัศมีที่จำกัดของลูกบอลจะแบ่งออกเป็นขีดจำกัดสูงสุดและขีดจำกัดต่ำสุด ดังนี้
ฟังก์ชั่น LimitEye (g3d, eye, center, options) { var LimitMaxL = options.limitMaxL, LimitMinL = options.limitMinL, LimitA = options.limitA; g3d.addPropertyChangeListener (e => { // จุดศูนย์กลางคงที่ถ้า (e.property = == 'center') { e.newValue[0] = center[0]; e.newValue[1] = ศูนย์กลาง[1]; e.newValue[2] = center[2]; } // จำกัดมุมมองถ้า (e.property === 'eye') { var newEyeV = new ht.Math.Vector3(e.newValue), centerV = new ht. Math.Vector3(กลาง), refEyeV = ใหม่ ht.Math.Vector3(ตา), refVector = refEyeV.clone().sub(centerV) newVector = newEyeV.clone().sub(centerV); if (centerV.distanceTo(newEyeV) > LimitMaxL) { newVector.setLength(limitMaxL); e.newValue[0] = newVector.x; newVector.y; e.newValue[2] = newVector.z; } ถ้า (centerV.distanceTo(newEyeV) LimitMinL) { newVector.setLength(limitMinL); e.newValue[0] = newVector.x; e.newValue[1] = newVector.y; e.newVector.z; } ถ้า (newVector.angleTo( refVector) > LimitA) { var oldLength = newVector.length(), oldAngle = newVector.angleTo(refVector), refLength = oldLength * Math.cos(oldAngle), vertVector, realVector, realEye; refVector.setLength(refLength); newEyeV = newVector.clone().เพิ่ม(centerV); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA); vertVector.setLength(vertLength); realVector = vertVector.clone().เพิ่ม(refEyeV).sub(centerV); .add(centerV); // ป้องกันมุมการเคลื่อนที่มากกว่า 180 องศา และกลับมุมมองถ้า (oldAngle > Math.PI / 2) { realEye.negate(); } e.newValue[0] = realEye.x; )}ระบบตรวจสอบเครื่องบิน
แน่นอนว่าในฐานะระบบเฝ้าติดตาม เป็นเรื่องปกติที่จะต้องมีการเฝ้าสังเกตเพิ่มแผนที่ขนาดเล็กที่มุมขวาล่างและมีโหมดสามโหมด: โฟกัสไปที่เครื่องบิน โฟกัสไปที่วิถีการบิน และโฟกัสไปที่แผนที่ และควบคุมเอฟเฟกต์การไหล ของวิถีการบินตามทิศทางการบินของเครื่องบิน โดยเน้นที่เครื่องบินจะติดตามการเคลื่อนที่ของเครื่องบินและดำเนินการ fitData เพื่อให้เครื่องบินอยู่ตรงกลางของแผนที่ขนาดเล็กเสมอ โดยมีรหัสดังนี้
var fitFlowP = function (e) { if (e.property === 'position' && e.data === ระนาบ) { mapGV.fitData (ระนาบ, false); }};buttonP.s({ 'interactive': true, 'onClick': ฟังก์ชั่น (เหตุการณ์ ข้อมูล มุมมอง จุด ความกว้าง ความสูง) { map.a('fitDataTag', 'plane2D'); mapGV.fitData(เครื่องบิน, false); mapDM.md(fitFlowP); }});buttonL.s({ 'interactive': true, 'onClick': ฟังก์ชั่น (เหตุการณ์, ข้อมูล, มุมมอง, จุด, ความกว้าง, ความสูง) { mapDM.umd(fitFlowP); map. a('fitDataTag', 'flyLine'); mapGV.fitData(flyLine, false }});// ...ละเว้น
เพิ่มการแจ้งให้เลื่อนเมาส์ไปยังตำแหน่งที่สอดคล้องกันของเครื่องบินเพื่อตั้งชื่อ ดับเบิลคลิกเพื่อแสดงแผงข้อมูลของตำแหน่งที่สอดคล้องกันของเครื่องบินและโฟกัสมุมมองบนแผง คลิกที่ใดก็ได้บนเครื่องบินเพื่อสลับกลับไปยัง โหมดการบินของเครื่องบิน และเอฟเฟกต์อื่นๆ
การเพิ่มแผงการตรวจสอบทางด้านซ้ายจะแทนที่การคลิกสองครั้งที่กล่าวมาข้างต้นของตำแหน่งที่เกี่ยวข้อง ซึ่งจะเน้นไปที่แผงข้อมูลที่ตำแหน่งที่เกี่ยวข้องโดยตรง ปุ่มที่นี่เปิดใช้งานการโต้ตอบและเพิ่มตรรกะการโต้ตอบที่เกี่ยวข้อง รหัสมีดังนี้:
button_JC.s({ 'interactive': true, 'onClick': ฟังก์ชั่น (เหตุการณ์ ข้อมูล มุมมอง จุด ความกว้าง ความสูง) { event.preventDefault(); ให้ g3d = G.g3d, g3dDM = G.g3d.dm (); g3d.fireInteractorEvent ({ ชนิด: 'doubleClickData' ข้อมูล: g3dDM.getDataByTag(data.getTag()) }) }});//...ละไว้เอฟเฟกต์การเรนเดอร์ท้องฟ้า
เนื่องจากเป็นระบบตรวจสอบจึงต้องตรวจสอบตลอด 24 ชั่วโมงโดยไม่มีความแตกต่าง เรื่องนี้เป็นไปไม่ได้สำหรับฉันที่จะบินข้ามท้องฟ้าสีครามกลางดึกสิ่งนี้จึงขาดความถูกต้องดังนั้นจึงต้องมี กระบวนการของท้องฟ้าจากสว่างไปมืด และจากมืดไปสว่าง ฉันตั้งกระบวนการนี้ไว้ชั่วคราวเป็นสองช่วงเวลา คือ 06:00-06:30 น. และ 19:00-19:30 น.
ท้องฟ้าใช้รูปทรงทรงกลม shape3d: 'sphere' เพื่อพันฉากทั้งหมด จากนั้นใช้ Reverse.flip เพื่อคัดลอกและผสมสีย้อม หลังจากนั้น ท้องฟ้าก็สามารถเรนเดอร์เป็นสีที่ฉันต้องการได้ แสงและเงาของท้องฟ้าตามเวลาก็ต้องเปลี่ยนค่าสีเท่านั้น
อย่างไรก็ตาม เนื่องจากสภาพแสงที่แตกต่างกันระหว่างกลางวันและกลางคืน ความเข้มของแสงที่สะท้อนจากเมฆจึงแตกต่างกัน ซึ่งนำไปสู่ความแตกต่างระหว่างเมฆในเวลากลางวันและกลางคืน ดังนั้นจึงจำเป็นต้องปรับความทึบแสงของเมฆด้วย พื้นผิวของช่องและคลาวด์ซึ่งโปร่งใสมากขึ้นในเวลากลางคืน รหัสมีดังนี้:
if ((ชั่วโมง > 6 && ชั่วโมง < 19) || (ชั่วโมง == 6 && นาที >= 30)) { timePane && timePane.a ({ 'morning.visible': false, 'day.visible': true, ' Dusk.visible': false, 'night.visible': false, 'day.opacity': 1 }) skyBox.s({ shape3d.blend: 'rgb (127, 200, 240)', }) cloudBackground.s ({ back.opacity: 0.7, }) cloud.s ({ shape3d.opacity: 0.7, })} อื่น ๆ ถ้า ((ชั่วโมง < 6 || ชั่วโมง > 19) ||. (ชั่วโมง == 19 && นาที >= 30)) {//...ละไว้} อย่างอื่นถ้า (ชั่วโมง == 6 && นาที < 15 ) {//...ละเว้น} อื่นถ้า (ชั่วโมง == 6 && นาที >= 15 && นาที < 30) {//...ละไว้} อื่นถ้า (ชั่วโมง == 19 && นาที < 15) { //...ละไว้} อื่นถ้า (ชั่วโมง == 19 && นาที >= 15 && นาที < 30) {//...ละไว้}
ที่นี่ฉันยังเพิ่มการรองรับไอคอนสถานะเวลาที่มุมขวาบนของแผงเวลา และเพิ่มเอฟเฟกต์จางลงเมื่อสลับไอคอน ในเวลาเดียวกัน ฉันเพิ่มคลิกเพื่อสลับ ไปยังตำแหน่งไอคอนสถานะครั้งถัดไปสำหรับไอคอนสถานะแผงเวลา
เพื่อแสดงให้เห็นถึงผลกระทบ ฉันจึงเพิ่มปุ่มเพิ่มเวลาเป็นสองเท่า รูปภาพต่อไปนี้แสดงการเปลี่ยนแปลงที่ 500 เท่าของอัตราการไหลของเวลา:
สรุปในการสาธิตนี้ ฉันพบว่ามีรายละเอียดมากมายในชีวิตที่ไม่มีใครสังเกตเห็น และมีความเป็นไปได้ในการแสดงข้อมูลเป็นภาพ ในยุคของข้อมูลขนาดใหญ่นี้ ความเป็นไปได้ต่างๆ มากมายคุ้มค่าแก่การสำรวจ อย่าพลาดทุกข้อมูลอันมีค่า การแสดงรายละเอียดรอบตัวคุณไม่เพียงแต่สามารถดึงศักยภาพของ HT สำหรับเว็บได้ดีขึ้นเท่านั้น แต่ยังช่วยเสริมคุณภาพโดยรวมในฐานะโปรแกรมเมอร์อีกด้วย