接着上一篇说,集成完成之后,你打开项目中Jni目录,你会看到这几个文件
重点是helloar.cc 这个文件,我们看它的代码
void HelloAR::render()
{
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Frame frame = augmenter_.newFrame();
if(view_size[0] > 0){
AR::resizeGL(view_size[0], view_size[1]);
if(camera_ && camera_.isOpened())
view_size[0] = -1;
}
augmenter_.setViewPort(viewport_);
augmenter_.drawVideoBackground();
glViewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]);
for (int i = 0; i < frame.targets().size(); ++i) {
AugmentedTarget::Status status = frame.targets()[i].status();
if (status == AugmentedTarget::kTargetStatusTracked) {
//这里就是说明,已经识别到了,开始绘制方块的地方
Matrix44F projectionMatrix = getProjectionGL(camera_.cameraCalibration(), 0.2f, 500.f);
Matrix44F cameraview = getPoseGL(frame.targets()[i].pose());
ImageTarget target = frame.targets()[i].target().cast_dynamic<ImageTarget>();
renderer.render(projectionMatrix, cameraview, target.size());
}
}
}
helloar.cc中的这个方法就是相当于识别图片的一个方法,那么我们如何在识别成功后,做自己的事情呢?我们需要将其绘制方块的代码去掉,然后在改一些地方(注意,传统JNI调用Java方法,如 env->findClass…. env->getStaticMethodId() 之类的在这里不能使用),我们需要按照接下来的步骤来做。
- 更改MainActivity中的nativeRender()方法,让其返回值是String
public static native String nativeRender();
2.更改helloar.cc文件,Jni方法返回值,需要改为jstring
JNIEXPORT jstring JNICALL JNIFUNCTION_NATIVE(nativeRender(JNIEnv* env, jobject obj));
在下面找到Jni的具体实现方法,改为
JNIEXPORT jstring JNICALL JNIFUNCTION_NATIVE(nativeRender(JNIEnv* env, jobject))
{
return env->NewStringUTF(ar.render());
}
3.更改helloar.cc文件中的HelloAr类中的render()方法,将其返回值改为 const char*
class HelloAR : public AR
{
public:
HelloAR();
virtual void initGL();
virtual void resizeGL(int width, int height);
virtual const char* render();
private:
Vec2I view_size;
Renderer renderer;
};
往下拉,改实现方法
const char* HelloAR::render()
{
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Frame frame = augmenter_.newFrame();
if(view_size[0] > 0){
AR::resizeGL(view_size[0], view_size[1]);
if(camera_ && camera_.isOpened())
view_size[0] = -1;
}
augmenter_.setViewPort(viewport_);
augmenter_.drawVideoBackground();
glViewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]);
const char *p="n";
for (int i = 0; i < frame.targets().size(); ++i) {
AugmentedTarget::Status status = frame.targets()[i].status();
if (status == AugmentedTarget::kTargetStatusTracked) {
const char* c_s= frame.targets()[i].target().name();
return c_s ;
}else
{
return p;
}
}
return p;
}
这里只有一点说明,rame.targets()[i].target().name() 方法,得到的是你json文件配置的name值,如:
当然你也可以rame.targets()[i].target().uid(); 得到uid属性(前提是你json文件配置了这个属性)。然后我return了回去,它会回调Renderer类中的onDrawFrame方法。
4.更改ar.cc文件,ctrl+f找到 render 方法,将其返回值改成 const char*
5.更改ar.hpp文件,ctrl+f找到render方法,将其返回值改成const char*
6.更改 renderer.cc 和 renderer.hpp 文件,同上
7.最后一步更改Renderer类
public class Renderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
ArScannerFragment.nativeInitGL();
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
ArScannerFragment.nativeResizeGL(w, h);
}
//更改这个方法
public void onDrawFrame(GL10 gl) {
String bo = null;
try {
bo = new String(ArScannerFragment.nativeRender().getBytes(),"UTF-8");
if(!"n".equals(bo))
{
//是否正在暂用
if(!isEnable)
{
isEnable = true;
EasyAR.onPause();
mCallBack.scannerFished(bo);
}else
{
//否则不打开
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
- onDrawFrame 这个方法,你可以简单理解为 识别成功后的回调方法,你可以在这里去写你的逻辑,比如,展示些你的模型。
- 之前在MainActivity中,我已经将nativeRender的返回值改为我String,所以这里我要用String去接收其返回值。
额外知识
1. 识别成功后,我想展示一个自己的模型?
说明:
我并不推荐你根据官方的方法去替换模型文件,我们只需要这个EasyAr提供扫描结果,然后将结果传给我们,之后由我们自己处理,比如我想展示一个模型,加载一个网页,一个View之类的。
如何做?
1. 如果你想展示模型,你需要下载jpct-ae库,它是安卓平台下的游戏引擎库,我们用它加载3d模型,我们下载它,然后解压,将其的lib引入到你的项目中。
- 之后进入其代码目录下,找到HelloWord.java文件,复制到你的项目中,之后怎么调用它,就是在你识别成功后,直接调用这个类就行了。
我用了Jpct-ae,但是背景如何透明啊?
// 类似java.awt.*中的Color类
private RGBColor back = new RGBColor(0, 0, 0); //这里指定alpha值为0
private View bottom;
private float touchTurn = 0.0f;
private float touchTurnUp = 0.0f;
// private float touchDown = 0;
//
// private float baseValue = 0;
// private float baseCameraValue = 100;
// private float scale = 0;
private float xpos = -1;
private float ypos = -1;
private Object3D cube = null;// 3d模型对象
// 每秒帧数
private int fps = 0;
// 光照类
private Light sun = null;
private Light moon = null;
private ProgressDialog progressDialog;
protected void onCreate(Bundle savedInstanceState) {
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("加载中,请稍候...");
progressDialog.show();
// Logger类中 jPCT中一个普通的用于打印和存储消息,错误和警告的日志类。
// 每一个JPCT生成的消息将被加入到这个类的队列中
Logger.log("onCreate");
// 如果本类对象不为NULL,将从Object中所有属性装入该类
if (master != null) {
copy(master);
}
super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(getApplication());
// 使用自己实现的 EGLConfigChooser,该实现必须在setRenderer(renderer)之前
// 如果没有setEGLConfigChooser方法被调用,则默认情况下,视图将选择一个与当前android.view.Surface兼容至少16位深度缓冲深度EGLConfig。
//然后这里
mGLView.setZOrderOnTop(true);
mGLView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
mGLView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
这样,你就完成了展示自己的模型了(模型的更改,在这个类中,通过R.raw指定,你可以替换为自己的模型)。
下一篇我们说,如何动态的加载识别图片,而不是固定。