יצירת אפליקציות צפייה ב-360° באיכות גבוהה לסמארטפונים
הפעלה חלקה של וידאו ב-360° במכשירים ניידים היא אתגר טכני משמעותי. נגן ה-AVPlayer הסטנדרטי אינו יכול להציג הקרנות כדוריות; יש צורך בצינור עיבוד Metal מותאם אישית שמפענח פריימים בזמן אמת ללא גמגום. בין אם מדובר בוידאו אקווירקטנגולרי ב-4K/8K או בסיורים וירטואליים אינטראקטיביים עם נקודות חמות, אנו מספקים פתרונות ל-iOS ול-Android שחורגים מתמונות סטטיות פשוטות.
אתגרים טכניים שאנו פותרים
פענוח וידאו ב-360° ב-iOS
וידאו ב-360° בפורמט אקווירקטנגולרי ב-iOS מפוענח באמצעות AVPlayer עם AVPlayerLayer, אך AVPlayerLayer מציג רק בתלת-ממד (2D). להקרנה כדורית יש צורך ב-AVPlayerItemVideoOutput בשילוב עם Metal או SceneKit. לפי התיעוד של Apple, AVPlayerItemVideoOutput.copyPixelBuffer(forItemTime:itemTimeForDisplay:) חוסם את ה-thread הקורא במהלך פענוח הפריים. באייפון 12, פענוח 4K H.265 אורך 8–15 אלפיות השנייה — מחצית מתקציב הפריים ב-60 fps. קריאה אליו ב-callback של CADisplayLink ב-thread הראשי גורמת לגמגום נראה לעין.
הגישה הנכונה: השתמשו ב-CADisplayLink רק כדי להפעיל את מעבר העיבוד של Metal, ובצעו את העתקת CVPixelBuffer ב-DispatchQueue(qos: .userInteractive) נפרד. התוצאה מועברת ל-Metal דרך CVMetalTextureCacheCreateTextureFromImage.
let displayLink = CADisplayLink(target: self, selector: #selector(renderFrame))
displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 60, maximum: 120, preferred: 120)
@objc func renderFrame() {
videoDecodeQueue.async { [weak self] in
guard let pixelBuffer = self?.videoOutput.copyPixelBuffer(
forItemTime: self!.playerItem.currentTime(),
itemTimeForDisplay: nil
) else { return }
self?.metalRenderer.render(pixelBuffer: pixelBuffer)
}
}גישה זו מבטיחה עיבוד חלק גם במכשירים ישנים יותר. עבור Android, פתרון דומה משתמש ב-let displayLink = CADisplayLink(target: self, selector: #selector(renderFrame)) displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 60, maximum: 120, preferred: 120) @objc func renderFrame() { videoDecodeQueue.async { [weak self] in guard let pixelBuffer = self?.videoOutput.copyPixelBuffer( forItemTime: self!.playerItem.currentTime(), itemTimeForDisplay: nil ) else { return } self?.metalRenderer.render(pixelBuffer: pixelBuffer) } } + TextureView עם קריאת OpenGL ברמת המשטח. צינור ה-Metal המותאם אישית שלנו מספק עיבוד חלק פי 2 מה-AVPlayer הסטנדרטי, ופנורמות מרוצפות משתמשות בפי 4 פחות זיכרון מפתרונות של תמונה אחת.
פנורמות מרוצפות לסיורים וירטואליים
לפנורמות סטטיות באיכות גבוהה (מלונות, נדל"ן, מוזיאונים), אנו משתמשים בגישה מרוצפת במקום בתמונה אחת: רמות פירוט מרובות המחולקות לרשת. כשמתקרבים (הקטנת FOV), נטענים אריחים ברזולוציה גבוהה יותר.
הפורמט הסטנדרטי הוא Krpano tile או Marzipano. לעיבוד במובייל אנו משתמשים בצינור Metal/OpenGL ES מותאם אישית או ב-PanoramaGL (Android). אריחים נטענים דרך MediaCodec עם עדיפויות: תחילה רבע הכדור הנראה, ולאחר מכן ארבעת האריחים השכנים (prefetch).
מטמון LRU לאריחים הוא חובה. בלעדיו, ניווט בסיור וירטואלי (10+ מיקומים × 6 פאות קובייה × 4 רמות פירוט) עלול לגרום לזיכרון לגדול ל-800 MB תוך 15 דקות. האופטימיזציה שלנו מפחיתה זאת ל-120 MB.
| פרמטר | פנורמת וידאו | פנורמה מרוצפת |
|---|---|---|
| רזולוציה | מוגבלת על ידי המפענח (4K~8K) | כמעט בלתי מוגבלת (רשת אריחים) |
| ביצועים | תלויים בפענוח חומרה | לינאריים למספר האריחים הנראים |
| אינטראקטיביות | מוגבלת (פנורמה בלבד) | נקודות חמות, מעברים, מדריך קולי |
| גודל דיסק | 500 MB עבור 5 דקות וידאו ב-4K | ~50 MB למיקום (10 אריחים) |
נקודות חמות ואינטראקטיביות
נקודה חמה היא נקודה במרחב הכדורי התלת-ממדי שהופכת, בעת העיבוד, לאלמנט דו-ממדי על המסך (אייקון, tooltip, כפתור מעבר). המרה מקואורדינטות כדוריות (yaw/pitch) לקואורדינטות מסך:
func sphericalToScreen(yaw: Float, pitch: Float, cameraYaw: Float, cameraPitch: Float, fov: Float, screenSize: CGSize) -> CGPoint? {
// Матричное преобразование: сферические → декартовы → проекция камеры → NDC → screen
let direction = SIMD3<Float>(
cos(pitch) * sin(yaw),
sin(pitch),
cos(pitch) * cos(yaw)
)
// ... view matrix × projection matrix → clip space → viewport
}אם URLSession — הנקודה החמה מאחורי המצלמה, דלגו על העיבוד.
אנימציה להופעת נקודה חמה בכניסה ל-FOV — fade-in דרך func sphericalToScreen(yaw: Float, pitch: Float, cameraYaw: Float, cameraPitch: Float, fov: Float, screenSize: CGSize) -> CGPoint? { // Матричное преобразование: сферические → декартовы → проекция камеры → NDC → screen let direction = SIMD3<Float>( cos(pitch) * sin(yaw), sin(pitch), cos(pitch) * cos(yaw) ) // ... view matrix × projection matrix → clip space → viewport } , לא אנימציית SwiftUI (שכבת SwiftUI מעל Metal SCNView מוסיפה 2–3 אלפיות השנייה של מעבר layout לפריים). אנו משתמשים בצינור עיבוד מותאם אישית שממזער תקורה.
גירוסקופ ומצפן
dot(direction, cameraForward) < 0 דרך CABasicAnimation מספק קווטרניון לכיוון המכשיר בתדירות של עד 100 הרץ. אנו ממירים לזוויות אוילר למצלמת הסצנה ומפעילים פילטר Kalman להחלקת רעידות. ללא סינון, סחיפת גירוסקופ במכשירים ישנים (~0.3° לשנייה) עלולה לסטות את "הצפון" ב-15° לאחר 5 דקות.
לצפון באתחול, אנו משתמשים ב-CMDeviceMotion כדי לקשור את ה-yaw הראשוני לצפון מגנטי/אמיתי. זה מבטיח מעקב מדויק בכל מכשירי האייפון והאייפד עם גירוסקופ.
כיצד אנו עובדים
תהליך
- ניתוח ואיסוף דרישות: דיון במטרות, סוגי תוכן, מכשירי יעד.
- תכנון ארכיטקטורה של צינור העיבוד (Metal/OpenGL ES).
- פיתוח מודולי טעינה ומטמון לאריחים.
- אינטגרציה של גירוסקופ, מצפן ובקרות מגע.
- יישום נקודות חמות עם אנימציות ומעברים.
- אופטימיזציית ביצועים למכשירי יעד.
- בדיקות על מכשירים אמיתיים וסימולטורים.
- הכנת תיעוד והוראות.
- תמיכה בפרסום ב-App Store וב-Google Play.
- 3 חודשי תמיכה טכנית לאחר המסירה.
מה כלול
- תיעוד טכני מפורט ודיאגרמת ארכיטקטורה של צינור העיבוד
- גישה למאגר הקוד וכלי הבנייה
- הוראות לאינטגרציית backend ופרסום בחנויות
- 3 חודשי תמיכה טכנית
פרטים נוספים על מטמון אריחים
אנו משתמשים באסטרטגיית מטמון LRU המוגבלת ל-100 MB. כל אריח ממוצע 100–300 KB. בטעינת מיקום חדש, אנו טוענים מראש את כל האריחים של הרמה הנוכחית וכן אריחים ממיקומים סמוכים אם מפת המעברים מגדירה אותם. זה מבטל פיגורים במהלך ניווט.
הערכות לוחות זמנים
| רכיב | לוח זמנים |
|---|---|
| פנורמת וידאו בסיסית עם עיבוד Metal (iOS) | 2–3 שבועות |
| פנורמה מרוצפת עם מטמון (iOS/Android) | 3–5 שבועות |
| סיור וירטואלי עם 10+ מיקומים, נקודות חמות, מדריך קולי | 6–10 שבועות |
| מחזור מלא (עיצוב, פיתוח, בדיקות, פריסה) | 8–14 שבועות |
פרויקט פנורמת וידאו בסיסי מתחיל ב-$5,000; סיור וירטואלי מלא עם 10 מיקומים ונקודות חמות הוא בדרך כלל $15,000–$25,000. העלות נקבעת באופן אישי לאחר ניתוח דרישות. אנו נבחן את הפרויקט שלך תוך 2 ימי עסקים. צור קשר להערכת פרויקט — ננתח את הדרישות שלך ונציע את הפתרון הטוב ביותר. קבל ייעוץ לדיון בפרטים.







