系列教程:
vuforia android 教程(1)
https://www.jianshu.com/p/37b158175b04
vuforia android 教程(2)
https://www.jianshu.com/p/2d70974857b8
vuforia android 教程(4)
https://www.jianshu.com/p/281a1e31a73c
在上一篇文章中,我们了解了如何替换识别图片
那么接下来,我们来替换 vuforia 模型
1. 准备工作
- .obj格式的模型
- 下载安装ActivePerl (下载连接: http://rj.baidu.com/soft/detail/14792.html?ald)
- 下载obj2opengl (下载连接: https://github.com/HBehrens/obj2opengl)
- 将model.obj 和obj2opengl文件放到C\Perl\bin目录下
- 然后在命令行中执行perl obj2opengl.p1 model.obj
- 执行以后会生成model.h
2. 替换方式
其实替换两种方式,一个是像demo一样直接把数据放进去,另一个是通过.h文件来加载出来
2.1直接放的方式,可以参考teapot
/*===============================================================================
Copyright (c) 2016 PTC Inc. All Rights Reserved.
Copyright (c) 2012-2014 Qualcomm Connected Experiences, Inc. All Rights Reserved.
Vuforia is a trademark of PTC Inc., registered in the United States and other
countries.
===============================================================================*/
package com.vuforia.samples.SampleApplication.utils;
import java.nio.Buffer;
public class Teapot extends MeshObject
{
private Buffer mVertBuff;
private Buffer mTexCoordBuff;
private Buffer mNormBuff;
private Buffer mIndBuff;
private int indicesNumber = 0;
private int verticesNumber = 0;
public Teapot()
{
setVerts();
setTexCoords();
setNorms();
setIndices();
}
private void setVerts()
{
double[] TEAPOT_VERTS = { 11.222200, 0.110300, .......};
mVertBuff = fillBuffer(TEAPOT_VERTS);
verticesNumber = TEAPOT_VERTS.length / 3;
}
private void setTexCoords()
{
double[] TEAPOT_TEX_COORDS = { 0.608828, 0.354913,.... };
mTexCoordBuff = fillBuffer(TEAPOT_TEX_COORDS);
}
private void setNorms()
{
double[] TEAPOT_NORMS = { -0.964496, 0.067011,.....};
mNormBuff = fillBuffer(TEAPOT_NORMS);
}
private void setIndices()
{
short[] TEAPOT_INDICES = { 0, 1, 2, 2, 3.....};
mIndBuff = fillBuffer(TEAPOT_INDICES);
indicesNumber = TEAPOT_INDICES.length;
}
public int getNumObjectIndex()
{
return indicesNumber;
}
@Override
public int getNumObjectVertex()
{
return verticesNumber;
}
@Override
public Buffer getBuffer(BUFFER_TYPE bufferType)
{
Buffer result = null;
switch (bufferType)
{
case BUFFER_TYPE_VERTEX:
result = mVertBuff;
break;
case BUFFER_TYPE_TEXTURE_COORD:
result = mTexCoordBuff;
break;
case BUFFER_TYPE_NORMALS:
result = mNormBuff;
break;
case BUFFER_TYPE_INDICES:
result = mIndBuff;
default:
break;
}
return result;
}
}
2.2文件读取
- 先把model.h文件中modelVerts , modelNormals , modelTexCoords,单独提取出来,放入三个.txt文件中
- 每个文件的结构都是复制出来的数据
- 然后放入assets文件里
- 最后就是写文件读取,我这里写了一个,大家可以参考一下
package com.vuforia.samples.SampleApplication.utils;
import android.content.res.AssetManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.Buffer;
/**
* Created by Admin on 2017/11/21.
*/
public class TestModel extends MeshObject {
private static final String TAG="modelTest";
private Buffer mVertBuff;//顶点
private Buffer mTexCoordBuff;//纹理坐标
private Buffer mNormBuff;//normal
private int verticesNumber = 0;
private AssetManager assetManager;
public TestModel(AssetManager inputassetManager){
this.assetManager = inputassetManager;
setVerts();
setTexCoords();
setNorms();
}
double[] model_VERTS;
double[] model_TEX_COORDS;
double[] model_NORMS;
InputStream inputFile = null;
private int loadVertsFromModel(String fileName) throws IOException {
try{
inputFile = assetManager.open(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputFile));
String line = reader.readLine();
int floatsToRead = 99519;
model_VERTS = new double[3*floatsToRead];
for(int i=0;i<floatsToRead;i++){
String curline = reader.readLine();
if(curline.indexOf('/')>=0){
i--;
continue;
}
// 将一行分成3个数据
String floatStrs[] = curline.split(",");
model_VERTS[3 * i] = Float.parseFloat(floatStrs[0]);
model_VERTS[3 * i + 1] = Float.parseFloat(floatStrs[1]);
model_VERTS[3 * i + 2] = Float.parseFloat(floatStrs[2]);
}
return floatsToRead;
} finally {
if(inputFile !=null){
inputFile.close();
}
}
}
private int loadTexCoordsFromModel(String fileName)
throws IOException
{
try
{
inputFile = assetManager.open(fileName);
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputFile));
String line = reader.readLine();
int floatsToRead = 99519;
model_TEX_COORDS = new double[2*floatsToRead];
for (int i = 0; i < floatsToRead; i++)
{
String curline = reader.readLine();
if( curline.indexOf('/') >= 0 ){
i--;
continue;
}
//将一行分成两个数据
String floatStrs[] = curline.split(",");
model_TEX_COORDS[2*i] = Float.parseFloat("".equals(floatStrs[0].replaceAll(" ","")) ? "0" : floatStrs[0]);
model_TEX_COORDS[2*i+1] = Float.parseFloat("".equals(floatStrs[1].replaceAll(" ","")) ? "0" : floatStrs[1]);
}
return floatsToRead;
} finally
{
if (inputFile != null)
inputFile.close();
}
}
private int loadNormsFromModel(String fileName)
throws IOException
{
try
{
inputFile = assetManager.open(fileName);
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputFile));
String line = reader.readLine();
int floatsToRead = 99519;
model_NORMS = new double[3*floatsToRead];
for (int i = 0; i < floatsToRead; i++)
{
String curline = reader.readLine();
if( curline.indexOf('/') >= 0 ){
i--;
continue;
}
//将一行分成三个数据
String floatStrs[] = curline.split(",");
model_NORMS[3*i] = Float.parseFloat(floatStrs[0]);
model_NORMS[3*i+1] = Float.parseFloat(floatStrs[1]);
model_NORMS[3*i+2] = Float.parseFloat(floatStrs[2]);
}
return floatsToRead;
} finally
{
if (inputFile != null)
inputFile.close();
}
}
private void setVerts(){
int num = 0;
try{
num = loadVertsFromModel("ImageTargets/model/verts.txt");
} catch(IOException e){
e.printStackTrace();
}
mVertBuff = fillBuffer(model_VERTS);
verticesNumber = num;
}
private void setTexCoords()
{
int num = 0;
try {
num = loadTexCoordsFromModel("ImageTargets/model/texcoords.txt");
} catch (IOException e) {
e.printStackTrace();
}
mTexCoordBuff = fillBuffer(model_TEX_COORDS);
}
private void setNorms()
{
int num = 0;
try {
num = loadNormsFromModel("ImageTargets/model/norms.txt");
} catch (IOException e) {
e.printStackTrace();
}
mNormBuff = fillBuffer(model_NORMS);
}
public int getNumObjectIndex()
{
return 0;
}
@Override
public int getNumObjectVertex()
{
return verticesNumber;
}
@Override
public Buffer getBuffer(BUFFER_TYPE bufferType)
{
Buffer result = null;
switch (bufferType)
{
case BUFFER_TYPE_VERTEX:
result = mVertBuff;
break;
case BUFFER_TYPE_TEXTURE_COORD:
result = mTexCoordBuff;
break;
case BUFFER_TYPE_NORMALS:
result = mNormBuff;
break;
default:
break;
}
return result;
}
}
注意 : int floatsToRead = 99519; 这个值是model.h里面的值
3. 开始替换
3.1 修改ImageTargetRenderer.java的文件
- 首先新建一个TestModel 变量
private TestModel testModel;
- 然后在initRendering方法给testmodel初始化
// Function for initializing the renderer.
private void initRendering()
{
testModel = new TestModel(mActivity.getResources().getAssets());
GLES20.glClearColor(0.0f, 0.0f, 0.0f, Vuforia.requiresAlpha() ? 0.0f
: 1.0f);
for (Texture t : mTextures)
{
GLES20.glGenTextures(1, t.mTextureID, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, t.mTextureID[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
t.mWidth, t.mHeight, 0, GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE, t.mData);
}
shaderProgramID = SampleUtils.createProgramFromShaderSrc(
CubeShaders.CUBE_MESH_VERTEX_SHADER,
CubeShaders.CUBE_MESH_FRAGMENT_SHADER);
vertexHandle = GLES20.glGetAttribLocation(shaderProgramID,
"vertexPosition");
textureCoordHandle = GLES20.glGetAttribLocation(shaderProgramID,
"vertexTexCoord");
mvpMatrixHandle = GLES20.glGetUniformLocation(shaderProgramID,
"modelViewProjectionMatrix");
texSampler2DHandle = GLES20.glGetUniformLocation(shaderProgramID,
"texSampler2D");
if(!mModelIsLoaded) {
mTeapot = new Teapot();
try {
mBuildingsModel = new SampleApplication3DModel();
mBuildingsModel.loadModel(mActivity.getResources().getAssets(),
"ImageTargets/Buildings.txt");
mModelIsLoaded = true;
} catch (IOException e) {
Log.e(LOGTAG, "Unable to load buildings");
}
// Hide the Loading Dialog
mActivity.loadingDialogHandler
.sendEmptyMessage(LoadingDialogHandler.HIDE_LOADING_DIALOG);
}
}
- 接着是在renderFrame方法加载进来
// The render function called from SampleAppRendering by using RenderingPrimitives views.
// The state is owned by SampleAppRenderer which is controlling it's lifecycle.
// State should not be cached outside this method.
public void renderFrame(State state, float[] projectionMatrix)
{
.....
.....
if (!mActivity.isExtendedTrackingActive()) {
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT,
false, 0, testModel.getVertices());
//false, 0, mTeapot.getVertices());
GLES20.glVertexAttribPointer(textureCoordHandle, 2,
GLES20.GL_FLOAT, false, 0, testModel.getTexCoords());
//GLES20.GL_FLOAT, false, 0, mTeapot.getTexCoords());
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glEnableVertexAttribArray(textureCoordHandle);
// activate texture 0, bind it, and pass to shader
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,
mTextures.get(textureIndex).mTextureID[0]);
GLES20.glUniform1i(texSampler2DHandle, 0);
// pass the model view matrix to the shader
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false,
modelViewProjection, 0);
// finally draw the teapot
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0,
testModel.getNumObjectVertex());
//GLES20.glDrawElements(GLES20.GL_TRIANGLES,
//mTeapot.getNumObjectIndex(), GLES20.GL_UNSIGNED_SHORT,
//mTeapot.getIndices());
// disable the enabled arrays
GLES20.glDisableVertexAttribArray(vertexHandle);
GLES20.glDisableVertexAttribArray(textureCoordHandle);
} else {
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT,
false, 0, testModel.getVertices());
//false, 0, mBuildingsModel.getVertices());
GLES20.glVertexAttribPointer(textureCoordHandle, 2,
GLES20.GL_FLOAT, false, 0, testModel.getTexCoords());
//GLES20.GL_FLOAT, false, 0, mBuildingsModel.getTexCoords());
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glEnableVertexAttribArray(textureCoordHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,
mTextures.get(3).mTextureID[0]);
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false,
modelViewProjection, 0);
GLES20.glUniform1i(texSampler2DHandle, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0,
testModel.getNumObjectVertex());
//mBuildingsModel.getNumObjectVertex());
SampleUtils.checkGLError("Renderer DrawBuildings");
}
SampleUtils.checkGLError("Render Frame");
}
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
}
3.2替换贴图 , 修改ImageTargets.java的代码
- 修改贴图loadTextures方法
// We want to load specific textures from the APK, which we will later use
// for rendering.
private void loadTextures()
{
mTextures.add(Texture.loadTextureFromApk("testmodel.jpg",
getAssets()));
// mTextures.add(Texture.loadTextureFromApk("TextureTeapotBrass.png",
// getAssets()));;
/* mTextures.add(Texture.loadTextureFromApk("001.jpg",
getAssets()));;*/
// mTextures.add(Texture.loadTextureFromApk("TextureTeapotBrass.png",
// getAssets()));;
//
// mTextures.add(Texture.loadTextureFromApk("TextureTeapotBlue.png",
// getAssets()));
// mTextures.add(Texture.loadTextureFromApk("TextureTeapotRed.png",
// getAssets()));
mTextures.add(Texture.loadTextureFromApk("ImageTargets/Buildings.jpeg",
getAssets()));
}
大功告成
参考: