咪免直播高品质美女在线视频互动社区_咪免直播官方版_咪免直播直播视频在线观看免费版下载

您的位置:首頁 > 軟件教程 > 教程 > 僅需6步,實(shí)現(xiàn)虛擬物體在現(xiàn)實(shí)世界的精準(zhǔn)放置

僅需6步,實(shí)現(xiàn)虛擬物體在現(xiàn)實(shí)世界的精準(zhǔn)放置

來源:好特整理 | 時(shí)間:2024-09-27 10:13:49 | 閱讀:82 |  標(biāo)簽: 世界 現(xiàn)實(shí)   | 分享到:

增強(qiáng)現(xiàn)實(shí)(AR)技術(shù)作為一種將數(shù)字信息和現(xiàn)實(shí)場景融合的創(chuàng)新技術(shù),近年來得到了快速發(fā)展,并在多個(gè)應(yīng)用領(lǐng)域展現(xiàn)出其獨(dú)特的魅力。比如在教育行業(yè),老師可以通過虛擬現(xiàn)實(shí)場景生動(dòng)直觀地幫助學(xué)生理解抽象概念;在旅游行業(yè),AR技術(shù)還能虛擬歷史文化場景、虛擬導(dǎo)航等,為游客提供更加沉浸的互動(dòng)體驗(yàn)。 然而,對于應(yīng)用來說,

增強(qiáng)現(xiàn)實(shí)(AR)技術(shù)作為一種將數(shù)字信息和現(xiàn)實(shí)場景融合的創(chuàng)新技術(shù),近年來得到了快速發(fā)展,并在多個(gè)應(yīng)用領(lǐng)域展現(xiàn)出其獨(dú)特的魅力。比如在教育行業(yè),老師可以通過虛擬現(xiàn)實(shí)場景生動(dòng)直觀地幫助學(xué)生理解抽象概念;在旅游行業(yè),AR技術(shù)還能虛擬歷史文化場景、虛擬導(dǎo)航等,為游客提供更加沉浸的互動(dòng)體驗(yàn)。

然而,對于應(yīng)用來說,AR技術(shù)的開發(fā)使用絕非易事,這需要高昂的開發(fā)成本和專業(yè)的技術(shù)人才;诖耍琀armonyOS SDK AR引擎服務(wù) (AR Engine)為廣大應(yīng)用開發(fā)者提供了先進(jìn)的AR技術(shù),解決了開發(fā)成本和技術(shù)門檻的難題。

僅需6步,實(shí)現(xiàn)虛擬物體在現(xiàn)實(shí)世界的精準(zhǔn)放置

在集成AR Engine能力后,開發(fā)者只需6個(gè)開發(fā)步驟,就可以實(shí)現(xiàn)將虛擬物體擺放于現(xiàn)實(shí)世界的平面上,實(shí)現(xiàn)虛擬和現(xiàn)實(shí)的融合,該功能可應(yīng)用于虛擬家具放置、數(shù)字展廳布展等場景,為用戶提供虛實(shí)結(jié)合的新體驗(yàn)。

業(yè)務(wù)流程

僅需6步,實(shí)現(xiàn)虛擬物體在現(xiàn)實(shí)世界的精準(zhǔn)放置

AR擺放實(shí)現(xiàn)的業(yè)務(wù)流程主要分為打開應(yīng)用、識別平面并展示和放置虛擬物體三個(gè)部分。

第一部分是用戶打開應(yīng)用,應(yīng)用需要向用戶申請相機(jī)權(quán)限。如果用戶未同意授權(quán),則無法使用該功能。

第二部分中,AR Engine識別平面并展示。包括完成AR Engine初始化,更新ARFrame對象、獲取平面、繪制平面并顯示預(yù)覽畫面等步驟。

第三部分為放置虛擬物體。即用戶點(diǎn)擊屏幕,通過碰撞檢測獲取現(xiàn)實(shí)環(huán)境中的興趣點(diǎn),并在興趣點(diǎn)上創(chuàng)建錨點(diǎn),最終實(shí)現(xiàn)在錨點(diǎn)位置繪制虛擬物體,并將虛擬物體顯示在預(yù)覽畫面上。

開發(fā)步驟

在實(shí)現(xiàn)AR物體擺放的具體開發(fā)步驟之前,開發(fā)者需要先創(chuàng)建Native C++工程,聲明ArkTs接口,并申請以下權(quán)限授權(quán)。

僅需6步,實(shí)現(xiàn)虛擬物體在現(xiàn)實(shí)世界的精準(zhǔn)放置

1.創(chuàng)建UI界面

在做好準(zhǔn)備工作后,需要?jiǎng)?chuàng)建一個(gè)UI界面,用于顯示相機(jī)預(yù)覽畫面,并定時(shí)觸發(fā)每一幀繪制。

import { Logger } from '../utils/Logger';
import arEngineDemo from 'libentry.so';
import { resourceManager } from '@kit.LocalizationKit';
import { display } from '@kit.ArkUI';

[@Entry](https://my.oschina.net/u/4127701)
[@Component](https://my.oschina.net/u/3907912)
struct ArWorld {
  private xcomponentId = 'ArWorld';
  private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All });
  private resMgr: resourceManager.ResourceManager = getContext(this).resourceManager;
  private interval: number = -1;
  private isUpdate: boolean = true;

  aboutToAppear() {
    Logger.debug('aboutToAppear ' + this.xcomponentId);
    arEngineDemo.init(this.resMgr);
    arEngineDemo.start(this.xcomponentId);
    display.on("foldStatusChange", (foldStatus: display.FoldStatus) => {
      Logger.info('foldStatusChange display on ' + foldStatus);
      if (foldStatus === display.FoldStatus.FOLD_STATUS_EXPANDED
        || foldStatus === display.FoldStatus.FOLD_STATUS_FOLDED) {
        arEngineDemo.stop(this.xcomponentId);
        arEngineDemo.init(this.resMgr);
        // 調(diào)用Native的start接口,創(chuàng)建ARSession。
        arEngineDemo.start(this.xcomponentId);
        arEngineDemo.show(this.xcomponentId);
      }
    })
  }

  aboutToDisappear() {
    Logger.debug('aboutToDisappear ' + this.xcomponentId);
    arEngineDemo.stop(this.xcomponentId);
  }

  onPageShow() {
   this.isUpdate = true;
    Logger.debug('onPageShow ' + this.xcomponentId);
    arEngineDemo.show(this.xcomponentId);
  }

  onPageHide() {
    Logger.debug('onPageHide ' + this.xcomponentId);
    this.isUpdate = false;
    arEngineDemo.hide(this.xcomponentId);
  }

  build() {
    Column() {
      XComponent({ id: this.xcomponentId, type: 'surface', libraryname: 'entry' })
        .onLoad(() => {
          Logger.debug('XComponent onLoad ' + this.xcomponentId);
          this.interval = setInterval(() => {
            if (this.isUpdate) {
              // 調(diào)用Native的update,更新AR Engine每一幀的計(jì)算結(jié)果
              arEngineDemo.update(this.xcomponentId);
            }
          }, 33); // 控制幀率為30fps(每33毫秒刷新一幀)。
        })
        .width('100%');
        .height('100%');
        .onDestroy(() => {
          Logger.debug('XComponent onDestroy ' + this.xcomponentId);
          clearInterval(this.interval);
        })
        .backgroundColor(Color.White);
    }
    .justifyContent(FlexAlign.SpaceAround);
    .alignItems(HorizontalAlign.Center);
    .backgroundColor(Color.White);
    .borderRadius(24);
    .width('100%');
    .height('100%');
  }
}

2.引入AR Engine

創(chuàng)建完UI界面后,引入AR Engine頭文件,并編寫CMakeLists.txt。

#include "ar/ar_engine_core.h" 

find_library(
    # Sets the name of the path variable.
    arengine-lib
    # Specifies the name of the NDK library that
    # you want CMake to locate.
    libarengine_ndk.z.so
)

target_link_libraries(entry PUBLIC
    ${arengine-lib}
)

3.創(chuàng)建AR場景

首先,配置AR會(huì)話及預(yù)覽尺寸。

// 【可選】創(chuàng)建一個(gè)擁有合理默認(rèn)配置的配置對象。
AREngine_ARConfig *arConfig = nullptr;
HMS_AREngine_ARConfig_Create(arSession, &arConfig);
// 【可選】配置AREngine_ARSession會(huì)話。
HMS_AREngine_ARSession_Configure(arSession, arConfig);
// 【可選】釋放指定的配置對象的內(nèi)存空間。
HMS_AREngine_ARConfig_Destroy(arConfig);

// 創(chuàng)建一個(gè)新的AREngine_ARFrame對象。
HMS_AREngine_ARFrame_Create(arSession, &arFrame);
// 預(yù)覽區(qū)域的實(shí)際寬高,如使用xcomponent組件顯示,則該寬和高是xcomponent的寬和高,如果不一致,會(huì)導(dǎo)致顯示相機(jī)預(yù)覽出錯(cuò)。
int32_t width = 1440;
int32_t height = 1080;
// 設(shè)置顯示的寬和高(以像素為單位)。
HMS_AREngine_ARSession_SetDisplayGeometry(arSession, displayRotation, width, height);

通過openGL接口獲取紋理ID。

//通過openGL接口獲取紋理ID.
GLuint textureId = 0;
glGenTextures(1, &textureId);

設(shè)置openGL紋理,存儲(chǔ)相機(jī)預(yù)覽流數(shù)據(jù)。

// 設(shè)置可用于存儲(chǔ)相機(jī)預(yù)覽流數(shù)據(jù)的openGL紋理。
HMS_AREngine_ARSession_SetCameraGLTexture(arSession, textureId );

4.獲取平面

調(diào)用HMS_AREngine_ARSession_Update函數(shù)更新當(dāng)前AREngine_ARFrame對象。

// 獲取幀數(shù)據(jù)AREngine_ARFrame。
HMS_AREngine_ARSession_Update(arSession, arFrame);

獲取相機(jī)的視圖矩陣和相機(jī)的投影矩陣,用于后續(xù)繪制。

// 根據(jù)AREngine_ARFrame對象可以獲取相機(jī)對象AREngine_ARCamera。
AREngine_ARCamera *arCamera = nullptr;
HMS_AREngine_ARFrame_AcquireCamera(arSession, arFrame, &arCamera);
// 獲取最新幀中相機(jī)的視圖矩陣。
HMS_AREngine_ARCamera_GetViewMatrix(arSession, arCamera, glm::value_ptr(*viewMat), 16);
// 獲取用于在相機(jī)圖像上層渲染虛擬內(nèi)容的投影矩陣,可用于相機(jī)坐標(biāo)系到裁剪坐標(biāo)系轉(zhuǎn)換。Near (0.1) Far (100)。
HMS_AREngine_ARCamera_GetProjectionMatrix(arSession, arCamera, {0.1f, 100.f}, glm::value_ptr(*projectionMat), 16);

調(diào)用HMS_AREngine_ARSession_GetAllTrackables函數(shù)獲取平面列表。

// 獲取當(dāng)前檢測到的平面列表。
AREngine_ARTrackableList *planeList = nullptr;
// 創(chuàng)建一個(gè)可跟蹤對象列表。
HMS_AREngine_ARTrackableList_Create(arSession, &planeList);
// 獲取所有指定類型為ARENGINE_TRACKABLE_PLANE的可跟蹤對像集合。
AREngine_ARTrackableType planeTrackedType = ARENGINE_TRACKABLE_PLANE;
HMS_AREngine_ARSession_GetAllTrackables(arSession, planeTrackedType, planeList);
int32_t planeListSize = 0;
// 獲取此列表中的可跟蹤對象的數(shù)量。
HMS_AREngine_ARTrackableList_GetSize(arSession, planeList, &planeListSize);
mPlaneCount = planeListSize;
for (int i = 0; i < planeListSize; ++i) {
    AREngine_ARTrackable *arTrackable = nullptr;
    // 從可跟蹤列表中獲取指定index的對象。
    HMS_AREngine_ARTrackableList_AcquireItem(arSession, planeList, i, &arTrackable);
    AREngine_ARPlane *arPlane = reinterpret_cast(arTrackable);
    // 獲取當(dāng)前可跟蹤對象的跟蹤狀態(tài)。如果狀態(tài)為:ARENGINE_TRACKING_STATE_TRACKING(可跟蹤狀態(tài))才進(jìn)行繪制。
    AREngine_ARTrackingState outTrackingState;
    HMS_AREngine_ARTrackable_GetTrackingState(arSession, arTrackable, &outTrackingState);
    AREngine_ARPlane *subsumePlane = nullptr;
    // 獲取平面的父平面(一個(gè)平面被另一個(gè)平面合并時(shí),會(huì)產(chǎn)生父平面),如果無父平面返回為NULL。
     HMS_AREngine_ARPlane_AcquireSubsumedBy(arSession, arPlane, &subsumePlane);
if (subsumePlane != nullptr) {
HMS_AREngine_ARTrackable_Release(reinterpret_cast(subsumePlane));
        // 如果當(dāng)前平面有父平面,則當(dāng)前平面不進(jìn)行展示。否則會(huì)出現(xiàn)雙平面。
        continue;
    }
    // 跟蹤狀態(tài)為:ARENGINE_TRACKING_STATE_TRACKING時(shí)才進(jìn)行繪制。
    if (AREngine_ARTrackingState::ARENGINE_TRACKING_STATE_TRACKING != outTrackingState) {
        continue;
    }
    // 進(jìn)行平面繪制。
}
HMS_AREngine_ARTrackableList_Destroy(planeList);
planeList = nullptr;

調(diào)用HMS_AREngine_ARPlane_GetPolygon函數(shù)獲取平面的二維頂點(diǎn)坐標(biāo)數(shù)組,用于繪制平面邊界。

// 獲取檢測到平面的二維頂點(diǎn)數(shù)組大小。
int32_t polygonLength = 0;
HMS_AREngine_ARPlane_GetPolygonSize(session, plane, &polygonLength);

// 獲取檢測到平面的二維頂點(diǎn)數(shù)組,格式為[x1,z1,x2,z2,...]。
const int32_t verticesSize = polygonLength / 2;
std::vector raw_vertices(verticesSize);
HMS_AREngine_ARPlane_GetPolygon(session, plane, glm::value_ptr(raw_vertices.front()), polygonLength);

// 局部坐標(biāo)系頂點(diǎn)坐標(biāo)。
for (int32_t i = 0; i < verticesSize; ++i) {
    vertices.emplace_back(raw_vertices[i].x, raw_vertices[i].y, 0.75f);
}

將平面的二維頂點(diǎn)坐標(biāo)轉(zhuǎn)換到世界坐標(biāo)系,并繪制平面。

// 獲取從平面的局部坐標(biāo)系到世界坐標(biāo)系轉(zhuǎn)換的位姿信息。
AREngine_ARPose *scopedArPose = nullptr;
HMS_AREngine_ARPose_Create(session, nullptr, 0, &scopedArPose);
HMS_AREngine_ARPlane_GetCenterPose(session, plane, scopedArPose);

// 將位姿數(shù)據(jù)轉(zhuǎn)換成4X4的矩陣,outMatrixColMajor4x4為存放數(shù)組,其中的數(shù)據(jù)按照列優(yōu)先存儲(chǔ).
// 該矩陣與局部坐標(biāo)系的坐標(biāo)點(diǎn)做乘法,可以得到局部坐標(biāo)系到世界坐標(biāo)系的轉(zhuǎn)換。
HMS_AREngine_ARPose_GetMatrix(session, scopedArPose, glm::value_ptr(modelMat), 16);
HMS_AREngine_ARPose_Destroy(scopedArPose);

// 構(gòu)筑繪制渲染平面所需的數(shù)據(jù)。
// 生成三角形。
for (int i = 1; i < verticesSize - 1; ++i) {
    triangles.push_back(0);
    triangles.push_back(i);
    triangles.push_back(i + 1);
}
// 生成平面包圍線。
for (int i = 0; i < verticesSize; ++i) {
    lines.push_back(i);
}

5.點(diǎn)擊屏幕

用戶點(diǎn)擊屏幕后,基于點(diǎn)擊事件獲取屏幕坐標(biāo)。

// 添加頭文件:native_interface_xcomponent.h
#include 

float pixeLX= 0.0f;
float pixeLY= 0.0f;
int32_t ret = OH_NativeXComponent_GetTouchEvent(component, window, &mTouchEvent);

if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
    if (mTouchEvent.type == OH_NATIVEXCOMPONENT_DOWN) {
        pixeLX= mTouchEvent.touchPoints[0].x;
    pixeLY= mTouchEvent.touchPoints[0].y;
    } else {
    return;
    }
}

調(diào)用HMS_AREngine_ARFrame_HitTest函數(shù)進(jìn)行碰撞檢測,結(jié)果存放在碰撞檢測結(jié)果列表中。

// 創(chuàng)建一個(gè)命中檢測結(jié)果對象列表,arSession為創(chuàng)建AR場景步驟中創(chuàng)建的會(huì)話對象。
AREngine_ARHitResultList *hitResultList = nullptr;
HMS_AREngine_ARHitResultList_Create(arSession, &hitResultList);

// 獲取命中檢測結(jié)果對象列表,arFrame為創(chuàng)建AR場景步驟中創(chuàng)建的幀對象,pixeLX/pixeLY為屏幕點(diǎn)坐標(biāo)。
HMS_AREngine_ARFrame_HitTest(arSession, arFrame, pixeLX, pixeLY, hitResultList);

6.放置虛擬物體

調(diào)用HMS_AREngine_ARHitResultList_GetItem函數(shù)遍歷碰撞檢測結(jié)果列表,獲取命中的可跟蹤對象。

// 創(chuàng)建命中檢測結(jié)果對象。
AREngine_ARHitResult *arHit = nullptr;
HMS_AREngine_ARHitResult_Create(arSession, &arHit);

// 獲取第一個(gè)命中檢測結(jié)果對象。
HMS_AREngine_ARHitResultList_GetItem(arSession, hitResultList, 0, arHit);

// 獲取被命中的可追蹤對象。
AREngine_ARTrackable *arHitTrackable = nullptr;
HMS_AREngine_ARHitResult_AcquireTrackable(arSession, arHit, &arHitTrackable);

判斷碰撞結(jié)果是否存在于平面內(nèi)部。

AREngine_ARTrackableType ar_trackable_type = ARENGINE_TRACKABLE_INVALID;
HMS_AREngine_ARTrackable_GetType(arSession, arTrackable, &ar_trackable_type)
if (ARENGINE_TRACKABLE_PLANE == ar_trackable_type) {
    AREngine_ARPose *arPose = nullptr;
    HMS_AREngine_ARPose_Create(arSession, nullptr, 0, &arPose);
    HMS_AREngine_ARHitResult_GetHitPose(arSession, arHit, arPose);
    // 判斷位姿是否位于平面的多邊形范圍內(nèi)。0表示不在范圍內(nèi),非0表示在范圍內(nèi)。
    HMS_AREngine_ARPlane_IsPoseInPolygon(mArSession, arPlane, arPose, &inPolygon)
    HMS_AREngine_ARPose_Destroy(arPose);
    if (!inPolygon) {
    // 不在平面內(nèi),就跳過當(dāng)前平面。
    continue;
    }
}

在碰撞結(jié)果位置創(chuàng)建一個(gè)新的錨點(diǎn),并基于此錨點(diǎn)放置虛擬模型。

// 在碰撞命中位置創(chuàng)建一個(gè)新的錨點(diǎn)。
AREngine_ARAnchor *anchor = nullptr;
HMS_AREngine_ARHitResult_AcquireNewAnchor(arSession, arHitResult, &anchor)

// 判斷錨點(diǎn)的可跟蹤狀態(tài)
AREngine_ARTrackingState trackingState = ARENGINE_TRACKING_STATE_STOPPED;
HMS_AREngine_ARAnchor_GetTrackingState(arSession, anchor, &trackingState)
if (trackingState != ARENGINE_TRACKING_STATE_TRACKING) {
    HMS_AREngine_ARAnchor_Release(anchor);
    return;
}

調(diào)用HMS_AREngine_ARAnchor_GetPose函數(shù)獲取錨點(diǎn)位姿,并基于該位姿繪制虛擬模型。

// 獲取錨點(diǎn)的位姿。
AREngine_ARPose *pose = nullptr;
HMS_AREngine_ARPose_Create(arSession, nullptr, 0, &pose);
HMS_AREngine_ARAnchor_GetPose(arSession, anchor, pose);
// 將位姿數(shù)據(jù)轉(zhuǎn)換成4X4的矩陣modelMat。
HMS_AREngine_ARPose_GetMatrix(arSession, pose, glm::value_ptr(modelMat), 16);
HMS_AREngine_ARPose_Destroy(pose);
// 繪制虛擬模型。

了解更多詳情>>

訪問 AR Engine聯(lián)盟官網(wǎng)

獲取 AR Engine開發(fā)指導(dǎo)文檔

小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認(rèn)同期限觀點(diǎn)或證實(shí)其描述。

現(xiàn)實(shí) 0.4.3
現(xiàn)實(shí) 0.4.3
類型:休閑益智  運(yùn)營狀態(tài):正式運(yùn)營  語言: 英文   

游戲攻略

游戲禮包

游戲視頻

游戲下載

游戲活動(dòng)

《現(xiàn)實(shí)》是由開發(fā)商HandprintGames開發(fā)的一款賽博朋克風(fēng)格的休閑跑酷類游戲,在這個(gè)游戲的世界里你可以同

相關(guān)視頻攻略

更多

掃二維碼進(jìn)入好特網(wǎng)手機(jī)版本!

掃二維碼進(jìn)入好特網(wǎng)微信公眾號!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請發(fā)郵件[email protected]

湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2025 haote.com 好特網(wǎng)