一覧に戻る

Android ネイティブAPIのレンダリング

2018.07.08AndroidネイティブAPI

レンダリング

このトピックでは、レンダリングがWikitude SDKネイティブAPIと連携してどのように機能するかを示します。

Wikitude SDK ネイティブAPIには、内部レンダリングと外部レンダリングの2種類のレンダリング方法が用意されています。内部レンダリングでは、OpenGLビューはWikitude SDKによってセットアップされ、SDKユーザーはカスタムレンダリングを定義できます。内部レンダリングビュー(OpenGL ES、Metal)は、Wikitude SDKによってセットアップされ、SDKユーザーはWikitude SDKによって実行されるカスタムレンダリングを定義できます。それに対して外部レンダリングは、SDKユーザーが独自にレンダリングビューを設定し、このレンダリング設定にWikitude SDKを統合します。

レンダリングAPI

Android用のWikitude SDKネイティブAPIは、次のRenderingAPIをサポートしています。

  • OpenGL ES 3
  • OpenGL ES 2

レンダリングAPIの選択方法については、「外部レンダリング用のAPIの選択」または「内部レンダリング用のAPIの選択」を参照してください。

外部レンダリング

外部レンダリングをアクティブにするには、ExternalRenderingインタフェースを実装するオブジェクトをWikitudeSDKクラスのコンストラクターに渡す必要があります。サンプルでは、ExternalRenderingActivityクラスで実装されています。これはサンプルのcom.wikitude.samples.rendering.externalにあります。

public class ExternalRenderingActivity extends Activity implements ImageTrackerListener, ExternalRendering {

    private WikitudeSDK wikitudeSDK;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        wikitudeSDK = new WikitudeSDK(this);

ExternalRenderingインタフェースによって定義されているonRenderExtensionCreatedメソッドでは、RenderExtensionインスタンスをパラメーターとして受け取ります。そのパラメーターを、GLSurfaceView.Rendererを拡張した独自のOpenGLレンダラーに渡します。また、Rendererを1秒間に30回呼び出して現在のフレームを描画するDriverも作成します。

    @Override
    public void onRenderExtensionCreated(final RenderExtension renderExtension) {
        glRenderer = new GLRenderer(renderExtension);
        view = new CustomSurfaceView(getApplicationContext(), glRenderer);
        driver = new Driver(view, 30);
        setContentView(view);
    }

以下のコードは、GLSurfaceView.Rendererの基本的な実装を示します。どのメソッドにおいても最初に必ず、WikitudeSDK RenderExtensionを呼び出します。そうしなければ、WikitudeSDKはカメラフレームをレンダリングできず、画像認識も実行できません。

public class GLRenderer implements GLSurfaceView.Renderer {

    private RenderExtension wikitudeRenderExtension = null;
    private TreeMap<String, Renderable> mOccluders = null;
    private TreeMap<String, Renderable> mRenderables = null;

    public GLRenderer(RenderExtension wikitudeRenderExtension) {
        wikitudeRenderExtension = wikitudeRenderExtension;
        /* * Until Wikitude SDK version 2.1 onDrawFrame triggered also a logic update inside the SDK core. * This behaviour is deprecated and onUpdate should be used from now on to update logic inside the SDK core. <br> * * The default behaviour is that onDrawFrame also updates logic. <br> * * To use the new separated drawing and logic update methods, RenderExtension.useSeparatedRenderAndLogicUpdates should be called. * Otherwise the logic will still be updated in onDrawFrame. */
        wikitudeRenderExtension.useSeparatedRenderAndLogicUpdates();
    }

    @Override
    public synchronized void onDrawFrame(final GL10 unused) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        GLES20.glClearDepthf(1.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        if (wikitudeRenderExtension != null) {
            // Will trigger a logic update in the SDK
            wikitudeRenderExtension.onUpdate();
            // will trigger drawing of the camera frame
            wikitudeRenderExtension.onDrawFrame(unused);
        }

        if (mOccluders.size() > 0) {
            Iterator itOccluders = mOccluders.entrySet().iterator();

            while (itOccluders.hasNext()) {
                TreeMap.Entry pairOccluder = (TreeMap.Entry)itOccluders.next();
                Renderable renderable = (Renderable)pairOccluder.getValue();

                renderable.onDrawFrame();
            }
        }

        if (mRenderables.size() > 0) {
            Iterator itRenderables = mRenderables.entrySet().iterator();

            while (itRenderables.hasNext()) {
                TreeMap.Entry pairRenderables = (TreeMap.Entry)itRenderables.next();
                Renderable renderable = (Renderable)pairRenderables.getValue();

                renderable.onDrawFrame();
            }
        }
    }

    @Override
    public void onSurfaceCreated(final GL10 unused, final EGLConfig config) {
        if (wikitudeRenderExtension != null) {
            wikitudeRenderExtension.onSurfaceCreated(unused, config);
        }

        mOccluders = new TreeMap<>();
        mRenderables = new TreeMap<>();
    }

    @Override
    public void onSurfaceChanged(final GL10 unused, final int width, final int height) {
        if (wikitudeRenderExtension != null) {
            wikitudeRenderExtension.onSurfaceChanged(unused, width, height);
        }
    }

    public void onResume() {
        if (wikitudeRenderExtension != null) {
            wikitudeRenderExtension.onResume();
        }
    }

    public void onPause() {
        if (wikitudeRenderExtension != null) {
            wikitudeRenderExtension.onPause();
        }
    }

    public synchronized void setRenderablesForKey(final String key, final Renderable renderbale, final Renderable occluder) {
        if (occluder != null) {
            mOccluders.put(key, occluder);
        }

        mRenderables.put(key, renderbale);
    }

    public synchronized void removeRenderablesForKey(final String key) {
        mRenderables.remove(key);
        mOccluders.remove(key);
    }

    public synchronized void removeAllRenderables() {
        mRenderables.clear();
        mOccluders.clear();
    }

    public synchronized Renderable getRenderableForKey(final String key) {
        return mRenderables.get(key);
    }

    public synchronized Renderable getOccluderForKey(final String key) {
        return mOccluders.get(key);
    }
}

外部レンダリング用のAPIの選択

外部レンダリングの場合、SDKは内部的に正しいAPI呼び出しを行うために、どのレンダリングAPIが使用されたかを把握する必要があります。 これが明示的に設定されていない場合、SDKはOpenGL ES 2コンテキストを要求します。 レンダリングAPIを設定するには、NativeStartupConfiguration.setRenderingAPI(RenderingAPI...)を使用します。 1つのRenderingAPIのみが設定されていることを確認してください。それ以外の場合は、SDKの起動後にIllegalArgumentExceptionがスローされます。

内部レンダリング

内部レンダリングをアクティブにするには、InternalRenderingインタフェースを実装するオブジェクトをWikitudeSDKクラスのコンストラクターに渡す必要があります。以下のサンプルでは、このオブジェクトはInternalRenderingActivityクラスのインスタンスです。これはサンプルのcom.wikitude.samples.rendering.internalにあります。

public class InternalRenderingActivity extends Activity implements InternalRendering, ImageTrackerListener {
    ...
    private WikitudeSDK wikitudeSDK;
    ...
    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        wikitudeSDK = new WikitudeSDK(this);
           ...

InternalRenderingインタフェースによって定義されているprovideRenderExtensionメソッドでは、CustomRenderExtensionのインスタンスを作成してそれを返します。

    @Override
    public RenderExtension provideRenderExtension() {
        renderExtension = new CustomRenderExtension();
        return renderExtension;
    }

CustomRenderExtensionは以下のように定義されています。定義されたすべてのメソッドが、Android標準の GLSurfaceView.Rendererを拡張したWikitudeSDKレンダラーの適切なメソッドから呼び出されます。

public class CustomRenderExtension implements GLSurfaceView.Renderer, RenderExtension {

    private Target currentlyRecognizedTarget = null;
    private StrokedRectangle strokedRectangle;

    @Override
    public void onDrawFrame(final GL10 unused) {
        if (currentlyRecognizedTarget != null) {
            strokedRectangle.onDrawFrame(currentlyRecognizedTarget);
        }
    }

    @Override
    public void onSurfaceCreated(final GL10 unused, final EGLConfig config) {
        strokedRectangle = new StrokedRectangle();
    }

    @Override
    public void onSurfaceChanged(final GL10 unused, final int width, final int height) {
    }

    public void onResume() {
    }

    public void onPause() {
    }

    @Override
    public void useSeparatedRenderAndLogicUpdates() {

    }

    public void setCurrentlyRecognizedTarget(final ImageTarget currentlyRecognizedTarget) {
        currentlyRecognizedTarget = currentlyRecognizedTarget;
    }

}

内部レンダリング用のAPIの選択

内部レンダリングの場合、SDKはどのレンダリングAPIコンテキストを作成するのかを把握する必要があります。 これが明示的に設定されていない場合、SDKはOpenGL ES 2コンテキストを作成して使用します。

レンダリングAPIを設定するには、NativeStartupConfiguration.setRenderingAPI(RenderingAPI...)を使用します。

SDKは"OpenGL ES 3" > "OpenGL ES 2"の順序でレンダリングAPIを設定します。

例:

NativeStartupConfiguration startupConfig = new NativeStartupConfiguration();

// try to create OpenGL ES 3 context, if OpenGL ES 3 is not supported on the device create an OpenGL ES 2 context
startupConfig.setRenderingAPI(RenderSettings.RenderingAPI.OPENGL_ES_3, RenderSettings.RenderingAPI.OPENGL_ES_2);

// try to create OpenGL ES 3 context, if OpenGL ES 3 is not supported on the device there will be undefined behaviour
startupConfig.setRenderingAPI(RenderSettings.RenderingAPI.OPENGL_ES_3);

// try to create OpenGL ES 2 context
startupConfig.setRenderingAPI();

作成されたRenderingAPIを確認するために、InternalRenderingインタフェースはonRenderingApiInstanceCreated(RenderingAPI)コールバックを定義します。

@Override
public void onRenderingApiInstanceCreated(RenderSettings.RenderingAPI renderingAPI) {
    String renderingAPIName = renderingAPI == RenderSettings.RenderingAPI.OPENGL_ES_3 ?
            "OpenGL ES 3.0" : "OpenGL ES 2.0";
    Log.v(TAG, "Rendering connection was created with rendering API " + renderingAPIName);
}