您的位置:首页 > 运维架构

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

2016-08-15 03:22 471 查看

背景

最近开始学习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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: