OpenGLES入门笔记:Rajawali学习(1)基本功能初探

转自:https://blog.csdn.net/lidec/article/details/52207667

背景

最近开始学习rajawali,rajawali是一个Android下封装了OpenGLES API的引擎,可以方便地建立自己的场景,目前还集成了CardBoard相关,可以进行VR相关的开发,同时也可以进行AR相关的开发。rajawali为我们提供了比较丰富的例程,很多东西可以参照例程快速上手。本文记录了rajawali的集成,以及制作一个简单的音乐频谱变化的小demo,其中遇到不少问题,还需要日后深入理解rajawali的源代码。

集成

仓库地址:https://github.com/Rajawali/Rajawali
其中包括了rajawali引擎,以及相关AndroidDemo,直接使用AndroidStuido打开即可。同时我们在工程下建立自己的一个Module,我们只需要在Module的build.gradle的dependencies下加入如下语句即可

compile project(':rajawali')
  • 1

demo中没有涉及AR,VR相关,所以先不导入其他库。

简单Demo

下面我们将完成一个简单的Demo,其中涉及到天空盒,光照,简单模型以及屏幕拖动几个基本功能。试想如果直接使用GLES的API,同时加入这些会使代码非常复杂,如今我们只需要参考自带的Demo,简单定义几个变量并设置相关属性就可以完成这些效果。rajawali中自带了丰富的Demo,很多效果可以直接参照demo实现。

这里写图片描述

如图,这里我们播放喀秋莎的音乐,立柱根据频谱而跳动,同时我们可以触摸屏幕拖动小球。下面我们记录一下这个Demo实现的步骤。

创建Fragment

我们可以直接继承Demo中的AExampleFragment,并且使用其布局文件。布局文件中,显示部分主要是用org.rajawali3d.view.TextureView,这个控件继承了Android自身的TextureView并实现了rajawali的ISurface接口,用于GLES的绘制。

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        // Inflate the view
        mLayout = (FrameLayout) inflater.inflate(R.layout.rajawali_textureview_fragment, container, false);

        // Find the TextureView
        mRenderSurface = (ISurface) mLayout.findViewById(R.id.rajwali_surface);

        // Create the loader
        mProgressBarLoader = (ProgressBar) mLayout.findViewById(R.id.progress_bar_loader);
        mProgressBarLoader.setVisibility(View.GONE);

        // Create the renderer
        mRenderer = createRenderer();
        onBeforeApplyRenderer();
        applyRenderer();
        return mLayout;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

其构造方法主要实例化了TextureView和Renderer,其中createRenderer()方法需要我们自己来实现,也就是定义我们自己的Renderer,用它来渲染TextureView。
在我们的自己的Fragment中,我们主要是实现上述Renderer。

建立天空盒

不用一切从零开始,我们直接使用Rajawali的API创建一个天空盒。

    private void buildSkyBox(){
            try{
                getCurrentScene().setSkybox(R.drawable.black, R.drawable.black,
                        R.drawable.black, R.drawable.black, R.drawable.black, R.drawable.black);
            } catch (ATexture.TextureException e) {
                e.printStackTrace();
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

getCurrentScene()就是获取当前的场景,这里所有的模型都是需要添加到这个场景中的,而每个renderer中都会包含一个场景。我们所创建的模型或者其他东西,最后只有添加给场景才能显示。

添加光照

参照Demo中的例子,我们为当前场景加一个点光源。

    private void buildLights(){
            PointLight light1 = new PointLight();
            light1.setPower(3.5f);
            light1.setY(3);
            light1.setX(0);
            light1.setZ(1);
            getCurrentScene().addLight(light1);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

相比较前几篇文章各种shader各种变量,感觉真的简单了好多。

添加蓝色柱子

private void buildRectangularPrisms(float r){

            double PI = 3.14;
            double sectorAngle = 120;
            double angle = 180 - (180 - sectorAngle)/2;
            double delta = (angle - (180 - sectorAngle)/2) / MusicPlayer.VisualizerListener.CYLINDER_NUM;

            int color = 0xff/(MusicPlayer.VisualizerListener.CYLINDER_NUM+5);
            int colorReflect = color;

            Material cubeMaterial = new Material();
            cubeMaterial.enableLighting(true);
            cubeMaterial.setDiffuseMethod(new DiffuseMethod.Lambert());

                for(int i=0; i< MusicPlayer.VisualizerListener.CYLINDER_NUM; i++) {
                    RectangularPrism rectangularPrism = new RectangularPrism(0.2f, mRectangularPrismHeight, 0.2f);
                    rectangularPrism.setMaterial(cubeMaterial);
                    rectangularPrism.setColor((color*(i+5))<<32);

                    //倒影
                    RectangularPrism rectangularPrismReflect = new RectangularPrism(0.2f, mRectangularPrismHeight, 0.2f);
                    rectangularPrismReflect.setMaterial(cubeMaterial);
                    rectangularPrismReflect.setColor((colorReflect*(i+5))<<32);

                    double x = Math.cos(PI * angle/180) * r;
                    double z = -Math.sin(PI * angle/180) * r;
                    angle = angle - delta;

                    rectangularPrism.setX(x);
                    rectangularPrism.setZ(z);
                    getCurrentScene().addChild(rectangularPrism);
                    rectangularPrismReflect.setX(x);
                    rectangularPrismReflect.setZ(z);
                    rectangularPrismReflect.setY(-mRectangularPrismHeight);
                    getCurrentScene().addChild(rectangularPrismReflect);

                    RectangularPrismInfo rectangularPrismInfo = new RectangularPrismInfo();
                    rectangularPrismInfo.rectangularPrism = rectangularPrism;
                    rectangularPrismInfo.yLengthRecorder = 1.0f;

                    RectangularPrismInfo rectangularPrismReflectInfo = new RectangularPrismInfo();
                    rectangularPrismReflectInfo.rectangularPrism = rectangularPrismReflect;
                    rectangularPrismReflectInfo.yLengthRecorder = 1.0f;

                    mRectangularPrismList.add(rectangularPrismInfo);
                    mRectangularPrismReflectList.add(rectangularPrismReflectInfo);
                }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

这里相关位置的计算较多,抛开这些计算,其实我们做的事情就是创建一个材质,创建一个几何体模型,设置几何体模型的位置大小等参数,最后把材质设置给几何体。

设置可在屏幕拖动的小球

首先为了获取屏幕拖动坐标,我们要复写Fragment的onTouch方法,这点和普通Android控件开发是一样的。

之后我们的renderer要实现OnObjectPickedListener接口,用来监听选中状态。主要实现如下两方法:

public interface OnObjectPickedListener {

    /**
     * Called when an object has been picked successfully.
     *
     * @param object {@link Object3D} The picked object.
     */
    void onObjectPicked(@NonNull Object3D object);

    /**
     * Called when no object was detected during picking.
     */
    void onNoObjectPicked();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

拖拽的具体原理比较复杂,我们会在后面的文章中单独分析实现过程。

我们还需要在Fragment建立时,让renderer自己监听自己,这样才能响应拖拽事件。

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        ((View) mRenderSurface).setOnTouchListener(this);
        return mLayout;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

最后,我们还有建立一个ObjectColorPicker对象,它是物体选择的最终管理中枢,其内部维护着所有需要拖拽功能对象的引用以及拖拽回调方法。我们可以用如下方法将一个球体变为到可拖拽物体。

mPicker = new ObjectColorPicker(this);
            mPicker.setOnObjectPickedListener(this);

            Material material = new Material();
            material.enableLighting(true);
            material.setDiffuseMethod(new DiffuseMethod.Lambert());

            Sphere sphere = new Sphere(.3f, 12, 12);
            sphere.setMaterial(material);
            sphere.setColor(0x333333 + (int) (Math.random() * 0xcccccc));
            sphere.setX(-2);
            sphere.setY(0);
            sphere.setZ(1);
            sphere.setDrawingMode(GLES20.GL_TRIANGLES);
            mPicker.registerObject(sphere);
            getCurrentScene().addChild(sphere);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

以上只是拖拽功能实现的基本流程,具体细节还需要参照Demo,具体实现原理将在后面文章中专门介绍。

设置相机位置与角度

Rajawali已经为我们封装好了相机的功能,并把它放入了场景中,此处我们直接调用,设置相机的位置以及方向。

getCurrentCamera().enableLookAt();
getCurrentCamera().setLookAt(0, 0, -3);
getCurrentCamera().setY(4);
getCurrentCamera().setZ(6);
  • 1
  • 2
  • 3
  • 4

这样,我们的render就设置好了。

总结

本文主要梳理了Rajawali引擎的一些基本功能,对Rajawali有了一些直观上的认识,Demo中还有许多不完善的地方,还需要进一步熟悉项目源码,排除bug。

本文代码下载地址http://download.csdn.net/detail/lidec/9603256

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值