1. 程式人生 > >(Android)Vuforia Native版本與jpct-ae結合

(Android)Vuforia Native版本與jpct-ae結合

AR/VR技術交流群 129340649

Qualcomm的Vuforia引擎是最強大的增強現實引擎之一。將它和JPCT-AE結合是一個很好的想法,它可以讓你的Android裝置實現讓人驚奇的AR場景。

其中在Android端和iOS端的Vuforia Native版本是需要進行NDK程式設計,並且對於3D渲染這塊做的不是很好,它採用的方案是將模型檔案轉換成.h或者java檔案,將其中的點線面等資料儲存,然後使用OpenGL讀取並繪製。這種方案的弊端有很多,比如模型檔案過大,不適合多貼圖,渲染效果不好等等。將Vuforia與3D渲染引擎在原生程式碼中融合一直是我想做的事情,這篇稿子主要講述Android端的Vuforia原生程式碼與jpct-AE得融合。

jpct-AE是一款免費的Android 系統下的3D渲染引擎。他是一款基於OpenGL技術開發的3D圖形引擎(PC環境為標準OpenGL,Android為OpenGL ES), 以Java語言為基礎的,擁有功能強大的Java 3D解決方案。

Vuforia和jpct都是使用OpenGL es中的GLSurfaceView進行繪製顯示 的。開啟ImageTargetsRenderer.java檔案,這個是OpenGL渲染類,我們需要把Jpct的程式碼插入進來。

首先,為ImageTargetsRenderer建立一個建構函式。在這個建構函式裡,將Activity作為引數傳遞進來,也在這個建構函式中初始化場景。


public ImageTargetsRenderer(ImageTargets activity){
        this.mActivity = activity;
        world = new World();
	world.setAmbientLight(20, 20, 20);

	sun = new Light(world);
	sun.setIntensity(250, 250, 250);

	// Create a texture out of the icon...:-)
	Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(mActivity.getResources().getDrawable(R.drawable.ic_launcher)), 64, 64));
	TextureManager.getInstance().addTexture("texture", texture);

	cube = Primitives.getCube(10);
	cube.calcTextureWrapSpherical();
	cube.setTexture("texture");
	cube.strip();
	cube.build();

	world.addObject(cube);

        cam = world.getCamera();
        cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
        cam.lookAt(cube.getTransformedCenter());

	SimpleVector sv = new SimpleVector();
	sv.set(cube.getTransformedCenter());
	sv.y -= 100;
	sv.z -= 100;
	sun.setPosition(sv);
	MemoryHelper.compact();

    }

然後在ImageTargets.java檔案中,修改ImageTargetRenderer的初始化將activity作為引數傳遞進結構體中。

        mRenderer = new ImageTargetsRenderer(this);
        mRenderer.mActivity = this;
        mGlView.setRenderer(mRenderer);

然後在ImageTargetRenderer類中的onSurfaceChanged方法中,把jpctframebuffer的初始化程式碼插入進來,同樣也是從jpct的例子中得來。

if (fb != null) {
     fb.dispose();
}
fb = new FrameBuffer(width, height);

好了,我們已經初始化場景和framebuffer,下一步就要使用jpct來繪製模型。(我們使用jpct的主要目的就是希望用他來繪製我們的虛擬場景)。需要在onDrawFrame()方法中完成。將下面的方法插入進onDrawFrame()方法中。

world.renderScene(fb);
world.draw(fb);
fb.display(); 

這裡不需要fb.clear()。因為QCAR的本地openGL程式碼已經清除了framebuffer.如果這裡再清除一次,就會清除攝像頭拍攝的真實場景。

這時,如果你開啟APP,會在真實場景上面看到一個矩形。(當然這個矩形目前還沒有完成註冊,還需要我們計算的攝像頭矩陣)。

這裡我們需要修改原生代碼,即jni檔案中的程式碼。開啟ImageTargets.cpp檔案,到JNIEXPORT void JNICALL Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargetsRenderer_renderFrame(JNIEnv *, jobject)這個方法的實現下。


這裡是標準的OpenGL的程式碼。逐幀迴圈執行的執行緒。在Android中這是一個單獨的執行緒。在這個方法裡,framebuffer被清空,計算得到投影矩陣和模型檢視矩陣,並且繪製模型。

這裡不需要使用Vuforia渲染,渲染的任務交給jPCT-AE即可。刪除一些不必要的語句,最後如下:

{
    // Clear color and depth buffer 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Get the state from QCAR and mark the beginning of a rendering section
    QCAR::State state = QCAR::Renderer::getInstance().begin();
    // Explicitly render the Video Background
    QCAR::Renderer::getInstance().drawVideoBackground();
    // Did we find any trackables this frame?
    for(int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++)
    {
        // Get the trackable:
        const QCAR::TrackableResult* result = state.getTrackableResult(tIdx);
        const QCAR::Trackable& trackable = result->getTrackable();
        QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(result->getPose());        
    }
    QCAR::Renderer::getInstance().end();
}

使用NDK進行編譯。接下來我們需要將native層計算得出的模型檢視矩陣和投影矩陣傳遞到java層。建立瞭如下方法接受從native層傳遞進來的矩陣,它是一個4X4的矩陣。

public void updateModelviewMatrix(float mat[]) {
    modelViewMat = mat;
}

由於矩陣(模型檢視矩陣和投影矩陣)是每幀都需要計算和檢測的,所以這個方法也應該迴圈呼叫。所以需要在native層中的renderFrame方法中呼叫該方法。這裡用到Jni程式設計的一些規則,不清楚的同學可以去參考相關資料。

jclass activityClass = env->GetObjectClass(obj); //獲取Activity
jmethodID updateMatrixMethod = env->GetMethodID(activityClass, "updateModelviewMatrix", "([F)V");

接下來就需要將估算的矩陣結果傳遞到java層。

	jfloatArray modelviewArray = env->NewFloatArray(16);
	for(int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++)
	{
		// Get the trackable:
		const QCAR::TrackableResult* result = state.getTrackableResult(tIdx);
		const QCAR::Trackable& trackable = result->getTrackable();
		QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(result->getPose());

		SampleUtils::rotatePoseMatrix(90.0f, 1.0f, 0, 0, &modelViewMatrix.data[0]);

		QCAR::Matrix44F inverseMV = SampleMath::Matrix44FInverse(modelViewMatrix);
		QCAR::Matrix44F invTranspMV = SampleMath::Matrix44FTranspose(inverseMV);

		// 將資料傳遞到java層
		env->SetFloatArrayRegion(modelviewArray, 0, 16, invTranspMV.data);
		env->CallVoidMethod(obj, updateMatrixMethod, modelviewArray);
	}


	// hide the objects when the targets are not detected
	if (state.getNumTrackableResults() == 0) {
		float m [] = {
				1,0,0,0,
				0,1,0,0,
				0,0,1,0,
				0,0,-10000,1
		};
		env->SetFloatArrayRegion(modelviewArray, 0, 16, m);
		env->CallVoidMethod(obj, updateMatrixMethod, modelviewArray);
	}
	env->DeleteLocalRef(modelviewArray);

這裡對modelViewMatrix矩陣在X軸上進行旋轉180°,因為JPCT的座標系繞X軸旋轉了180°。使用SetFloatArrayRegion將矩陣結果設定成浮點陣列型別。最後通過native層呼叫java層方法updateMatrix將結果向Java層傳遞。

好的,接下來回到Java層,將剛剛從Native層傳遞過來的資料給Camera。
public void updateCamera() {
		if (modelViewMat != null) {
			float[] m = modelViewMat;


			final SimpleVector camUp;
			if (mActivity.isPortrait()) {
				camUp = new SimpleVector(-m[0], -m[1], -m[2]);
			} else {
				camUp = new SimpleVector(-m[4], -m[5], -m[6]);
			}
			
			final SimpleVector camDirection = new SimpleVector(m[8], m[9], m[10]);
			final SimpleVector camPosition = new SimpleVector(m[12], m[13], m[14]);
			
			cam.setOrientation(camDirection, camUp);
			cam.setPosition(camPosition);
			
			cam.setFOV(fov);
			cam.setYFOV(fovy);
		}
	}
位置和旋轉組成攝像頭的稱作攝像頭的位姿,然而除了這個之外,攝像頭所需要設定的引數遠不止這些,還有FOV,簡稱視場,他也會影響攝像頭所看到的場景,關於更詳細的資訊請看:http://en.wikipedia.org/wiki/Field_of_view

由於不同的裝置具有不同的FOV。這個就和攝像頭的標定有關了。在QCAR庫中提供了計算的函式,包括水平和垂直的FOV,看下面的程式碼。

這裡使用QCAR攝像頭標定的方法,獲取攝像頭的內部物理引數,這個在關於3D模型AR應用中也是必須的。

const QCAR::CameraCalibration& cameraCalibration = QCAR::CameraDevice::getInstance().getCameraCalibration();
QCAR::Vec2F size = cameraCalibration.getSize();
QCAR::Vec2F focalLength = cameraCalibration.getFocalLength();
float fovyRadians = 2 * atan(0.5f * size.data[1] / focalLength.data[1]);
float fovRadians = 2 * atan(0.5f * size.data[0] / focalLength.data[0]);

然後在通過對應的方法將資料上傳:

Java層:

	public void setFov(float fov) {
		this.fov = fov;
	}
	
	public void setFovy(float fovy) {
		this.fovy = fovy;
	}

Native層:
jmethodID fovMethod = env->GetMethodID(activityClass, "setFov", "(F)V");
jmethodID fovyMethod = env->GetMethodID(activityClass, "setFovy", "(F)V");

env->CallVoidMethod(obj, fovMethod, fovRadians);
env->CallVoidMethod(obj, fovyMethod, fovyRadians);

寫到這裡,基本上整合工作就做完了,可以執行試試效果。


相關推薦

AndroidVuforia Native版本jpct-ae結合

AR/VR技術交流群 129340649 Qualcomm的Vuforia引擎是最強大的增強現實引擎之一。將它和JPCT-AE結合是一個很好的想法,它可以讓你的Android裝置實現讓人驚奇的AR場景。 其中在Android端和iOS端的Vuforia Native版本

Androidreact-native更改狀態列文字和圖示顏色

react-native中給的StatusBar元件中並不能更改Android的文字顏色,下面是通過Android原生進行更改的,但是並不適用於所有的Android手機。 1、初始化一個專案做測試。用Android Studio開啟專案的android部分。 在java檔案

React-Native 原生的3種互動通訊Android

前言 最近到新公司,採用React-Native開發App。在某些效能方面有問題或者模組特殊的開發情況,不可避免的需要我們原生開發(Android\IOS)給予前端開發支援。 在為前端書寫模組部分,不可避免的要接觸核心的通訊部分。 大致分為2種情況:

Kubernetes 1.12公佈:Kubelet TLS BootstrapAzure虛擬機器規模集VMSS迎來通用版本

今天,我們非常高興地推出Kubernetes 1.12版本號,這也是我們今年以來公佈的第三個版本號。 此次公佈繼續關注內部改進與功能完好。旨在進一步提升與Kubernetes對接時的穩定性。 這一最新版本號亦在安全性與Azure等關鍵功能上做出增

Kubernetes 1.12公布:Kubelet TLS BootstrapAzure虛擬機規模集VMSS迎來通用版本

node 2018年 ear 撤銷 開源技術 apiserver als 新版本 Helm 版權聲明:本文為博主原創文章,未經博主同意不得轉載。 https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/art

windows下配置React-NativeAndroid開發環境總結

首先配置環境我們需要用到以下工具: node.js react-native-cli Android Studio JDK(1.8以上) SDK python 1.安裝node.js和react-native-cli命令列工具

SpringCloud進擊 | 四淺出:斷路器容錯Hystrix【Finchley版本

1.前言 上一節:SpringCloud進擊 | 三淺出:服務消費者(Feign)【Finchley版本】 斷路器:Hystrix 客戶端,字面上理解,就是斷開一端和另一端之間的鏈路。當某個服務單元發生故障之後,通過斷路器的故障監控,向呼叫方返回一個預留的、可處理的備選響應,即服務降

SpringCloud進擊 | 一淺出:服務註冊發現Eureka【Finchley版本

1.前言 Spring Cloud 已經幫我們實現了服務註冊中心,我們只需要很簡單的幾個步驟就可以完成。關於理論知識,我想大家都已經有不同程度上的瞭解和認識,這裡,我們最後再進行總結。本系列 Spring Cloud 介紹基於 Spring Boot 2.0.5 版本和 Spring C

spring-cloud服務的註冊發現Eureka(Finchley版本)

spring cloud 為開發人員提供了快速構建分散式系統的一些工具,包括配置管理、服務發現、斷路器、路由、微代理、事件匯流排、全域性鎖、決策競選、分散式會話等等。它執行環境簡單,可以在開發人員的電腦上跑。另外說明spring cloud是基於springboot的,所以需要開發中對springb

react-native 啟動頁設定android

使用第三方外掛:react-native-splash-screen 下載地址:https://www.npmjs.com/package/react-native-splash-screen 第一步:安裝下載外掛 1、npm i react-native-splash-screen

二維碼QRcode容量的計算版本

轉載自: https://www.cnblogs.com/feng9exe/p/5995055.html  4.版本資訊:即二維碼的規格,QR碼符號共有40種規格的矩陣(一般為黑白色),從21x21(版本1),到177x177(版本40),每一版本符號比前一版本每邊增加4個模組。

Kubernetes 1.12釋出:Kubelet TLS BootstrapAzure虛擬機器規模集VMSS迎來通用版本

今天,我們很高興地推出Kubernetes 1.12版本,這也是我們今年以來發布的第三個版本!此

react-native-android-unityreact-native加入android原生

 本人是做後端php的,對各類語言和方向都有興趣,多而不精。最近公司專案有一個移動端app,決定採用react-native開發,專案中有這麼個要求,要求react-native中嵌入原生頁面,然後原生頁面嵌入unity,並實現原生和unity之前相互通訊,網路查詢資料後實現

Android Studio使用的那些事AS不同版本安裝注意點

繼上篇遷移整理了 Android Studio使用的那些事(二)AS常見錯誤 這篇將整理記錄Android Studio我在使用更新不同版本時候所遇到要注意的點。Android Studio當時的1.2、1.5 我就沒有記錄了,因為當時AS還不夠成熟問題還很多,雖然下載安裝了

FTS資料庫優化Android原理應用詳解1

在Android的官方開發文件上,有建議在使用文字類的資料庫全文搜尋(full-text search)時,使用FTS優化查詢速度。有關FTS的介紹文章不多,本文調研整理一下有關知識,供在Android上使用FTS之前參考。 1.什麼是FTS? FTS,即full te

Python網路爬蟲:chromdriver.exechrome版本對映及下載連結

前言:最近正在學習Python網路爬蟲,學到selenium,需要用到chrome瀏覽器的驅動,但是網上的很多地址都被牆了,而且沒有準確的驅動和chrome版本的對映,很麻煩。現在我已經解決了這些問題,現在把對映和下載連結分享出來。 (一)檢視chrome

Android二維碼掃描開發:實現思路原理

【 回覆“ 1024 ”,送你一個特別推送 】 現在二維碼已經非常普及了,那麼二維碼的掃描與處理也成為了Android開發中的一個必要技能。網上有很多關於Android中二維碼處理的帖子,大都是在講開源框架zxing用法,然後貼貼程式碼就完了,並沒有一個系統的分析和

React-Native 熱更新嘗試Android

前言:由於蘋果釋出的ios的一些rn的app存在安全問題,主要就是由於一些第三方的熱更新庫導致的,然而訊息一出就鬧得沸沸揚揚的,導致有些人直接認為“學了大半年的rn白學啦~~!!真是哭笑不得。廢話不多說了,馬上進入我們今天的主題吧。“ 因為一直在做androi

Weex元件模組封裝Android

Weex元件Android Studio配置在AndroidManifest.xml中新增網路許可權等許可權。<uses-permission android:name="android.perm

Android基礎:四大元件另一個重要元件Intent的簡單認識

與其他系統應用程式不同,Android應用程式沒有為應用程式提供一個單獨的應用程式入口(如同沒有mian方法)而是為系統依照需求例項化提供了基本的元件,這就是我之後要講到的Android的四大元件和另