มีข้อแม้อยู่สองสามข้อสำหรับคำตอบของฉันซึ่งฉันจะออกไปให้พ้นก่อน: มันเกี่ยวข้องกับกล่องที่ไม่หมุนได้เท่านั้น ถือว่าคุณกำลังพยายามจัดการกับปัญหาการขุดอุโมงค์เช่นปัญหาที่เกิดจากวัตถุที่เคลื่อนที่ด้วยความเร็วสูง
เมื่อคุณระบุ MTV แล้วคุณจะรู้ว่าขอบ / พื้นผิวปกติคุณต้องทำการทดสอบ คุณก็รู้เวกเตอร์ความเร็วเชิงเส้นของวัตถุแทรกซึม
เมื่อคุณทราบแล้วว่าในบางช่วงระหว่างเฟรมเกิดจุดตัดขึ้นคุณสามารถดำเนินการครึ่งขั้นตอนแบบไบนารีโดยยึดตามจุดเริ่มต้นต่อไปนี้: ระบุจุดสุดยอดที่แทรกซึมครั้งแรกระหว่างเฟรม:
vec3 vertex;
float mindot = FLT_MAX;
for ( vert : vertices )
{
if (dot(vert, MTV) < mindot)
{
mindot = dot(vert, MTV);
vertex = vert;
}
}
เมื่อคุณมีจุดสุดยอดที่ระบุแล้วขั้นตอนครึ่งหนึ่งของไบนารีจะกลายเป็นราคาถูกกว่ามาก:
//mindistance is the where the reference edge/plane intersects it's own normal.
//The max dot product of all vertices in B along the MTV will get you this value.
halfstep = 1.0f;
vec3 cp = vertex;
vec3 v = A.velocity*framedurationSeconds;
float errorThreshold = 0.01f; //choose meaningful value here
//alternatively, set the while condition to be while halfstep > some minimum value
while (abs(dot(cp,normal)) > errorThreshold)
{
halfstep*=0.5f;
if (dot(cp,normal) < mindistance) //cp is inside the object, move backward
{
cp += v*(-1*halfstep);
}
else if ( dot(cp,normal) > mindistance) //cp is outside, move it forward
{
cp += v*(halfstep);
}
}
return cp;
นี่เป็นเหตุผลที่ถูกต้อง แต่จะให้จุดการชนเพียงครั้งเดียวในกรณีเดียว
โดยปกติแล้วเป็นไปได้ที่จะบอกล่วงหน้าว่าวัตถุจะเคลื่อนที่เร็วพอต่อเฟรมเพื่อให้สามารถขุดอุโมงค์แบบนี้ได้ดังนั้นคำแนะนำที่ดีที่สุดคือการระบุจุดยอดนำตามความเร็วและทำการทดสอบรังสีตามเวกเตอร์ความเร็ว ในกรณีของการหมุนวัตถุคุณจะต้องทำเลขฐานสองแบบครึ่งครึ่งบางส่วนเพื่อยืนยันจุดติดต่อที่ถูกต้อง
ในกรณีส่วนใหญ่ก็สามารถสันนิษฐานได้อย่างปลอดภัยว่าวัตถุส่วนใหญ่ในฉากของคุณจะไม่เคลื่อนที่เร็วพอที่จะเจาะเข้าไปไกลในเฟรมเดียวดังนั้นจึงไม่จำเป็นต้องเหยียบครึ่งหนึ่งและการตรวจจับการชนกันแบบไม่ต่อเนื่องจะเพียงพอ วัตถุความเร็วสูงเช่นกระสุนซึ่งเคลื่อนที่เร็วเกินกว่าจะมองเห็นสามารถนำไปใช้กับจุดสัมผัสได้
ที่น่าสนใจวิธี halfstep นี้ยังให้เวลา (เกือบ) เวลาที่วัตถุเกิดขึ้นระหว่างเฟรม:
float collisionTime = frametimeSeconds * halfstep;
หากคุณทำการแก้ปัญหาการชนกันของฟิสิกส์บางประเภทคุณสามารถแก้ไขตำแหน่งของ A โดย:
v - (v*halfstep)
จากนั้นคุณสามารถทำฟิสิกส์ของคุณได้ตามปกติ ข้อเสียคือถ้าวัตถุเคลื่อนที่เร็วพอสมควรคุณจะเห็นมันเคลื่อนย้ายกลับไปตามเวกเตอร์ความเร็ว