หน้านี้อธิบายปัญหาประสิทธิภาพทั่วไปและการปฏิบัติที่ดีที่สุดสำหรับการบรรเทาพวกมัน
คำนวณสคริปต์
การดำเนินการที่แพงในรหัส Luau ใช้เวลาในการประมวลผลนานขึ้นและจึงสามารถส่งผลต่ออัตราเฟรมได้เว้นแต่จะถูกดำเนินการแบบพาราเลลล์ Luau รหัสจะทำงานอย่างสะสมและบล็อกกระทู้หลักจนกว่าจะพบฟังก์ชันที่สร้างกระทู้ขึ้น
ปัญหาทั่วไป
การดำเนินการอย่างหนักในโครงสร้างตาราง - การดำเนินการที่ซับซ้อนเช่นการเซริฟิเคชันการถอดรหัสและการโคลนลึกมีค่าใช้จ่ายในการทำงานสูง โดยเฉพาะอย่างยิ่งในโครงสร้างตารางขนาดใหญ่เป็นจริงโดยเฉพาะอย่างยิ่งถ้าการดำเนินการเหล่านี้เป็นการเรียกซ้ำหรือรวมถึงการเรียกซ้ำเหนือโครงสร้างข้อมูลขนาดใหญ่เกินไป
อีเวนต์ความถี่สูง - ผูกการดำเนินการแพงไปยังอีเวนต์ขอบเฟรมของ RunService โดยไม่ จํากัด ความถี่หมายความว่าการดำเนินการเหล่านี้จะถูกทําซ้ําในแต่ละเฟรมซึ่งมักจะทําให้เกิดการเพิ่มขึ้นที่ไม่จําเป็นในเวลาการคํานวณกิจกรรมเหล่านี้รวมถึง:
การลดผลกระทบ
- เรียกร้องโค้ดในกิจกรรม RunService อย่างประหยัด จํากัดการใช้งานเฉพาะกรณีที่การเรียกใช้บ่อยเป็นสิ่งจําเป็น (ตัวอย่างเช่น การอัปเดตกล้อง)คุณสามารถดําเนินโค้ดอื่น ๆ ส่วนใหญ่ในอีเวนต์อื่นหรือบ่อยน้อยลงในลูป
- แยกภารกิจขนาดใหญ่หรือราคาแพงโดยใช้ task.wait() เพื่อกระจายงานไปทั่วหลายกรอบ
- ระบุและเพิ่มประสิทธิภาพการดำเนินการที่มีราคาแพงโดยไม่จำเป็นและใช้ multithreading สำหรับภารกิจที่มีราคาแพงในการคำนวณที่ไม่จำเป็นต้องเข้าถึงโมเดลข้อมูล
- สคริปต์บางตัวบนเซิร์ฟเวอร์สามารถได้รับประโยชน์จาก การสร้างโค้ดเดิม ซึ่งเป็นธงง่ายๆ ที่รวบรวมสคริปต์เป็นโค้ดแมชชีนแทนโค้ดไบต์
ขอบเขตของ MicroProfiler
ขอบเขต | การคำนวณที่เกี่ยวข้อง |
RunService.PreRender (การดำเนินการก่อนที่จะเรนเดอร์) | รหัสที่ดำเนินการในอีเวนต์ PreRender |
RunService.PreSimulation สามารถใช้งานได้แล้ว | การดําเนินโค้ดบนอีเวนต์ Stepped |
ทำงานบริการ RunService.PostSimulation | รหัสดำเนินการในอีเวนต์ Heartbeat |
การดำเนินการ RunService.Heartbeat | รหัสดำเนินการในอีเวนต์ Heartbeat |
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการแก้ไขข้อผิดพลาดของสคริปต์โดยใช้ MicroProfiler ดูที่ห้องสมุด debug ซึ่งรวมฟังก์ชันสำหรับการทำเครื่องหมายโค้ดเฉพาะและเพิ่มความเฉพาะเจาะจงมากขึ้นเช่น debug.profilebegin และ debug.profileendวิธีการ API Roblox จํานวนมากที่เรียกโดยสคริปต์ยังมีแท็ก MicroProfiler ที่เกี่ยวข้องของตนเองที่สามารถให้สัญญาณที่มีประโยชน์
การใช้หน่วยความจำของสคริปต์
การรั่วไหลของหน่วยความจําสามารถเกิดขึ้นเมื่อคุณเขียนสคริปต์ที่ใช้หน่วยความจําที่คัดลอกขยะไม่สามารถปล่อยได้อย่างถูกต้องเมื่อหมดการใช้งานการรั่วไหลมีอยู่อย่างแพร่หลายบนเซิร์ฟเวอร์โดยเฉพาะเพราะพวกเขาสามารถออนไลน์ได้อย่างต่อเนื่องเป็นเวลาหลายวันในขณะที่เซสชันของไคลเอนต์สั้นมาก
ค่าหน่วยความจําต่อไปนี้ใน คอนโซลผู้พัฒนา สามารถบ่งบอกถึงปัญหาที่ต้องการการตรวจสอบเพิ่มเติม:
- LuaHeap - การบริโภคสูงหรือเพิ่มขึ้นแนะนำว่ามีการรั่วไหลของหน่วยความจำ
- จํานวนตัวอย่าง - เพิ่มจํานวนตัวอย่างอย่างต่อเนื่องแสดงให้เห็นว่าการอ้างอิงถึงบางตัวอย่างในโค้ดของคุณไม่ถูกเก็บขยะอย่างสม่ำเสมอ
- หน่วยความจําสคริปต์สถานที่ - ให้สคริปต์โดยการแยกส่วนของการใช้หน่วยความจําของสคริปต์
ปัญหาทั่วไป
ออกการเชื่อมต่อที่เชื่อมต่ออยู่ - เครื่องยนต์ไม่เคยรวบรวมขยะอีเวนต์ที่เชื่อมโยงกับตัวอย่างและค่าใดๆ ที่อ้างอิงภายในคอลเลกชันการโทรกลับที่เชื่อมต่อดังนั้นการเชื่อมต่อที่ใช้งานของเหตุการณ์และโค้ดภายในตัวอย่างที่เชื่อมต่อฟังก์ชันที่เชื่อมต่อ และค่าที่อ้างอิง ออกจากขอบเขตของตัวรวบรวมขยะหน่วยความจำแม้หลังจากที่เหตุการณ์ถูกยิง
แม้ว่าเหตุการณ์จะถูกตัดการเชื่อมต่อเมื่อตัวอย่างที่พวกเขาเป็นส่วนหนึ่งถูกทําลาย แต่ข้อผิดพลาดทั่วไปคือการเชื่อว่าสิ่งนี้ใช้กับวัตถุ Playerหลังจากที่ผู้ใช้ออกจากประสบการณ์แล้ว เครื่องยนต์จะไม่ทําลายวัตถุและโมเดลตัวละครที่เป็นตัวแทนของพวกเขาโดยอัตโนมัติ Player และโมเดลตัวละครและตัวละคร เช่น Player ซึ่งอยู่ภายใต้โมเดลตัวละคร เช่น Player.CharacterAdded จะยังคงใช้หน่วยความจําหากคุณไม่แยกพวกเขาออกจากสคริปท์ของคุณอาจทำให้เกิดการรั่วไหลหน่วยความจําอย่างมากในเวลาผ่านไปบนเซิร์ฟเวอร์เมื่อผู้ใช้หลายร้อยคนเข้าร่วมและออกจากประสบการณ์
ตาราง - การสอดแทรกวัตถุลงในตาราง แต่ไม่ลบพวกมันเมื่อไม่จำเป็นอีกต่อไปทำให้เกิดการใช้หน่วยความจำที่ไม่จำเป็น โดยเฉพาะอย่างยิ่งสำหรับตารางที่ติดตามข้อมูลผู้ใช้เมื่อพวกเขาเข้าร่วมตัวอย่างโค้ดต่อไปนี้สร้างตารางที่เพิ่มข้อมูลผู้ใช้ทุกครั้งที่ผู้ใช้เข้าร่วม
ตัวอย่างเช่นlocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- ข้อมูลบางส่วนend)หากคุณไม่ลบรายการเหล่านี้เมื่อไม่จำเป็นอีกต่อไป ตารางจะยังคงเติบโตในขนาดและใช้ทรัพยากรหน่วยความจำมากขึ้นเมื่อผู้ใช้รายอื่นเข้าร่วมเซสชันรหัสใดๆ ที่ซ้ำซ้อนบนตารางนี้ยังกลายเป็นราคาแพงมากขึ้นเมื่อตารางเติบโตขนาดใหญ่ขึ้น
การลดผลกระทบ
เพื่อล้างค่าทั้งหมดที่ใช้แล้วเพื่อป้องกันการรั่วไหลของหน่วยความจำ:
ตัดการเชื่อมต่อทั้งหมด - ไปผ่านฐานคอดของคุณตรวจสอบให้แน่ใจว่าแต่ละการเชื่อมต่อถูกล้างออกผ่านหนึ่งในเส้นทางต่อไปนี้:
- ตัดการเชื่อมต่อด้วยตนเองโดยใช้ฟังก์ชัน Disconnect()
- การทําลายตัวอย่างที่เหตุการณ์นั้นเป็นส่วนหนึ่งด้วยฟังก์ชัน Destroy()
- ทำลายวัตถุสคริปต์ที่เชื่อมโยงกลับไป
ลบวัตถุและตัวละครผู้เล่นหลังจากออก - ใช้รหัสเพื่อให้แน่ใจว่าไม่มีการเชื่อมต่อยังคงอยู่หลังจากที่ผู้ใช้ออกไป เช่นในตัวอย่างต่อไปนี้:
ตัวอย่างเช่นPlayers.PlayerAdded:Connect(function(player)player.CharacterRemoving:Connect(function(character)task.defer(character.Destroy, character)end)end)Players.PlayerRemoving:Connect(function(player)task.defer(player.Destroy, player)end)
การคำนวณทางกายภาพ
การจำลองฟิสิกส์ที่มากเกินไปอาจเป็นสาเหตุสําคัญของเวลาการคํานวณที่เพิ่มขึ้นต่อเฟรมทั้งบนเซิร์ฟเวอร์และไคลเอนต์
ปัญหาทั่วไป
ความถี่ขั้นตอนทางฟิสิกส์ที่มากเกินไป - โดยปกติแล้ว การก้าวจะอยู่ในโหมด "adaptive" ซึ่งก้าวฟิสิกส์ที่ 60 Hz, 120 Hz หรือ 240 Hz ขึ้นอยู่กับความซับซ้อนของเมคานิกส์ทางฟิสิกส์
โหมดคงที่ที่มีความแม่นยำของฟิสิกส์ที่ดีขึ้นยังมีอยู่เช่นกันซึ่งบังคับให้ทุกชิ้นส่วนฟิสิกส์เดินที่ความถี่ 240 Hz (สี่ครั้งต่อเฟรม)ผลลัพธ์นี้ทำให้เกิดการคำนวณเพิ่มขึ้นอย่างมากในแต่ละเฟรม
จํานวนความซับซ้อนที่มากเกินไปของวัตถุจําลอง - ยิ่งมีการจําลอง 3D มากเท่าใด การคํานวณทางฟิสิกส์ก็จะใช้เวลานานขึ้นในแต่ละเฟรมบ่อยครั้งที่ประสบการณ์จะมีวัตถุที่ถูกจำลองที่ไม่จำเป็นต้องเป็นหรือจะมีเครื่องมือที่มีข้อจำกัดและข้อต่อมากกว่าที่ต้องการ
การตรวจจับการชนที่แม่นยําเกินไป - ชิ้นส่วนเมชมีคุณสมบัติ CollisionFidelity สําหรับการตรวจจับการชนซึ่งมีหลายโหมดที่มีผลกระทบต่อประสิทธิภาพที่แตกต่างกันโหมดการตรวจจับการชนที่แม่นยําสําหรับชิ้นส่วนเมชมีค่าใช้จ่ายในการทํางานแพงที่สุดและใช้เวลานานกว่าในการคํานวณเครื่องยนต์
การลดผลกระทบ
ชิ้นส่วนที่ไม่ต้องการการจำลอง - ยึดชิ้นส่วนทั้งหมดที่ไม่จำเป็นต้องขับเคลื่อนด้วยฟิสิกส์ เช่น สำหรับ NPC คงที่
ใช้การก้าวทางกายภาพแบบปรับได้ - การก้าวทางกายภาพที่ปรับได้จะปรับอัตราการคำนวณฟิสิกส์สำหรับฟิสิกส์ในรูปแบบต่างๆ โดยอัตโนมัติ ทำให้สามารถทำการอัปเดตฟิสิกส์ได้บ่อยน้อยลงในบางกรณี
ลดความซับซ้อนของเครื่องกล * หากเป็นไปได้ให้ลดจํานวนข้อจํากัดทางฟิสิกส์หรือข้อต่อในการประกอบให้น้อยที่สุด
- ลดปริมาณการชนกันของตัวเองภายในเครื่องจักร เช่น โดยการใช้ข้อจํากัดหรือข้อจํากัดการไม่ชนกันกับส่วนของรากดอลล์เพื่อป้องกันไม่ให้มันชนกันกับอีก
ลดการใช้ความถูกต้องของการชนกันอย่างแม่นยําสําหรับเมช * สำหรับวัตถุขนาดเล็กหรือไม่สามารถโต้ตอบได้ซึ่งผู้ใช้จะแทบไม่สังเกตเห็นความแตกต่าง ให้ใช้ความจงรักภักดีของกล่อง
สำหรับวัตถุขนาดเล็กถึงขนาดกลางใช้ความจงรักภักดีของกล่องหรือเรือโดยขึ้นอยู่กับรูปร่าง
สำหรับวัตถุขนาดใหญ่และซับซ้อนมาก ให้สร้างการชนกันแบบกำหนดเองโดยใช้ส่วนที่มองไม่เห็นเมื่อเป็นไปได้
สำหรับวัตถุที่ไม่ต้องการการชนกัน ให้ปิดการชนกันและใช้ความจงรักภาพของกล่องหรือเรือ เนื่องจากภาคการชนกันยังคงถูกเก็บไว้ในหน่วยความจำอยู่
คุณสามารถเรนเดอร์คอลลิเดนซ์เพื่อวัตถุประสงค์ในการดีบักใน Studio โดยสลับเปิดใช้งาน ความถูกต้องของการชน จากวิดเจ็ต ตัวเลือกการแสดงผล ในมุมขวาบนของหน้าต่าง 3D ดูเพื่อดีบัก
หรือคุณสามารถใช้ฟิลเตอร์ CollisionFidelity = Precise กับ Explorer ซึ่งแสดงจํานวนชิ้นส่วนเมชทั้งหมดที่มีความถูกต้องแม่นยําและช่วยให้คุณสามารถเลือกได้อย่างง่ายดาย
สำหรับการสำรวจแบบละเอียดเกี่ยวกับวิธีการเลือกตัวเลือกความน่าเชื่อถือของการชนกันที่สมดุลความต้องการด้านความแม่นยําและประสิทธิภาพของคุณ โปรดดู ตั้งค่าพารามิเตอร์ฟิสิกส์และการเรนเดอร์ริ่ง
ขอบเขตของ MicroProfiler
ขอบเขต | การคำนวณที่เกี่ยวข้อง |
ฟิสิกส์ขั้นตอน | การคำนวณทางฟิสิกส์โดยรวม |
ก้าวโลก | ขั้นตอนฟิสิกส์เฉพาะที่ใช้ในแต่ละเฟรม |
การใช้หน่วยความจําทางกายภาพ
การเคลื่อนที่และการตรวจจับการชนกินพื้นที่หน่วยความจำชิ้นส่วนเมชมีคุณสมบัติ CollisionFidelity ที่กำหนดวิธีการที่ใช้ในการประเมินขอบเขตการชนกันของเมช
ปัญหาที่พบบ่อย
โหมดการตรวจจับการชนที่เริ่มต้นและแม่นยําใช้ความทรงจํามากกว่าสองโหมดอื่นที่มีรูปแบบการชนที่มีความถูกต้องน้อยกว่าอย่างมาก
หากคุณเห็นระดับการใช้หน่วยความจําสูงภายใต้ PhysicsParts คุณอาจต้องสํารวจการลดความน่าเชื่อถือของการชนกันของวัตถุในประสบการณ์ของคุณ
วิธีลดความเสี่ยง
เพื่อลดหน่วยความจําที่ใช้สําหรับความน่าเชื่อถือในการชนกัน:
- สำหรับชิ้นส่วนที่ไม่ต้องการการชนกัน ให้ปิดการชนกันโดยการตั้ง BasePart.CanCollide , BasePart.CanTouch และ BasePart.CanQuery เป็น false
- ลดความจงรักภักดีของการชนกันโดยใช้การตั้งค่า Class.MeshPart.CollisionFidelity|CollisionFidelity``Enum.CollisionFidelity.Box|Box มีภาระหน่วยความจำต่ำสุด และ Default และ Precise มักจะแพงกว่า
- โดยทั่วไปปลอดภัยที่จะตั้งความน่าเชื่อถือในการชนกันของชิ้นส่วนที่ติดตั้งขนาดเล็กใดๆ เป็น Box
- สำหรับเมชที่ซับซ้อนมาก คุณอาจต้องการสร้างเมชการชนกันของคุณเองจากวัตถุขนาดเล็กที่มีความน่าเชื่อถือในการชนกล่อง
มนุษย์เทียม
Humanoid เป็นคลาสที่ให้ฟังก์ชันหลากหลายแก่ตัวละครผู้เล่นและตัวละครที่ไม่ใช่ผู้เล่น (NPC)แม้ว่าจะมีประสิทธิภาพ แต่ Humanoid มาพร้อมกับต้นทุนการคำนวณที่สำคัญ
ปัญหาทั่วไป
- ปิดใช้งานทั้งหมด HumanoidStateTypes บน NPCs - มีค่าใช้จ่ายด้านประสิทธิภาพในการปิดใช้งานบางส่วน HumanoidStateTypes ที่เปิดใช้งานอยู่ปิดใช้งานใดๆ ที่ไม่จำเป็นสำหรับ NPC ของคุณตัวอย่างเช่น หาก NPC ของคุณไม่ได้จะปีนบันได ก็ปลอดภัยที่จะปิดใช้งานสถานะ Climbing
- สร้างรูปแบบใหม่ ปรับแต่ง และเกิดใหม่อีกครั้งกับมนุษย์บ่อยๆ * นี่อาจเป็นการใช้งานหนักสำหรับเครื่องยนต์ในการประมวลผลโดยเฉพาะอย่างยิ่งถ้ารูปแบบเหล่านี้ใช้ เสื้อผ้าชั้นใน นี่ยังอาจเป็นปัญหาพิเศษในประสบการณ์ที่อวาตาร์เกิดใหม่บ่อย
- ใน MicroProfiler แท็กยาว อัปเดตคลัสเตอร์ที่ไม่ถูกต้องอย่างรวดเร็ว (มากกว่า 4 มิลลิวินาที) มักเป็นสัญญาณว่าการสร้าง/การแก้ไขอวาตาร์กำลังกระตุ้นการละเมิดที่มากเกินไป
- การใช้ Humanoids ในกรณีที่ไม่จำเป็น - NPC คงที่ที่ไม่เคลื่อนไหวโดยทั่วไปไม่จำเป็นต้องใช้คลาส Humanoid
- การเล่นแอนิเมชันบนจํานวน NPC จํานวนมากจากเซิร์ฟเวอร์ - แอนิเมชัน NPC ที่ทํางานบนเซิร์ฟเวอร์จะต้องถูกจําลองบนเซิร์ฟเวอร์และสําเนาไปยังไคลเอ็นต์นี่อาจเป็นค่าใช้จ่ายที่ไม่จำเป็น
การลดผลกระทบ
- เล่นแอนิเมชั่น NPC บนไคลเอนต์ - ในประสบการณ์ที่มีจํานวน NPC จํานวนมากให้พิจารณาสร้าง Animator บนไคลเอนต์และดําเนินการแอนิเมชั่นในท้องถิ่นสิ่งนี้ลดภาระบนเซิร์ฟเวอร์และความจำเป็นในการสําเนาที่ไม่จําเป็นนอกจากนี้ยังทำให้การปรับแต่งเพิ่มเติมเป็นไปได้ (เช่นเพียงเล่นแอนิเมชั่นสำหรับ NPC ที่อยู่ใกล้ตัวละครเท่านั้น)
- ใช้ทางเลือกที่เป็นมิตรกับประสิทธิภาพแทนมนุษย์ - โมเดล NPC ไม่จำเป็นต้องมีวัตถุมนุษย์อยู่
- สำหรับ NPC คงที่ใช้ AnimationController ง่ายๆเพราะพวกเขาไม่จำเป็นต้องเคลื่อนที่แต่ต้องการเล่นแอนิเมชั่นเท่านั้น
- สำหรับการเคลื่อนย้าย NPC พิจารณาการใช้ตัวควบคุมการเคลื่อนที่ของคุณเองและใช้ AnimationController สำหรับภาพเคลื่อนไหวขึ้นอยู่กับความซับซ้อนของ NPC ของคุณ
- ปิดใช้งานสถานะ humanoid ที่ไม่ได้ใช้งาน - ใช้ Humanoid:SetStateEnabled() เพื่อเปิดใช้งานสถานะที่จำเป็นเท่านั้นสำหรับแต่ละ humanoid
- รูปแบบ NPC สระน้ำที่มีการฟื้นคืนชีพบ่อย - แทนที่จะทำลาย NPC อย่างสมบูรณ์ ส่ง NPC ไปยังสระน้ำของ NPC ที่ไม่ได้ใช้งานวิธีนี้เมื่อต้องการรีสปอว์น NPC ใหม่ คุณสามารถเปิดใช้งาน NPC หนึ่งจากสระน้ำได้อีกครั้งกระบวนการนี้เรียกว่าการรวม ซึ่งลดจํานวนครั้งที่ตัวละครจะต้องถูกสร้างขึ้น
- สร้าง NPC เฉพาะเมื่อผู้ใช้อยู่ใกล้เท่านั้น - อย่าสร้าง NPC เมื่อผู้ใช้ไม่อยู่ในระยะ และกำจัดพวกเขาเมื่อผู้ใช้ออกจากระยะ
- หลีกเลี่ยงการทำการเปลี่ยนแปลงในลำดับชั้นของอวตารหลังจากที่มันถูกสร้างขึ้น - การแก้ไขบางอย่างในลำดับชั้นของอวตารมีผลกระทบที่สำคัญต่อประสิทธิภาพมีการปรับแต่งบางอย่างที่สามารถใช้ได้
- สำหรับแอนิเมชั่นขั้นตอนที่กำหนดเอง, อย่าอัปเดตคุณสมบัติ JointInstance.C0 และ JointInstance.C1 แต่ให้อัปเดตคุณสมบัติ Motor6D.Transform
- หากต้องการแนบวัตถุใด ๆ BasePart ให้กับอวาตาร์ ให้ทำเช่นนั้นนอกเหนือจากระดับของอวาตาร์ Model
ขอบเขตของ MicroProfiler
ขอบเขต | การคำนวณที่เกี่ยวข้อง |
ขั้นตอน Humanoid | การควบคุมและฟิสิกส์ของมนุษย์หุ่น |
ขั้นตอนแอนิเมชัน | ภาพเคลื่อนไหวของมนุษย์และนักแสดงแอนิเมะ |
อัปเดตกลุ่มเร็วที่ไม่ถูกต้อง | เกี่ยวข้องกับการสร้างหรือแก้ไขอวาตาร์ |
การทำเรนเดอร์
ส่วนสำคัญของเวลาที่ลูกค้าใช้ในแต่ละเฟรมคือการเรนเดอร์สถานที่ในเฟรมปัจจุบันเซิร์ฟเวอร์ไม่ทำการเรนเดอร์ใดๆ ดังนั้นส่วนนี้จึงเป็นพิเศษสำหรับไคลเอนต์เท่านั้น
เรียกภาพ
การเรียกวาดเป็นชุดคําแนะนําจากเครื่องยนต์ไปยัง GPU เพื่อแสดงผลบางสิ่งการเรียกวาดมีค่าใช้จ่ายที่สำคัญโดยทั่วไป ยิ่งมีการเรียกวาดน้อยลงต่อเฟรม เวลาในการคำนวณก็จะน้อยลงในการเรนเดอร์เฟรม
คุณสามารถดูได้ว่าการเรียกวาดเกิดขึ้นกี่ครั้งในขณะนี้ด้วยไอเทม สถิติการเรนเดอร์ > เวลา ใน Studioคุณสามารถดู สถิติการเรนเดอร์ ในไคลเอนต์โดยกด ShiftF2
ยิ่งมีวัตถุมากขึ้นที่ต้องวาดในฉากในกรอบเวลาที่กำหนด การเรียกใช้การวาดจะถูกส่งไปยัง GPU มากขึ้นอย่างไรก็ตาม เครื่องยนต์ Roblox ใช้กระบวนการที่เรียกว่า instancing เพื่อย่อเมชที่เหมือนกันด้วยลักษณะเทกเจอร์เดียวกันให้เป็นการเรียกวาดเดียวโดยเฉพาะอย่างยิ่งเมชที่หลากหลายด้วยเดียวกัน MeshId จะได้รับการจัดการในการเรียกวาดเดียวเมื่อ:
- วัสดุจะเหมือนกันเมื่อทั้ง SurfaceAppearance และ MeshPart.TextureID ไม่มีอยู่
ปัญหาทั่วไปอื่น ๆ
ความหนาแน่นวัตถุที่มากเกินไป - หากจํานวนวัตถุจํานวนมากถูกรวมไว้ด้วยความหนาแน่นสูง การเรนเดอร์ส่วนนี้ของฉากจะต้องใช้การเรียกวาดเพิ่มเติมหากคุณพบว่าอัตราเฟรมของคุณลดลงเมื่อมองไปที่ส่วนหนึ่งของแผนที่บางอย่าง นี่อาจเป็นสัญญาณที่ดีว่าความหนาแน่นของวัตถุในพื้นที่นี้สูงเกินไป
วัตถุเช่นภาพวาด เทกเจอร์ และอนุภาคไม่สามารถจัดเรียงได้ดีและนำเสนอการดึงเพิ่มเติมได้ให้ความสนใจเป็นพิเศษกับประเภทวัตถุเหล่านี้ในฉากโดยเฉพาะอย่างยิ่งการเปลี่ยนแปลงคุณสมบัติเป็น ParticleEmitters อาจมีผลกระทบอย่างมากต่อประสิทธิภาพ
พลาดโอกาสในการจำลอง - บ่อยครั้งที่ฉากจะรวมเมชเดียวกันซ้ำหลายครั้ง แต่แต่ละเมชของเมชมี ID ทรัพยากรเมชหรือเทกเจอร์ที่แตกต่างกันสิ่งนี้ป้องกันการติดตั้งและอาจนำไปสู่การเรียกดึงที่ไม่จำเป็น
สาเหตุทั่วไปของปัญหานี้คือเมื่อนำฉากทั้งหมดมาในครั้งเดียวแทนที่จะนำทรัพยากรแต่ละอย่างมายัง Roblox แล้วจากนั้นจะทำซ้ำหลังจากนำมาประกอบฉาก
ความซับซ้อนของวัตถุมากเกินไป - แม้ว่าจะไม่สำคัญเท่ากับจํานวนการเรียกวาด แต่จํานวนสามเหลี่ยมในฉากก็มีอิทธิพลต่อระยะเวลาที่ใช้ในการแสดงผลของเฟรมฉากที่มีจํานวนเมชที่ซับซ้อนมากจํานวนมากเป็นปัญหาทั่วไปเช่นเดียวกับฉากที่มีค่า MeshPart.RenderFidelity ของคุณตั้งค่าเป็น Enum.RenderFidelity.Precise บนเมชที่มากเกินไป
การโค้งเงามากเกินไป - การจัดการเงาเป็นกระบวนการที่มีราคาแพงและแผนที่ที่มีจํานวนและความหนาแน่นของแสงสูงที่โค้งเงา (หรือจํานวนและความหนาแน่นของชิ้นส่วนขนาดเล็กที่ได้รับอิทธิพลจากเงา) มีแนวโน้มที่จะมีปัญหาประสิทธิภาพ
การดึงความโปร่งใสสูง - วางวัตถุที่มีความโปร่งใสบางส่วนใกล้กันทำให้เครื่องยนต์ต้องแสดงพิกเซลซ้อนกันหลายครั้งซึ่งอาจส่งผลต่อประสิทธิภาพได้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการระบุและแก้ไขปัญหานี้ โปรดดู ลบความโปร่งใสแบบซ้อนกัน
การลดผลกระทบ
- สร้างเมชที่เหมือนกันและลดจำนวนเมชที่ไม่ซ้ำกัน - หากคุณตรวจสอบให้แน่ใจว่าเมชทั้งหมดเหมือนกันทั้งหมดมี ID สินทรัพย์พื้นฐานเดียวกันเดียวกัน เครื่องยนต์สามารถรู้จักและแสดงพวกเขาในการเรียกวาดเดียวได้ตรวจสอบให้แน่ใจว่าอัปโหลดแต่ละเมชในแผนที่เพียงครั้งเดียวแล้วทำซ้ำในสตูดิโอเพื่อใช้ซ้ำแทนการนำเข้าแผนที่ขนาดใหญ่ทั้งหมดซึ่งอาจทำให้เมชที่เหมือนกันมี ID เนื้อหาแยกต่างหากและได้รับการยอมรับว่าเป็นสินทรัพย์ที่ไม่ซ้ำกันโดยเครื่องยนต์แพคเกจ เป็นเครื่องมือที่มีประโยชน์สำหรับการใช้ซ้ำวัตถุ
- การคัดเลือก - การคัดเลือกอธิบายกระบวนการการลบคำสั่งวาดสำหรับวัตถุที่ไม่ได้เป็นปัจจัยในกรอบภาพที่สร้างขึ้นในที่สุดโดยค่าเริ่มต้น เครื่องยนต์จะข้ามการเรียกสำหรับวัตถุที่อยู่นอกสนามมุมมองของกล้อง (การคัดเลือก frustum) แต่ไม่ข้ามการเรียกสำหรับวัตถุที่ถูกปิดกั้นจากการมองเห็นโดยวัตถุอื่น (การคัดเลือกการปิดกั้น)หากฉากของคุณมีจำนวนการเรียกวาดจำนวนมาก พิจารณาที่จะใช้การคัดเลือกเพิ่มเติมของคุณเองในเวลาเรียลไทม์สำหรับทุกเฟรม เช่น การใช้กลยุทธ์ทั่วไปต่อไปนี้:
- สำหรับสภาพแวดล้อมภายใน, ให้ดำเนินการติดตั้งระบบห้องหรือพอร์ทัลที่ซ่อนวัตถุที่ไม่ได้ใช้งานอยู่ในปัจจุบันโดยผู้ใช้ใดๆ
- ลดความถูกต้องของการเรนเดอร์ - ตั้งความถูกต้องของการเรนเดอร์เป็น อัตโนมัติ หรือ ประสิทธิภาพ สิ่งนี้ช่วยให้เมชกลับไปใช้ทางเลือกที่ซับซ้อนน้อยลงซึ่งสามารถลดจํานวนโพลิโกนที่ต้องวาดได้
- การปิดใช้งานการโค้งเงาบนส่วนและวัตถุแสงที่เหมาะสม - ความซับซ้อนของเงาในฉากสามารถลดลงได้โดยการปิดใช้งานคุณสมบัติการโค้งเงาบนวัตถุแสงและส่วนอย่างเลือกได้สามารถทำได้ในเวลาแก้ไขหรืออย่างไดนามิกในระหว่างการทำงานตัวอย่างบางส่วนคือ:
ใช้คุณสมบัติ BasePart.CastShadow เพื่อปิดการโค้งเงาบนชิ้นส่วนขนาดเล็กที่มีโอกาสน้อยที่จะมองเห็นเงาสิ่งนี้สามารถมีประสิทธิภาพมากเมื่อใช้เฉพาะกับชิ้นส่วนที่อยู่ไกลจากกล้องของผู้ใช้เท่านั้น
ปิดใช้งานเงาบนวัตถุเคลื่อนที่เมื่อเป็นไปได้
ปิดการใช้งาน Light.Shadows บนตัวอย่างแสงที่วัตถุไม่จำเป็นต้องโค้งเงา
จำกัดระยะและมุมของตัวอย่างแสง
ใช้แสงน้อยลง
ขอบเขตของ MicroProfiler
ขอบเขต | การคำนวณที่เกี่ยวข้อง |
เตรียมและดำเนินการ | การแสดงผลโดยรวม |
ดําเนินการ/ฉาก/คํานวณแสงดําเนิน | การอัปเดตกริดแสงและเงา |
หน่วยประมวลผล LightGridCPU | การอัปเดตเครือข่ายแสง Voxel |
ระบบ ShadowMap | แผนที่เงา |
ดำเนินการ/ฉาก/อัปเดตมุมมอง | การเตรียมพร้อมสําหรับการเรนเดอร์และการอัปเดตอนุภาค |
ดำเนินการ/ฉาก/RenderView | การเรนเดอร์และการประมวลผลภายหลัง |
การเชื่อมต่อและการจำลอง
การเชื่อมต่อและการจำลองอธิบายถึงกระบวนการที่ข้อมูลถูกส่งระหว่างเซิร์ฟเวอร์และไคลเอนต์ที่เชื่อมต่อข้อมูลจะถูกส่งระหว่างไคลเอนต์และเซิร์ฟเวอร์ในทุกเฟรม แต่จำนวนข้อมูลที่มากขึ้นต้องใช้เวลาในการคำนวณมากขึ้น
ปัญหาทั่วไป
การจราจรระยะไกลที่มากเกินไป - การส่งข้อมูลจํานวนมากผ่าน RemoteEvent หรือ RemoteFunction วัตถุหรือเรียกใช้พวกเขาบ่อยมากเกินไปอาจทําให้เกิดเวลาในการประมวลผลของ CPU จํานวนมากในแต่ละเฟรมข้อผิดพลาดทั่วไปรวมถึง:
- สําเนาข้อมูลทุกเฟรมที่ไม่จําเป็นต้องสําเนา
- การสําเนาข้อมูลตามการใส่ของผู้ใช้โดยไม่มีเครื่องมือในการจํากัด
- ส่งข้อมูลมากกว่าที่จำเป็นตัวอย่างเช่น การส่งสินค้าคงคลังทั้งหมดของผู้เล่นเมื่อซื้อรายการแทนที่จะเป็นรายละเอียดของรายการที่ซื้อ
การสร้างหรือลบต้นไม้ตัวอย่างที่ซับซ้อน - เมื่อมีการทำการเปลี่ยนแปลงในโมเดลข้อมูลบนเซิร์ฟเวอร์ จะถูกส่งต่อไปยังไคลเอนต์ที่เชื่อมต่อซึ่งหมายความว่าการสร้างและทําลายชั้นวางตําแหน่งขนาดใหญ่เช่นแผนที่ในระหว่างการทํางานอาจใช้เครือข่ายมาก ๆ
คนร้ายทั่วไปที่นี่คือข้อมูลแอนิเมชันที่ซับซ้อนที่บันทึกโดยปลั๊กอินตัวแก้ไขแอนิเมชันในริกหากไม่มีการลบเหล่านี้ก่อนที่เกมจะเผยแพร่และโมเดลแอนิเมชั่นถูกคลอนอย่างสม่ำเสมอจำนวนข้อมูลจำนวนมากจะถูกเลียนแบบโดยไร้ความจำเป็น
บริการ TweenService ด้านเซิร์ฟเวอร์ - หาก TweenService ถูกใช้เพื่อทวีนเซิร์ฟเวอร์ด้านวัตถุ คุณสมบัติที่ทวีนจะถูกเลียนแบบไปยังแต่ละไคลเอนต์ในแต่ละเฟรมไม่เพียงแค่นี้ทำให้วัยรุ่นตื่นตระหนกเมื่อความล่าช้าของไคลเอนต์เปลี่ยนแปลง แต่ยังทำให้เกิดการจราจรเครือข่ายที่ไม่จำเป็นจํานวนมาก
การลดผลกระทบ
คุณสามารถใช้กลยุทธ์ต่อไปนี้เพื่อลดการซ้ำซ้อนที่ไม่จำเป็นได้
- หลีกเลี่ยงการส่งข้อมูลจํานวนมากในครั้งเดียวผ่านอีเวนต์ระยะไกล แทนที่จะส่งข้อมูลที่จำเป็นเฉพาะในความถี่ที่ต่ำกว่าตัวอย่างเช่น สำหรับสถานะของตัวละคร ทำซ้ำเมื่อมันเปลี่ยนแปลงแทนที่จะทำทุกเฟรม
- แยกต้นไม้กรณีที่ซับซ้อนออกเป็นชิ้นส่วน เช่นแผนที่และโหลดพวกมันในชิ้นส่วนเพื่อจัดจำหน่ายงานสําเร็จรูปเหล่านี้ไปทั่วหลายกรอบ
- ล้างข้อมูลอนิเมชั่น โดยเฉพาะอย่างยิ่งไดเรกทอรีอนิเมชั่นของแรมหลังจากนำเข้า
- จํากัดการสําเนาตัวอย่างที่ไม่จําเป็น โดยเฉพาะอย่างยิ่งในกรณีที่เซิร์ฟเวอร์ไม่จําเป็นต้องมีความรู้เกี่ยวกับตัวอย่างที่กําลังถูก创建ซึ่งรวมถึง:
- เอฟเฟกต์ภาพเช่นการระเบิดหรือระเบิดคาถาเวทมนตร์เซิร์ฟเวอร์ต้องรู้ตำแหน่งเท่านั้นเพื่อกำหนดผลลัพธ์ ในขณะที่ลูกค้าสามารถสร้างภาพได้ในท้องถิ่น
- รูปแบบการดูไอเทมบุคคลแรก
- วัตถุระหว่างทางบนไคลเอนต์แทนที่จะเป็นเซิร์ฟเวอร์
ขอบเขตของ MicroProfiler
ขอบเขต | การคำนวณที่เกี่ยวข้อง |
แพคเกจการประมวลผล | การประมวลผลสำหรับแพคเกจเครือข่ายที่เข้ามา เช่น การเรียกใช้อีเวนต์และการเปลี่ยนแปลงคุณสมบัติ |
จัดสรรความถี่และส่งสัญญาณผู้ส่ง | อีเวนต์ที่ออกไปที่เกี่ยวข้องกับเซิร์ฟเวอร์ |
การใช้หน่วยความจําทรัพยากรอย่างเต็มที่
กลไกผลกระทบสูงสุดที่มีอยู่สำหรับผู้สร้างเพื่อปรับปรุงการใช้หน่วยความจําของไคลเอนต์คือการเปิดใช้งาน การสตรีมตัวอย่าง
การสตรีมตัวอย่างอินสแตนซ์
การสตรีมตัวอย่างเลือกโหลดส่วนหนึ่งของโมเดลข้อมูลที่ไม่จำเป็นซึ่งอาจทำให้เวลาในการโหลดลดลงอย่างมากและเพิ่มความสามารถของไคลเอนต์ในการป้องกันการล้มเหลวเมื่ออยู่ภายใต้แรงกดดันของหน่วยความจำ
หากคุณพบปัญหาเกี่ยวกับหน่วยความจําและมีการสตรีมตัวอย่างถูกปิดใช้งาน ให้พิจารณาอัปเดตประสบการณ์ของคุณเพื่อสนับสนุนมัน โดยเฉพาะอย่างยิ่งหากโลก 3D ของคุณใหญ่การสตรีมตัวอย่างขึ้นอยู่กับระยะทางในพื้นที่ 3D ดังนั้นโลกขนาดใหญ่จะได้รับประโยชน์จากมันมากขึ้นตามธรรมชาติ
หากการสตรีมตัวอย่างเปิดใช้งานแล้ว คุณสามารถเพิ่มความก้าวร้าวของมันได้ ตัวอย่างเช่น พิจารณา:
- ลดการใช้งานอย่างถาวร StreamingIntegrity * ลดรัศมีการสตรีม **** สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกการสตรีมและประโยชน์ของพวกเขา ดู คุณสมบัติการสตรีม
ปัญหาทั่วไปอื่น ๆ
- การซ้ำของสินทรัพย์ - ข้อผิดพลาดทั่วไปคือการอัปโหลดสินทรัพย์เดียวหลายครั้งซึ่งทำให้เกิด ID สินทรัพย์ที่แตกต่างกันสิ่งนี้อาจทำให้เนื้อหาเดียวกันถูกโหลดเข้าสู่หน่วยความจำหลายรอบ
- ปริมาณสินทรัพย์ที่มากเกินไป - แม้ว่าสินทรัพย์จะไม่เหมือนกัน แต่ก็มีกรณีที่โอกาสในการนำสินทรัพย์เดียวกันกลับมาใช้และประหยัดหน่วยความจำถูกพลาด
- ไฟล์เสียง - ไฟล์เสียงสามารถเป็นผู้บริจาคที่น่าประหลาดใจต่อการใช้หน่วยความจำได้ โดยเฉพาะอย่างยิ่งหากคุณโหลดพวกเขาทั้งหมดลงในไคลเอนต์พร้อมกันแทนที่จะโหลดเฉพาะสิ่งที่คุณต้องการสำหรับส่วนหนึ่งของประสบการณ์สำหรับกลยุทธ์ ดูที่ เวลาโหลด
- เทกเจอร์ความละเอียดสูง - การใช้หน่วยความจำกราฟิกสำหรับเทกเจอร์ไม่เกี่ยวข้องกับขนาดของเทกเจอร์บนดิสก์ แต่เป็นจํานวนพิกเซลในเทกเจอร์
- ตัวอย่างเช่น เทกเจอร์ขนาด 1024x1024 ใช้หน่วยความจํากราฟิกสี่เท่าของเทกเจอร์ขนาด 512x512
- ภาพที่อัปโหลดไปยัง Roblox จะถูกเข้ารหัสเป็นรูปแบบคงที่ดังนั้นจึงไม่มีประโยชน์ในการอัปโหลดภาพในโมเดลสีที่มีขนาดไฟล์น้อยกว่า 1 ไบต์ต่อพิกเซลเช่นเดียวกับการบีบอัดภาพก่อนอัปโหลดหรือลบช่องแอลฟาออกจากภาพที่ไม่ต้องการสามารถลดขนาดภาพบนดิสก์ได้ แต่ก็ไม่ดีขึ้นหรือดีขึ้นเพียงเล็กน้อยเท่านั้นในการใช้หน่วยความจำแม้ว่าเครื่องยนต์จะลดความละเอียดของเทกเจอร์ในบางอุปกรณ์โดยอัตโนมัติ แต่ขนาดของการลดความละเอียดขึ้นอยู่กับคุณสมบัติของอุปกรณ์ และความละเอียดของเทกเจอร์ที่มากเกินไปยังคงสามารถทำให้เกิดปัญหาได้
- คุณสามารถระบุการใช้หน่วยความจำกราฟิกสำหรับเทกเจอร์ที่กำหนดได้โดยขยายหมวดหมู่ กราฟิกเทกเจอร์ ใน คอนโซลนักพัฒนา
การลดผลกระทบ
- อัปโหลดสินทรัพย์เพียงครั้งเดียว - ใช้สินทรัพย์เดียวกันในวัตถุทั้งหมดและตรวจสอบให้แน่ใจว่าสินทรัพย์เช่นเมชและภาพไม่ถูกอัปโหลดแยกต่างหากหลายครั้ง
- ค้นหาและแก้ไขสินทรัพย์ซ้ำ - มองหาชิ้นส่วนเมชและเทกเจอร์ที่เหมือนกันที่อัปโหลดหลายครั้งด้วย ID ที่แตกต่างกัน
- แม้ว่าจะไม่มี API ที่จะตรวจจับความคล้ายคลึงกันของสินทรัพย์โดยอัตโนมัติ คุณสามารถรวบรวม ID ทั้งหมดของสินทรัพย์ภาพในสถานที่ของคุณ (ไม่ว่าจะเป็นด้วยตนเองหรือด้วยสคริปต์) ดาวน์โหลดพวกเขา และเปรียบเทียบพวกเขาโดยใช้เครื่องมือเปรียบเทียบภายนอก
- สำหรับชิ้นส่วนเมช กลยุทธ์ที่ดีที่สุดคือการใช้ ID เมชที่ไม่ซ้ำกันและจัดเรียงตามขนาดเพื่อระบุชิ้นส่วนซ้ำด้วยตนเอง
- แทนที่จะใช้เทกเจอร์แยกต่างหากสำหรับสีที่แตกต่างกัน ให้อัปโหลดเทกเจอร์เดียวและใช้คุณสมบัติ SurfaceAppearance.Color เพื่อใช้สีต่างๆ กับมัน
- นำสินทรัพย์มาในแผนที่แยกต่างหาก - แทนที่จะนำแผนที่ทั้งหมดมาในครั้งเดียว ให้นำสินทรัพย์มาในแผนที่แยกต่างหากและสร้างใหม่ และสร้างใหม่นักนำเข้า 3D ไม่ทําการซ้ําของเมช ดังนั้นหากคุณนําเข้าแผนที่ขนาดใหญ่พร้อมกับกระเบื้องหลายชิ้น แต่ละกระเบื้องจะถูกนําเข้าเป็นสินทรัพย์แยกต่างหาก (แม้ว่าพวกเขาจะเป็นซ้ําก็ตามสิ่งนี้สามารถนำไปสู่ปัญหาประสิทธิภาพและหน่วยความจําลงตามเส้น เนื่องจากแต่ละเมชจะได้รับการปฏิบัติเป็นอิสระและใช้หน่วยความจําและดึงการโทรได้
- จำกัดพิกเซลของภาพ ไม่เกินจำนวนที่จำเป็นเว้นแต่ภาพจะใช้พื้นที่บนหน้าจอจํานวนมาก โดยปกติจะต้องการพิกเซลสูงสุด 512x512 เท่านั้นภาพขนาดเล็กส่วนใหญ่ควรเล็กกว่า 256x256 พิกเซล
- ใช้แผ่นตัด เพื่อให้แน่ใจว่ามีการใช้ซ้ำเทกเจอร์สูงสุดในแผนที่ 3 มิติสำหรับขั้นตอนและตัวอย่างวิธีการสร้างแผ่นตัดดูที่ การสร้างแผ่นตัด
เวลาในการโหลด
ประสบการณ์จํานวนมากใช้หน้าจอโหลดที่กําหนดเองและใช้วิธี ContentProvider:PreloadAsync() ในการร้องขอทรัพยากรเพื่อให้ภาพเสียงและเมชถูกดาวน์โหลดในพื้นหลัง
ประโยชน์ของวิธีนี้คือคุณสามารถตรวจสอบให้แน่ใจว่าส่วนสำคัญของประสบการณ์ของคุณโหลดเต็มแล้วโดยไม่ต้องป๊อปอินอย่างไรก็ตาม, ข้อผิดพลาดทั่วไปคือการใช้วิธีนี้มากเกินไปเพื่อการโหลดล่วงหน้าของทรัพยากรเพิ่มเติมกว่าที่จำเป็น
ตัวอย่างของการปฏิบัติที่ไม่ดีคือการโหลด ทั้งหมดWorkspaceแม้ว่าสิ่งนี้อาจป้องกันไม่ให้เทกเจอร์ปรากฏ แต่ก็เพิ่มเวลาในการโหลดอย่างมาก
แทนที่จะใช้เฉพาะ ContentProvider:PreloadAsync() ในสถานการณ์ที่จำเป็นซึ่งรวมถึง:
- รูปภาพในหน้าจอโหลด
- รูปภาพสำคัญในเมนูประสบการณ์ของคุณ เช่น พื้นหลังปุ่มและไอคอน
- สินทรัพย์สำคัญในพื้นที่เริ่มต้นหรือสร้างใหม่
หากคุณต้องโหลดจํานวนมากของสินทรัพย์ เราแนะนําให้คุณให้ปุ่ม ข้ามการโหลด