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

    xiaoxiao2025-06-20  6

    背景

    最近开始学习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')

    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; }

    其构造方法主要实例化了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(); } }

    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); }

    相比较前几篇文章各种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); } }

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

    设置可在屏幕拖动的小球

    首先为了获取屏幕拖动坐标,我们要复写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(); }

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

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

    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); ((View) mRenderSurface).setOnTouchListener(this); return mLayout; }

    最后,我们还有建立一个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);

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

    设置相机位置与角度

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

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

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

    总结

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

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

    转载请注明原文地址: https://ju.6miu.com/read-1300153.html
    最新回复(0)