Skip to main content
ARShow
ARShow
 首页 » 资源教程 » Vuforia教程

Android | Vuforia 更换模型

2016年09月30日 20:07:0032290

1.获得一个obj模型文件(可以使用3dmax等建模软件制作,亦可直接百度下载) 
2. 
1)下载ActivePerl(百度下载) 
http://download.csdn.net/detail/zhimou/8450071 
2)下载obj2opengl(可以将.obj文件转化成.h) 
http://download.csdn.net/detail/ggtaas/4998714 
3.将obj2opengl.pl和你需要转换的obj放到C:\Perl\bin目录中 
(这里我们以banana.obj为例) 


4.运行命令提示符,定位到C:\Perl\bin目录下,输入命令:perl obj2opengl.pl banana.obj

Android | Vuforia 更换模型 Vuforia教程 第1张

这时候你会发现,bin文件夹中自动生成了banana.h文件。 


5.修改代码 
这部分有点繁,等哪天有空了再写教程,先放上代码… 
1)仿照Teapot.Java,新建一个Banana.java 
  主要任务是要替换模型数据,由于数据量大,这里使用了文件操作,我将verts, norms, texcoords三个模型数据放在文件中分别导入

  同时要注意的是,TeaPot的实现有4个参数,而使用obj2opengl导出的.h数据中只有3个参数,缺少indices数据,不过不影响模型的显示,Sample中的Building也是只有3个参数,但具体原理我就不太懂了,跟opengl的知识有关,还望大神指教

/*===============================================================================
Copyright (c) 2012-2014 Qualcomm Connected Experiences, Inc. All Rights Reserved.

Vuforia is a trademark of QUALCOMM Incorporated, registered in the United States 
and other countries. Trademarks of QUALCOMM Incorporated are used with permission.
===============================================================================*/package com.qualcomm.vuforia.samples.SampleApplication.utils;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.FileInputStream;import java.io.InputStreamReader;import java.nio.Buffer;import java.nio.ByteBuffer;import java.nio.ByteOrder;import android.content.res.AssetManager;import android.util.Log;public class Banana extends MeshObject{

    private static final String LOGTAG = "Banana";    private Buffer mVertBuff;    private Buffer mTexCoordBuff;    private Buffer mNormBuff;    private Buffer mIndBuff;    private int indicesNumber = 0;    private int verticesNumber = 0;    private AssetManager assetManager;    public Banana(AssetManager inputassetManager)
    {        this.assetManager = inputassetManager;
        setVerts();
        setTexCoords();
        setNorms();

    }    double[] banana_VERTS;    double[] banana_TEX_COORDS;    double[] banana_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();                //ex.24168 3 floatsdata in 1 line
                int floatsToRead = Integer.parseInt(line);                //int floatsToRead = 1000;

                banana_VERTS = new double[3*floatsToRead];                for (int i = 0; i < floatsToRead; i++)
                {

                    String curline = reader.readLine();                    if( curline.indexOf('/') >= 0 ){
                        i--;                        continue;
                    }                    //split 1 line to 3 data
                    String floatStrs[] = curline.split(",");

                    banana_VERTS[3*i] = Float.parseFloat(floatStrs[0]);
                    banana_VERTS[3*i+1] = Float.parseFloat(floatStrs[1]);
                    banana_VERTS[3*i+2] = Float.parseFloat(floatStrs[2]);
                    Log.d(LOGTAG, ""+i);
                }                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();                //ex.24168 3 floatsdata in 1 line
                int floatsToRead = Integer.parseInt(line);                //int floatsToRead = 1000;

                banana_TEX_COORDS = new double[2*floatsToRead];                for (int i = 0; i < floatsToRead; i++)
                {

                    String curline = reader.readLine();                    if( curline.indexOf('/') >= 0 ){
                        i--;                        continue;
                    }                    //split 1 line to 2 data
                    String floatStrs[] = curline.split(",");

                    banana_TEX_COORDS[2*i] = Float.parseFloat(floatStrs[0]);
                    banana_TEX_COORDS[2*i+1] = Float.parseFloat(floatStrs[1]);                    //banana_TEX_COORDS[3*i+2] = Float.parseFloat(floatStrs[2]);
                }                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();                //ex.24168 3 floatsdata in 1 line
                int floatsToRead = Integer.parseInt(line);                //int floatsToRead = 1000;

                banana_NORMS = new double[3*floatsToRead];                for (int i = 0; i < floatsToRead; i++)
                {

                    String curline = reader.readLine();                    if( curline.indexOf('/') >= 0 ){
                        i--;                        continue;
                    }                    //split 1 line to 3 data
                    String floatStrs[] = curline.split(",");

                    banana_NORMS[3*i] = Float.parseFloat(floatStrs[0]);
                    banana_NORMS[3*i+1] = Float.parseFloat(floatStrs[1]);
                    banana_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/banana/verts.txt");
        } catch (IOException e) {            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        mVertBuff = fillBuffer(banana_VERTS);
        verticesNumber = num ;
    }    private void setTexCoords()
    {        int num = 0;        try {
            num = loadTexCoordsFromModel("ImageTargets/banana/texcoords.txt");
        } catch (IOException e) {            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        mTexCoordBuff = fillBuffer(banana_TEX_COORDS);

    }    private void setNorms()
    {        int num = 0;        try {
            num = loadNormsFromModel("ImageTargets/banana/norms.txt");
        } catch (IOException e) {            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mNormBuff = fillBuffer(banana_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;
    }


}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278

2)修改ImageTargetRenderer.java 
基本就是把TeaPot换成了Banana,然后绘图函数部分将glDrawElements替换成了glDrawArrays

/*===============================================================================
Copyright (c) 2012-2014 Qualcomm Connected Experiences, Inc. All Rights Reserved.

Vuforia is a trademark of QUALCOMM Incorporated, registered in the United States 
and other countries. Trademarks of QUALCOMM Incorporated are used with permission.
===============================================================================*/package com.qualcomm.vuforia.samples.VuforiaSamples.app.ImageTargets;import java.io.IOException;import java.util.Vector;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.opengl.GLES20;import android.opengl.GLSurfaceView;import android.opengl.Matrix;import android.util.Log;import com.qualcomm.vuforia.Matrix44F;import com.qualcomm.vuforia.Renderer;import com.qualcomm.vuforia.State;import com.qualcomm.vuforia.Tool;import com.qualcomm.vuforia.Trackable;import com.qualcomm.vuforia.TrackableResult;import com.qualcomm.vuforia.VIDEO_BACKGROUND_REFLECTION;import com.qualcomm.vuforia.Vuforia;import com.qualcomm.vuforia.samples.SampleApplication.SampleApplicationSession;import com.qualcomm.vuforia.samples.SampleApplication.utils.CubeShaders;import com.qualcomm.vuforia.samples.SampleApplication.utils.LoadingDialogHandler;import com.qualcomm.vuforia.samples.SampleApplication.utils.SampleApplication3DModel;import com.qualcomm.vuforia.samples.SampleApplication.utils.SampleUtils;import com.qualcomm.vuforia.samples.SampleApplication.utils.Teapot;import com.qualcomm.vuforia.samples.SampleApplication.utils.Banana;import com.qualcomm.vuforia.samples.SampleApplication.utils.Texture;// The renderer class for the ImageTargets sample. 
public class ImageTargetRenderer implements GLSurfaceView.Renderer{
    private static final String LOGTAG = "ImageTargetRenderer";

    private SampleApplicationSession vuforiaAppSession;
    private ImageTargets mActivity;

    private Vector<Texture> mTextures;

    private int shaderProgramID;

    private int vertexHandle;

    private int normalHandle;

    private int textureCoordHandle;

    private int mvpMatrixHandle;

    private int texSampler2DHandle;

    private Teapot mTeapot;

    private Banana mBanana;

    private float kBuildingScale = 120.0f;
    private SampleApplication3DModel mBuildingsModel;

    private Renderer mRenderer;

    boolean mIsActive = false;

    private static final float OBJECT_SCALE_FLOAT = 50.0f;


    public ImageTargetRenderer(ImageTargets activity,
        SampleApplicationSession session)
    {
        mActivity = activity;
        vuforiaAppSession = session;
    }


    // Called to draw the current frame.
    @Override
    public void onDrawFrame(GL10 gl)
    {
        if (!mIsActive)
            return;

        // Call our function to render content
        renderFrame();
    }


    // Called when the surface is created or recreated.
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
        Log.d(LOGTAG, "GLRenderer.onSurfaceCreated");

        initRendering();

        // Call Vuforia function to (re)initialize rendering after first use
        // or after OpenGL ES context was lost (e.g. after onPause/onResume):
        vuforiaAppSession.onSurfaceCreated();
    }


    // Called when the surface changed size.
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        Log.d(LOGTAG, "GLRenderer.onSurfaceChanged");

        // Call Vuforia function to handle render surface size changes:
        vuforiaAppSession.onSurfaceChanged(width, height);
    }


    // Function for initializing the renderer.
    private void initRendering()
    {
        //mTeapot = new Teapot();
        mBanana = new Banana(mActivity.getResources().getAssets());

        mRenderer = Renderer.getInstance();

        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");
        normalHandle = GLES20.glGetAttribLocation(shaderProgramID,            "vertexNormal");
        textureCoordHandle = GLES20.glGetAttribLocation(shaderProgramID,            "vertexTexCoord");
        mvpMatrixHandle = GLES20.glGetUniformLocation(shaderProgramID,            "modelViewProjectionMatrix");
        texSampler2DHandle = GLES20.glGetUniformLocation(shaderProgramID,            "texSampler2D");

        try
        {
            mBuildingsModel = new SampleApplication3DModel();
            mBuildingsModel.loadModel(mActivity.getResources().getAssets(),                "ImageTargets/Buildings.txt");
        } catch (IOException e)
        {
            Log.e(LOGTAG, "Unable to load buildings");
        }

        // Hide the Loading Dialog
        mActivity.loadingDialogHandler
            .sendEmptyMessage(LoadingDialogHandler.HIDE_LOADING_DIALOG);

    }


    // The render function.
    private void renderFrame()
    {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        State state = mRenderer.begin();
        mRenderer.drawVideoBackground();

        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

        // handle face culling, we need to detect if we are using reflection
        // to determine the direction of the culling
        GLES20.glEnable(GLES20.GL_CULL_FACE);
        GLES20.glCullFace(GLES20.GL_BACK);
        if (Renderer.getInstance().getVideoBackgroundConfig().getReflection() == VIDEO_BACKGROUND_REFLECTION.VIDEO_BACKGROUND_REFLECTION_ON)
            GLES20.glFrontFace(GLES20.GL_CW); // Front camera
        else
            GLES20.glFrontFace(GLES20.GL_CCW); // Back camera

        // did we find any trackables this frame?
        for (int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++)
        {
            TrackableResult result = state.getTrackableResult(tIdx);
            Trackable trackable = result.getTrackable();
            printUserData(trackable);
            Matrix44F modelViewMatrix_Vuforia = Tool                .convertPose2GLMatrix(result.getPose());
            float[] modelViewMatrix = modelViewMatrix_Vuforia.getData();//            int textureIndex = trackable.getName().equalsIgnoreCase("stones") ? 0//                : 1;
            int textureIndex = trackable.getName().equalsIgnoreCase("Tree") ? 0
                    : 1;
            textureIndex = trackable.getName().equalsIgnoreCase("tarmac") ? 2
                : textureIndex;

            // deal with the modelview and projection matrices
            float[] modelViewProjection = new float[16];

            if (!mActivity.isExtendedTrackingActive())
            {
                Matrix.translateM(modelViewMatrix, 0, 0.0f, 0.0f,
                    OBJECT_SCALE_FLOAT);
                Matrix.scaleM(modelViewMatrix, 0, OBJECT_SCALE_FLOAT,
                    OBJECT_SCALE_FLOAT, OBJECT_SCALE_FLOAT);
            } else
            {
                Matrix.rotateM(modelViewMatrix, 0, 90.0f, 1.0f, 0, 0);
                Matrix.scaleM(modelViewMatrix, 0, kBuildingScale,
                    kBuildingScale, kBuildingScale);
            }

            Matrix.multiplyMM(modelViewProjection, 0, vuforiaAppSession                .getProjectionMatrix().getData(), 0, modelViewMatrix, 0);

            // activate the shader program and bind the vertex/normal/tex coords
            GLES20.glUseProgram(shaderProgramID);

            if (!mActivity.isExtendedTrackingActive())
            {
                GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT,
                    //false, 0, mTeapot.getVertices());
                    false, 0, mBanana.getVertices());
                GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT,
                    //false, 0, mTeapot.getNormals());
                    false, 0, mBanana.getNormals());
                GLES20.glVertexAttribPointer(textureCoordHandle, 2,
                    //GLES20.GL_FLOAT, false, 0, mTeapot.getTexCoords());
                    GLES20.GL_FLOAT, false, 0, mBanana.getTexCoords());
                GLES20.glEnableVertexAttribArray(vertexHandle);
                GLES20.glEnableVertexAttribArray(normalHandle);
                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.glDrawElements(GLES20.GL_TRIANGLES,
//                    mTeapot.getNumObjectIndex(), GLES20.GL_UNSIGNED_SHORT,
//                    mTeapot.getIndices());
                GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0,
                     mBanana.getNumObjectVertex());

                // disable the enabled arrays
                GLES20.glDisableVertexAttribArray(vertexHandle);
                GLES20.glDisableVertexAttribArray(normalHandle);
                GLES20.glDisableVertexAttribArray(textureCoordHandle);
            } else
            {
                GLES20.glDisable(GLES20.GL_CULL_FACE);
                GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT,
                    //false, 0, mBuildingsModel.getVertices());
                        false, 0, mBanana.getVertices());
                GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT,
                    //false, 0, mBuildingsModel.getNormals());
                        false, 0, mBanana.getNormals());
                GLES20.glVertexAttribPointer(textureCoordHandle, 2,
                    //GLES20.GL_FLOAT, false, 0, mBuildingsModel.getTexCoords());
                        GLES20.GL_FLOAT, false, 0, mBanana.getTexCoords());

                GLES20.glEnableVertexAttribArray(vertexHandle);
                GLES20.glEnableVertexAttribArray(normalHandle);
                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,
                    //mBuildingsModel.getNumObjectVertex());
                        mBanana.getNumObjectVertex());

                SampleUtils.checkGLError("Renderer DrawBuildings");
            }

            SampleUtils.checkGLError("Render Frame");

        }

        GLES20.glDisable(GLES20.GL_DEPTH_TEST);

        mRenderer.end();
    }


    private void printUserData(Trackable trackable)
    {
        String userData = (String) trackable.getUserData();
        Log.d(LOGTAG, "UserData:Retreived User Data \"" + userData + "\"");
    }


    public void setTextures(Vector<Texture> textures)
    {
        mTextures = textures;

    }

}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324

3)修改ImageTargets.java 
把贴图文件banana.png 放到和Teapot贴图相同的路径下,并修改以下代码

    private void loadTextures()
    {
        mTextures.add(Texture.loadTextureFromApk("banana.png",
            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()));

    }12345678910111213141234567891011121314

如果贴图显示有问题,可以试着将贴图的方向调整一下 


效果图: 
Android | Vuforia 更换模型 Vuforia教程 第2张

    评论列表暂无评论
    发表评论