Lerping फ़ंक्शन में Time.deltaTime का उपयोग क्यों करें?


12

मेरी समझ में, एक Lerp फ़ंक्शन दो मानों ( aऔर ) के बीच bएक तीसरे मान ( t) 0और का उपयोग करके अंतर करता है 1। पर t = 0, मान लौटाया जाता है, पर t = 1, मान bलौटाया जाता है। 0.5 के बीच मान आधा हो जाता है aऔर bवापस आ जाता है।

(निम्नलिखित चित्र एक चिकनाई है, आमतौर पर एक घन प्रक्षेप)

यहाँ छवि विवरण दर्ज करें

मैं फ़ोरम ब्राउज़ कर रहा हूं और इस उत्तर पर मुझे कोड की निम्न पंक्ति मिली:transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime);

मैंने खुद से सोचा, "क्या मूर्ख है, उसे कोई पता नहीं है" लेकिन चूंकि इसमें 40+ अपवोट था इसलिए मैंने इसे एक कोशिश की और निश्चित रूप से पर्याप्त था, यह काम किया!

float t = Time.deltaTime;
transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, t);
Debug.Log(t);

मैं के बीच यादृच्छिक मान मिल गया 0.01और 0.02के लिए t। तदनुसार कार्य को प्रक्षेप नहीं करना चाहिए? ये मूल्य क्यों ढेर हो गए? यह लार्प के बारे में क्या है जो मुझे समझ में नहीं आता है?


1
ए आम तौर पर स्थिति है, जो 1/60 (60 एफपीएस) पर परिवर्तन और उसके नमूने को केवल 0.16 के प्रक्षेप द्वारा वस्तु को आगे बढ़ाएगा, ए और बी के बीच की दूरी को लगातार कम करेगा (इस प्रकार नमूना हर बार छोटा और छोटा होता है)।
सिदार

आपने t को लॉग किया और tt के साथ lerped ... वे अलग-अलग चर हैं।
user253751

जवाबों:


18

इसका जवाब भी देखिए

उपयोग करने के दो सामान्य तरीके हैं Lerp:

1. एक शुरुआत और एक अंत के बीच रैखिक सम्मिश्रण

progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);

यह वह संस्करण है जिससे आप संभवतः सबसे अधिक परिचित हैं।

2. एक लक्ष्य की ओर घातीय आसानी

current = Mathf.Lerp(current, target, sharpnessPerTick);

ध्यान दें कि इस संस्करण में currentमूल्य आउटपुट और इनपुट दोनों के रूप में प्रकट होता है । यह startचर को विस्थापित करता है, इसलिए हम हमेशा उस जगह से शुरू कर रहे हैं जहां से हम आखिरी अपडेट पर गए थे। यह वह है जो Lerpमेमोरी के इस संस्करण को एक फ्रेम से अगले तक देता है। इस गतिमान शुरुआती बिंदु से, हम फिर targetएक sharpnessपैरामीटर द्वारा तय की गई दूरी का एक अंश स्थानांतरित करते हैं ।

यह पैरामीटर अब काफी "गति" नहीं है, क्योंकि हम एक ज़ेनो-जैसे फैशन में लक्ष्य तक पहुंचते हैं । यदि sharpnessPerTickथे 0.5, तो पहले अद्यतन पर हम अपने लक्ष्य से आधे रास्ते पर चले गए। फिर अगले अपडेट पर हम शेष बची हुई आधी दूरी (इसलिए हमारी प्रारंभिक दूरी का एक चौथाई) को स्थानांतरित करेंगे। फिर अगले पर हम फिर से आधा आगे बढ़ेंगे ...

यह एक "घातीय सहजता" प्रदान करता है, जहां लक्ष्य से दूर होने पर गति तेज होती है और धीरे-धीरे धीमी हो जाती है क्योंकि यह asymptotically के पास पहुंचती है (हालांकि अनंत-सटीक संख्याओं के साथ यह अपडेट के किसी भी परिमित संख्या में कभी नहीं पहुंचेगा - हमारे उद्देश्यों के लिए करीब हो जाता है)। यह एक चलती लक्ष्य मान का पीछा करने के लिए, या " एक्सपोनेंशियल मूविंग एवरेज " का उपयोग करके एक शोर इनपुट को चौरसाई करने के लिए बहुत अच्छा है, आमतौर पर sharpnessPerTickजैसे 0.1या बहुत छोटे पैरामीटर का उपयोग करते हुए ।


लेकिन आप सही हैं, आपके द्वारा लिंक किए गए उत्तर में कोई त्रुटि है। यह deltaTimeसही तरीके के लिए सही नहीं है। इस शैली का उपयोग करते समय यह एक बहुत ही सामान्य गलती है Lerp

की पहली शैली Lerpरैखिक है, इसलिए हम गुणा करके गति को समायोजित कर सकते हैं deltaTime:

progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);

लेकिन हमारा घातीय सहजता गैर-रैखिक है , इसलिए हमारे sharpnessपैरामीटर को केवल गुणा deltaTimeकरना सही समय सुधार नहीं देगा। यदि हमारे फ्रैमरेट में उतार-चढ़ाव होता है, या 30 से 60 तक लगातार चला जाता है, तो यह आंदोलन में एक निर्णायक के रूप में दिखाई देगा।

इसके बजाय हमें अपने घातीय आसानी के लिए एक घातीय सुधार लागू करने की आवश्यकता है:

blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);

यहाँ referenceFramerateसिर्फ एक स्थिरांक है जैसे 30इकाइयों sharpnessको उसी के लिए रखना जैसे हम समय के लिए सही करने से पहले उपयोग कर रहे थे।


उस कोड में एक और तर्कपूर्ण त्रुटि है, जो उपयोग कर रहा है Slerp- गोलाकार रैखिक प्रक्षेप तब उपयोगी होता है जब हम पूरे आंदोलन के माध्यम से रोटेशन की एक बिल्कुल सुसंगत दर चाहते हैं। लेकिन अगर हम किसी भी तरह से एक गैर-रेखीय घातीय आसानी का उपयोग करने जा रहे हैं, तो Lerpयह लगभग अविभाज्य परिणाम देगा और यह सस्ता है। ;) मातृत्व की तुलना में Quaternions lerp बहुत बेहतर है, इसलिए यह आमतौर पर एक सुरक्षित प्रतिस्थापन है।


1

मुझे लगता है कि गायब होने वाली मूल अवधारणा इस परिदृश्य में होगी ए निश्चित नहीं है। A को प्रत्येक चरण के साथ अद्यतन किया जाता है, हालांकि समय-समय पर प्रक्षेप के साथ बहुत अधिक है कि Time.deltaTime है।

तो, A प्रत्येक चरण के साथ B के करीब होने के साथ, प्रत्येक Lerp / Slerp कॉल के साथ प्रक्षेप का कुल स्थान बदलता है। वास्तविक गणित किए बिना, मुझे संदेह होगा कि प्रभाव आपके स्मूथस्टेप ग्राफ के समान नहीं है, लेकिन एक मंदी के करीब होने का एक सस्ता तरीका है क्योंकि ए बी के करीब जाता है।

इसके अलावा, इसका उपयोग अक्सर किया जाता है क्योंकि बी या तो स्थिर नहीं हो सकता है। एक खिलाड़ी के बाद विशिष्ट मामला एक कैमरा हो सकता है। आप झटके से बचना चाहते हैं, कैमरा जंप या किसी स्थान पर घूमने के लिए।


1

आप सही हैं, विधि और राशि के Quaternion Slerp(Quaternion a, Quaternion b, float t)बीच अंतर करती है । लेकिन पहला मूल्य देखें, यह प्रारंभ मूल्य नहीं है।abt

यहां विधि को दिया गया पहला मान वर्तमान वस्तु रोटेशन है transform.rotation। इसलिए प्रत्येक फ्रेम के लिए यह वर्तमान रोटेशन और _lookRotationराशि द्वारा लक्ष्य रोटेशन के बीच अंतर करता है Time.deltaTime

यही कारण है कि यह एक चिकनी रोटेशन का उत्पादन करता है।


2
अब मैं बेवकूफ की तरह महसूस करता
हूं

@AzulShiva चिंता न करें यह हर किसी के लिए होता है;)
लुडोविक फेल्ट्ज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.