[转载]详解Android动画之Tween Animation - scott's blog - 博客频道 - CSDN.NET

mikel阅读(671)

来源: [转载]详解Android动画之Tween Animation – scott’s blog – 博客频道 – CSDN.NET

前面讲了动画中的Frame动画,今天就来详细讲解一下Tween动画的使用。

同样,在开始实例演示之前,先引用官方文档中的一段话:

Tween动画是操作某个控件让其展现出旋转、渐变、移动、缩放的这么一种转换过程,我们成为补间动画。我们可以以XML形式定义动画,也可以编码实现。

如果以XML形式定义一个动画,我们按照动画的定义语法完成XML,并放置于/res/anim目录下,文件名可以作为资源ID被引用;如果由编码实现,我们需要使用到Animation对象。

如果用定义XML方式实现动画,我们需要熟悉一下动画XML语法:


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"] >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromX="float"
android:toX="float"
android:fromY="float"
android:toY="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>

XML文件中必须有一个根元素,可以是<alpha>、<scale>、<translate>、<rotate>中的任意一个,也可以是<set>来管理一个由前面几个元素组成的动画集合。

<set>是一个动画容器,管理多个动画的群组,与之相对应的Java对象是AnimationSet。它有两个属 性,Android:interpolator代表一个插值器资源,可以引用系统自带插值器资源,也可以用自定义插值器资源,默认值是匀速插值器;稍后我 会对插值器做出详细讲解。Android:shareInterpolator代表<set>里面的多个动画是否要共享插值器,默认值为 true,即共享插值器,如果设置为false,那么<set>的插值器就不再起作用,我们要在每个动画中加入插值器。

<alpha>是渐变动画,可以实现fadeIn和fadeOut的效果,与之对应的Java对象是AlphaAnimation。 Android:fromAlpha属性代表起始alpha值,浮点值,范围在0.0和1.0之间,分别代表透明和完全不透 明,android:toAlpha属性代表结尾alpha值,浮点值,范围也在0.0和1.0之间。

<scale>是缩放动画,可以实现动态调控件尺寸的效果,与之对应的Java对象是ScaleAnimation。 android:fromXScale属性代表起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0 代表放大一倍;android:toXScale属性代表结尾的X方向上相对自身的缩放比例,浮点值;android:fromYScale属性代表起始 的Y方向上相对自身的缩放比例,浮点值;android:toYScale属性代表结尾的Y方向上相对自身的缩放比例,浮点 值;android:pivotX属性代表缩放的中轴点X坐标,浮点值,android:pivotY属性代表缩放的中轴点Y坐标,浮点值,对于这两个属 性,如果我们想表示中轴点为图像的中心,我们可以把两个属性值定义成0.5或者50%。

<translate>是位移动画,代表一个水平、垂直的位移。与之对应的Java对象是TranslateAnimation。 android:fromXDelta属性代表起始X方向的位置,android:toXDelta代表结尾X方向上的位 置,android:fromYScale属性代表起始Y方向上的位置,android:toYDelta属性代表结尾Y方向上的位置,以上四个属性都支 持三种表示方式:浮点数、num%、num%p;如果以浮点数字表示,代表相对自身原始位置的像素值;如果以num%表示,代表相对于自己的百分比,比如 toXDelta定义为100%就表示在X方向上移动自己的1倍距离;如果以num%p表示,代表相对于父类组件的百分比。

<rotate>是旋转动画,与之对应的Java对象是RotateAnimation。android:fromDegrees属性 代表起始角度,浮点值,单位:度;android:toDegrees属性代表结尾角度,浮点值,单位:度;android:pivotX属性代表旋转中 心的X坐标值,android:pivotY属性代表旋转中心的Y坐标值,这两个属性也有三种表示方式,数字方式代表相对于自身左边缘的像素值,num% 方式代表相对于自身左边缘或顶边缘的百分比,num%p方式代表相对于父容器的左边缘或顶边缘的百分比。

另外,在动画中,如果我们添加了android:fillAfter=”true”后,这个动画执行完之后保持最后的状态;android:duration=”integer”代表动画持续的时间,单位为毫秒。

如果要把定义在XML中的动画应用在一个ImageView上,代码是这样的:


ImageView image = (ImageView) findViewById(R.id.image);
Animation testAnim = AnimationUtils.loadAnimation(this, R.anim.test);
image.startAnimation(testAnim);

下面重点介绍一下插值器的概念:

首先要了解为什么需要插值器,因为在补间动画中,我们一般只定义关键帧(首帧或尾帧),然后由系统自动生成中间帧,生成中间帧的这个过程可以成为 “插值”。插值器定义了动画变化的速率,提供不同的函数定义变化值相对于时间的变化规则,可以定义各种各样的非线性变化函数,比如加速、减速等。下面是几 种常见的插值器:

Interpolator对象 资源ID 功能作用
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 先加速再减速
AccelerateInterpolator @android:anim/accelerate_interpolator 加速
AnticipateInterpolator @android:anim/anticipate_interpolator 先回退一小步然后加速前进
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 在上一个基础上超出终点一小步再回到终点
BounceInterpolator @android:anim/bounce_interpolator 最后阶段弹球效果
CycleInterpolator @android:anim/cycle_interpolator 周期运动
DecelerateInterpolator @android:anim/decelerate_interpolator 减速
LinearInterpolator @android:anim/linear_interpolator 匀速
OvershootInterpolator @android:anim/overshoot_interpolator 快速到达终点并超出一小步最后回到终点

然后我们可以这样使用一个插值器:


&lt;set android:interpolator="@android:anim/accelerate_interpolator"&gt;
...
&lt;/set&gt;

&lt;alpha android:interpolator="@android:anim/accelerate_interpolator"
.../&gt;

如果只简单地引用这些插值器还不能满足需要的话,我们要考虑一下个性化插值器。我们可以创建一个插值器资源修改插值器的属性,比如修改 AnticipateInterpolator的加速速率,调整CycleInterpolator的循环次数等。为了完成这种需求,我们需要创建XML 资源文件,然后将其放于/res/anim下,然后再动画元素中引用即可。我们先来看一下几种常见的插值器可调整的属性:

<accelerateDecelerateInterpolator> 无

<accelerateInterpolator> android:factor 浮点值,加速速率,默认为1

<anticipateInterploator> android:tension 浮点值,起始点后退的张力、拉力数,默认为2

<anticipateOvershootInterpolator> android:tension 同上 android:extraTension 浮点值,拉力的倍数,默认为1.5(2  * 1.5)

<bounceInterpolator> 无

<cycleInterplolator> android:cycles 整数值,循环的个数,默认为1

<decelerateInterpolator> android:factor 浮点值,减速的速率,默认为1

<linearInterpolator> 无

<overshootInterpolator> 浮点值,超出终点后的张力、拉力,默认为2

下面我们就拿最后一个插值器来举例:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:tension="7.0"/&gt;

上面的代码中,我们把张力改为7.0,然后将此文件命名为my_overshoot_interpolator.xml,放置于/res/anim下,我们就可以引用到自定义的插值器了:


&lt;scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/my_overshoot_interpolator"
.../&gt;

如果以上这些简单的定义还不能满足我们的需求,那么我们就需要考虑一下自己定义插值器类了。

我们可以实现Interpolator接口,因为上面所有的Interpolator都实现了Interpolator接口,这个接口定义了一个方法:float getInterpolation(float input);

此方法由系统调用,input代表动画的时间,在0和1之间,也就是开始和结束之间。

线性(匀速)插值器定义如下:


public float getInterpolation(float input) {
return input;
}

加速减速插值器定义如下:


public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

有兴趣的话,大家可以尝试一下自定义一个插值器。

讲了这么久的概念,下面我们就结合实例来演示一下几种Tween动画的应用。

先来介绍一下旋转动画的使用,布局文件/res/layout/rotate.xml如下:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF"&gt;
&lt;ImageView
android:id="@+id/piechart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/piechart"/&gt;
&lt;Button
android:id="@+id/positive"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="顺时针"
android:onClick="positive"/&gt;
&lt;Button
android:id="@+id/negative"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="逆时针"
android:onClick="negative"/&gt;
&lt;/LinearLayout&gt;

我们定义了一个ImageView,用于显示一个饼状图,演示旋转动画,然后定义了两个按钮,用以运行编码实现的动画。动画定义文件/res/anim/rotate.xml如下:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"&gt;
&lt;rotate
android:fromDegrees="0"
android:toDegrees="+360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="5000"/&gt;
&lt;/set&gt;

最后再来看一下RotateActivity.java代码:


package com.scott.anim;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;

public class RotateActivity extends Activity {

private int currAngle;
private View piechart;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rotate);

piechart = findViewById(R.id.piechart);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate);
piechart.startAnimation(animation);
}

public void positive(View v) {
Animation anim = new RotateAnimation(currAngle, currAngle + 180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
/** 匀速插值器 */
LinearInterpolator lir = new LinearInterpolator();
anim.setInterpolator(lir);
anim.setDuration(1000);
/** 动画完成后不恢复原状 */
anim.setFillAfter(true);
currAngle += 180;
if (currAngle &gt; 360) {
currAngle = currAngle - 360;
}
piechart.startAnimation(anim);
}

public void negative(View v) {
Animation anim = new RotateAnimation(currAngle, currAngle - 180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
/** 匀速插值器 */
LinearInterpolator lir = new LinearInterpolator();
anim.setInterpolator(lir);
anim.setDuration(1000);
/** 动画完成后不恢复原状 */
anim.setFillAfter(true);
currAngle -= 180;
if (currAngle &lt; -360) {
currAngle = currAngle + 360;
}
piechart.startAnimation(anim);
}
}

[/xml]

然后,看一下渐变动画,布局文件/res/layout/alpha.xml如下:



动画定义文件/res/anim/alpha.xml如下:



AlphaActivity.java代码如下:



package com.scott.anim;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;

public class AlphaActivity extends Activity implements AnimationListener {

private ImageView splash;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alpha);

splash = (ImageView) findViewById(R.id.splash);
Animation anim = AnimationUtils.loadAnimation(this, R.anim.alpha);
anim.setAnimationListener(this);
splash.startAnimation(anim);
}

public void alpha(View view) {
Animation anim = new AlphaAnimation(1.0f, 0.0f);
anim.setDuration(3000);
anim.setFillAfter(true);
splash.startAnimation(anim);
}

@Override
public void onAnimationStart(Animation animation) {
Log.i("alpha", "onAnimationStart called.");
}

@Override
public void onAnimationEnd(Animation animation) {
Log.i("alpha", "onAnimationEnd called");
}

@Override
public void onAnimationRepeat(Animation animation) {
Log.i("alpha", "onAnimationRepeat called");
}
}

接着看一下位移动画,布局文件/res/layout/translate.xml如下:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"&gt;
&lt;ImageView
android:id="@+id/trans_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/person"/&gt;
&lt;Button
android:id="@+id/trans_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="translate"
android:onClick="translate"/&gt;
&lt;/FrameLayout&gt;

动画定义文件/res/anim/translate.xml如下:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/bounce_interpolator"&gt;
&lt;translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="200"
android:toYDelta="300"
android:duration="2000"/&gt;
&lt;/set&gt;

然后TranslateActivity.java代码如下:


package com.scott.anim;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;

public class TranslateActivity extends Activity {

private ImageView trans_iamge;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tanslate);
trans_iamge = (ImageView) findViewById(R.id.trans_image);
Animation anim = AnimationUtils.loadAnimation(this, R.anim.translate);
anim.setFillAfter(true);
trans_iamge.startAnimation(anim);
}

public void translate(View view) {
Animation anim = new TranslateAnimation(200, 0, 300, 0);
anim.setDuration(2000);
anim.setFillAfter(true);
OvershootInterpolator overshoot = new OvershootInterpolator();
anim.setInterpolator(overshoot);
trans_iamge.startAnimation(anim);
}
}

最后,我们再来看以下缩放动画,布局文件/res/layout/scale.xml如下:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"&gt;
&lt;ImageView
android:id="@+id/scale_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:src="@drawable/person"/&gt;
&lt;Button
android:id="@+id/scale_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="scale"
android:onClick="sclae"/&gt;
&lt;/LinearLayout&gt;

动画定义文件/res/anim/scale.xml如下:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/bounce_interpolator"&gt;
&lt;scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="2.0"
android:pivotX="0.5"
android:pivotY="50%"
android:duration="2000"/&gt;
&lt;alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="3000"/&gt;
&lt;/set&gt;

然后ScaleActivity.java代码如下:


package com.scott.anim;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.BounceInterpolator;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;

public class ScaleActivity extends Activity {

private ImageView scale_iamge;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scale);
scale_iamge = (ImageView) findViewById(R.id.scale_image);
Animation anim = AnimationUtils.loadAnimation(this, R.anim.scale);
anim.setFillAfter(true);
scale_iamge.startAnimation(anim);
}

public void sclae(View view) {
Animation anim = new ScaleAnimation(2.0f, 1.0f, 2.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(2000);
anim.setFillAfter(true);
BounceInterpolator bounce = new BounceInterpolator();
anim.setInterpolator(bounce);
scale_iamge.startAnimation(anim);
}
}

几种动画运行效果如下图所示:

详解Android动画之Frame Animation

mikel阅读(816)

在开始实例讲解之前,先引用官方文档中的一段话:

Frame动画是一系列图片按照一定的顺序展示的过程,和放电影的机制很相似,我们称为逐帧动画。Frame动画可以被定义在XML文件中,也可以完全编码实现。

如果被定义在XML文件中,我们可以放置在/res下的anim或drawable目录中(/res/[anim | drawable]/filename.xml),文件名可以作为资源ID在代码中引用;如果由完全由编码实现,我们需要使用到 AnimationDrawable对象。

如果是将动画定义在XML文件中的话,语法如下:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] &gt;
&lt;item
android:drawable="@[package:]drawable/drawable_resource_name"
android:duration="integer" /&gt;
&lt;/animation-list&gt;

需要注意的是:

<animation-list>元素是必须的,并且必须要作为根元素,可以包含一或多个<item>元素;Android:onshot如果定义为true的话,此动画只会执行一次,如果为false则一直循环。

<item>元素代表一帧动画,Android:drawable指定此帧动画所对应的图片资源,android:druation代表此帧持续的时间,整数,单位为毫秒。

文档接下来的示例我就不在解说了,因为接下来我们也要结合自己的实例演示一下这个过程。

我们新建一个名为anim的工程,将四张连续的图片分别命名为f1.png,f2.png,f3.png,f4.png,放于drawable目录,然后新建一个frame.xml文件:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"&gt;
&lt;item android:drawable="@drawable/f1" android:duration="300" /&gt;
&lt;item android:drawable="@drawable/f2" android:duration="300" /&gt;
&lt;item android:drawable="@drawable/f3" android:duration="300" /&gt;
&lt;item android:drawable="@drawable/f4" android:duration="300" /&gt;
&lt;/animation-list&gt;

我们可以将frame.xml文件放置于drawable或anim目录,官方文档上是放到了drawable中了,大家可以根据喜好来放置,放在这两个目录都是可以运行的。

然后介绍一下布局文件res/layout/frame.xml:


&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"&gt;
&lt;ImageView
android:id="@+id/frame_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/&gt;
&lt;Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="stopFrame"
android:onClick="stopFrame"/&gt;
&lt;Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="runFrame"
android:onClick="runFrame"/&gt;
&lt;/LinearLayout&gt;

我们定义了一个ImageView作为动画的载体,然后定义了两个按钮,分别是停止和启动动画。

接下来介绍一下如何通过加载动画定义文件来实现动画的效果。我们首先会这样写:


package com.scott.anim;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class FrameActivity extends Activity {

private ImageView image;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame);
image = (ImageView) findViewById(R.id.frame_image);

image.setBackgroundResource(R.anim.frame);
AnimationDrawable anim = (AnimationDrawable) image.getBackground();
anim.start();
}
}

看似十分完美,跟官方文档上写的一样,然而当我们运行这个程序时会发现,它只停留在第一帧,并没有出现我们期望的动画,也许你会失望的说一 句:“Why?”,然后你把相应的代码放在一个按钮的点击事件中,动画就顺利执行了,再移回到onCreate中,还是没效果,这个时候估计你会气急败坏 的吼一句:“What the fuck!”。但是,什么原因呢?如何解决呢?

出现这种现象是因为当我们在onCreate中调用AnimationDrawable的start方法时,窗口Window对象还没有完全初始 化,AnimationDrawable不能完全追加到窗口Window对象中,那么该怎么办呢?我们需要把这段代码放在 onWindowFocusChanged方法中,当Activity展示给用户时,onWindowFocusChanged方法就会被调用,我们正是 在这个时候实现我们的动画效果。当然,onWindowFocusChanged是在onCreate之后被调用的,如图:

然后我们需要重写一下代码:


package com.scott.anim;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class FrameActivity extends Activity {

private ImageView image;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame);
image = (ImageView) findViewById(R.id.frame_image);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
image.setBackgroundResource(R.anim.frame);
AnimationDrawable anim = (AnimationDrawable) image.getBackground();
anim.start();
}
}

运行一下,动画就可以正常显示了。

如果在有些场合,我们需要用纯代码方式实现一个动画,我们可以这样写:


AnimationDrawable anim = new AnimationDrawable();
for (int i = 1; i &lt;= 4; i++) {
int id = getResources().getIdentifier("f" + i, "drawable", getPackageName());
Drawable drawable = getResources().getDrawable(id);
anim.addFrame(drawable, 300);
}
anim.setOneShot(false);
image.setBackgroundDrawable(anim);
anim.start();

完整的FrameActivity.java代码如下:


package com.scott.anim;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class FrameActivity extends Activity {

private ImageView image;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame);
image = (ImageView) findViewById(R.id.frame_image);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
image.setBackgroundResource(R.anim.frame);    //将动画资源文件设置为ImageView的背景
AnimationDrawable anim = (AnimationDrawable) image.getBackground();    //获取ImageView背景,此时已被编译成AnimationDrawable
anim.start();    //开始动画
}

public void stopFrame(View view) {
AnimationDrawable anim = (AnimationDrawable) image.getBackground();
if (anim.isRunning()) {    //如果正在运行,就停止
anim.stop();
}
}

public void runFrame(View view) {
//完全编码实现的动画效果
AnimationDrawable anim = new AnimationDrawable();
for (int i = 1; i &lt;= 4; i++) {
//根据资源名称和目录获取R.java中对应的资源ID
int id = getResources().getIdentifier("f" + i, "drawable", getPackageName());
//根据资源ID获取到Drawable对象
Drawable drawable = getResources().getDrawable(id);
//将此帧添加到AnimationDrawable中
anim.addFrame(drawable, 300);
}
anim.setOneShot(false);    //设置为loop
image.setBackgroundDrawable(anim);    //将动画设置为ImageView背景
anim.start();    //开始动画
}
}

好,先到这里,谢谢大家。

 

[转载]APIDemo学习笔记——Android上几种简单的Animation使用方法(一) - 风清云淡 - 博客频道 - CSDN.NET

mikel阅读(808)

来源: [转载]APIDemo学习笔记——Android上几种简单的Animation使用方法(一) – 风清云淡 – 博客频道 – CSDN.NET

 

(啊,一不小心把这篇文章删了,没有备份,只能重来了。)

在API Demo的View->Animation下可以找到四个Animation的Demo,第一个3D Translate比较复杂,最后再讲,先讲第2个Interpolator。该Activity对应的是view包内的 Animation3.java,和layout的animation_3.xml。

界面的布局不加解释了,就一个Spinner和一个TextView。不是本文内容。

主要解释下几个重点语句。

 

初始化Animation,从类的名字可以看出是一个变换View的位置的动画,参数起点横坐标,终点横坐标,起点纵坐标,终点纵坐标。


Animation a = new TranslateAnimation(0.0f,
targetParent.getWidth() - target.getWidth() - targetParent.getPaddingLeft() -
targetParent.getPaddingRight(), 0.0f, 0.0f);

下面是动画的参数设置,我加上了注释


a.setDuration(1000);//设置动画所用的时间
a.setStartOffset(300);//设置动画启动的延时
//设置重复模式,RESTART为结束后重新开始,REVERSE为按原来的轨迹逆向返回
a.setRepeatMode(Animation.RESTART);
//设置重复次数,INFINITE为无限
a.setRepeatCount(Animation.INFINITE);
//根据用户在Spinner的选择设置target的进入的方式
switch (position) {
case 0:
//加速进入
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.accelerate_interpolator));
break;
case 1:
//减速进入
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.decelerate_interpolator));
break;
case 2:
//加速进入.与第一个的区别为当repeatMode为reverse时,仍为加速返回原点
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.accelerate_decelerate_interpolator));
break;
case 3:
//先往后退一点再加速前进
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.anticipate_interpolator));
break;
case 4:
//减速前进,冲过终点前再后退
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.overshoot_interpolator));
break;
case 5:
//case 3,4的结合体
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.anticipate_overshoot_interpolator));
break;
case 6:
//停止前来回振几下
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.bounce_interpolator));
break;
}
//让target开始执行这个动画
target.startAnimation(a);
}

这里使用的是Android已预设的一些动作,我们也可以自定义XML来实现更好看的动画效果的,这个下一篇再讲。

除了TranslationAnimation,还有AlphaAnimation、RotateAnimation、ScaleAnimation,使用这几个基体动作的组合,可以形成一系列复杂的动画效果。具体用法请查看SDK。

整个都比较简单,就一个函数的调用,还不懂的看一下API的注释和SDK文档,没什么难理解的。

APIDemo学习笔记——Android上几种简单的Animation使用方法(二)

mikel阅读(928)

现在开始看第三个Push,从View->animation->Push可以启动这个Activity

Push这个Demo主要是展示了View之间的切换效果。

Push对应的Java文件为view包内的Animation2.java,对应的XML布局文件为layout/animation_2.xml。

先看布局文件,这个页面内最主要用到的是一个ViewFlipper。使用ViewFlipper可以实现多个View之间的动态切换,并且可以自定义切换动画,本例中所展示的就是如何定义切换动画。

下面只挑重点语句来讲了。

 

让ViewFlipper开始自动切换。


mFlipper.startFlipping();

当点击时Spinner内的选项时,更改进入和退出的动画效果。


public void onItemSelected(AdapterView parent, View v, int position, long id) {
switch (position) {
case 0:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_out));
break;
case 1:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_out));
break;
case 2:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_out));
break;
default:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.hyperspace_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.hyperspace_out));
break;
}
}

这里的Animation都是自定义的动画效果,可以在res/anim内找到对应的XML文件,下面用push_up_in.xml来说明定义的大概用法。

因为这个动画是由几个动画复合组成的,所以外围就用一个set标签括起来,组成一个AnimationSet。

translate标签内主要定义位置的变化情况,fromYDelta=”100%p”,是指从ViewFlipper的正下方刚好一个View 的高度的距离的地方开始出现,100%p是一个相对值,大于0为下方,小于0为上方。toYDelta=”0″,是指刚好达到布局文件的原始位置停止。 Android:duration=”300″,是指整个动作的时间用时为300毫秒,系统会根据这个时间自动调整速度。

alpha标签内定义的是透明度,0为全透明,1.0为不透明,过程为300毫秒,让View为逐渐出现的过程


&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
&lt;translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="300"/&gt;
&lt;alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" /&gt;
&lt;/set&gt;

push_up_out.xml,和push_left的两个标签都几乎一样的,应该很好理解。

hyperspace_in.xml更简单,只有一个alpha,所以外层没有set标签。startOffset是设置延迟。

 

hyperspace_out.xml相对复杂一点,set里面还包括有set,但仍然是由几个小动作一起组成的,可以一点点拆成来理解。

最外层是一个set,里面嵌套一个scale和一个set。

第一个scale标签可以理解为,以当前View的正中间位置为轴点,在700毫秒时间内,以加速放大的方式,将View的横长变为1.4倍,高度 变为0.6倍。至于fillAfter这个标签我一直搞不懂这个功能,照SDK里的解释,是在连续动画中让View保持在动画的最后一帧,但照我的实验似 乎没有什么效果,这个求高手指教。(查网上一些资料是说必须在代码里设置,这个是不是属于Android的Bug?)一个animationSet可以做 为另一个animationSet的子集,这个很容易理解。rotate标签内的照字面意思应该很容易理解了,不再赘述了。


&lt;set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"&gt;
&lt;scale
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="0.6"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="700" /&gt;
&lt;set
android:interpolator="@android:anim/accelerate_interpolator"
android:startOffset="700"&gt;

&lt;scale
android:fromXScale="1.4"
android:toXScale="0.0"
android:fromYScale="0.6"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="400" /&gt;

&lt;rotate
android:fromDegrees="0"
android:toDegrees="-45"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="400" /&gt;
&lt;/set&gt;
&lt;/set&gt;

很多动画其实都是通过alpha, scale, rotate, translate这几个基本动作组成的。这些都属于Tween Animation。另外还有一种Frame Animation,类似放电影的效果,一帧帧播放动画,以后再说。

所有在XML内的设置的属性都可以在JAVA里找到对应的API函数,在Android SDK文档里可以查得到。

其实我觉得我这样写得都有点啰嗦了,Android的API的名字定义都很规范,从名字都已经可以判断出这个函数的功能了,下次不再写这么详细了。

 

 

 

[转载]掌握这 4 步,你也能打造一款用户爱不释手的产品 | 雷锋网

mikel阅读(772)

打造一款用户都喜欢使用的产品应该是无数产品人的目标。当然在一个产品开始之前,首先我们要确认产品的市场是否真实存在,是否有一批用户在等待产品的诞生。

来源: [转载]掌握这 4 步,你也能打造一款用户爱不释手的产品 | 雷锋网

打造一款用户都喜欢使用的产品应该是无数产品人的目标。当然在一个产品开始之前,首先我们要确认产品的市场是否真实存在,是否有一批用户在等待产品的诞生。当你找到这个问题的肯定答案时,我们不妨来看一下做产品最需要关注的事情。

产品通常的步骤是从小做起,即先为这产品制作出一款最简化版本。那么一般我们是如何开始的呢?

1、哪个群体在使用我的产品?

拿办公软件举个例子好了,我们需要考虑清楚这几个问题:

  1. 哪类员工会每天使用我的产品?
  2. 哪里是他们的使用场景?——在电脑上还是在手机上?
  3. 他们会经常切换不同的设备来使用我的产品吗?
  4. 他们最喜欢哪种沟通方式?——语音、文字还是即时消息?

如果我们能很清楚地回答这些问题,那么我们就能很好地确定产品开发的优先级。

2、列出最重要的用户需求清单

这 一步最能说明用户是如何使用我们的产品,以及使用该产品为她/他带来的价值。清单上的用户需求可以这么写,比如「作为一个用户,我希望这款产品能在台上电 脑上收发消息」、「作为一个用户,我希望在电脑上开始会话后,在我离开电脑桌的时候仍可以用手机继续对话。」接着我们会按照这些用户需求的优先级排序,然 后开始开发一款小规模产品。

3、优秀的交互体验

很多人可能会马上想到 UI(用户交互界面)设计,但是这也同样适用于那些没有 UI 交互的产品,比如 API(应用程序界面)。对于一款使用体验优秀的 API 产品,关键在于考虑它的文档和 Github 体验。如果我们设计 UI,那就需要考虑界面、感官以及滑动屏幕的流畅度。无论是哪种设计,我们的目标是让用户在使用产品的过程中愉悦,用产品来吸引和打动她/他。

4、降低用户对产品的学习门槛

如果产品不够直观简单,让用户无从下手,那么再好的用户体验也于事无补。当然,如果我们能够提供一个简短的视频教程和易懂的注册流程介绍,这对于减少用户的学习成本是非常有帮助的。

我们已经掌握了以上 4 个步骤,那么接下来该做什么?反馈,更多的用户反馈。用户如果一旦开始使用这款产品,我们要做的是不断调整产品的相关细节和体验:观察他们使用这款产品的神情、聆听他们对这款产品的评价以及思维过程。

我希望能听到产品哪部分做得好、哪部分还能优化得更好以及用户的真正需要什么(注意是「需要」而不是「想要」)。毫无疑问,他们的建议能对我们有所启发,这对产品本身的改进非常有帮助,比如产品的迭代或者加入更多实用的功能。

Via Medium

[转载]Opengl绘制我们的小屋(一)球体,立方体绘制 - 天天不在 - 博客园

mikel阅读(1169)

来源: [转载]Opengl绘制我们的小屋(一)球体,立方体绘制 – 天天不在 – 博客园

这个系列我想用来运用opengl红皮书的前八章节的内容,来打造一个室内小屋.

这一章主要是定义几个基本的结构.并给出球体与立方体的画法,先让我们来定义一些基本的结构.一个是包含点,法向量,纹理贴图向量,二是矩形与圆形的父类,包含一些基本公有的处理.


type T2N3V3 =
struct
val mutable TexCoord : Vector2
val mutable Normal : Vector3
val mutable Position : Vector3
new(v,n,p) = {TexCoord = v;Normal = n;Position = p}
end
[&lt;AbstractClass&gt;]
type Shape() =
let mutable bCreate = false
let mutable vi = 0
let mutable ei = 0
let mutable count = 0
member this.vboID with get() = vi and set value = vi &lt;- value
member this.eboID with get() = ei and set value = ei &lt;- value
member this.TriangelCount with get() = count and set value = count &lt;- value
member this.IsCreate with get() = bCreate and set value = bCreate &lt;- value
abstract Draw : unit -&gt; unit
abstract Init : unit -&gt; unit
member this.InitQ : unit -&gt; unit =fun () -&gt; ()

然后是球体的画法,相关具体过程如上篇,先贴上代码,我会对其中一些做些说明.
type Sphere(radius:float32,level:int) =
        inherit Shape()
        let mutable rad,lev = radius,level
        let RightLevel = 
            if lev &lt; 0 then lev &lt;- 0
            elif lev &gt; 6 then lev &lt;-6
        override this.Draw() =  
            if this.IsCreate&lt;&gt;true then this.Init()
            GL.BindBuffer(BufferTarget.ArrayBuffer,this.vboID)
            GL.BindBuffer(BufferTarget.ElementArrayBuffer,this.eboID)
            GL.InterleavedArrays(InterleavedArrayFormat.T2fN3fV3f,0,IntPtr.Zero)
            GL.DrawElements(BeginMode.Triangles,this.TriangelCount,DrawElementsType.UnsignedInt,IntPtr.Zero)
        override this.Init() =
            let alls = Array.create 6 (new T2N3V3())
            alls.[0] &lt;- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitX, Vector3.UnitX * rad )
            alls.[1] &lt;- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitY, Vector3.UnitY * rad )
            alls.[2] &lt;- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitZ, Vector3.UnitZ * rad )
            alls.[3] &lt;- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitX, -Vector3.UnitX * rad )
            alls.[4] &lt;- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitY, -Vector3.UnitY * rad )
            alls.[5] &lt;- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitZ, -Vector3.UnitZ * rad )
            let is = [| 
                            1;2;0
                            0;2;4
                            0;4;5
                            5;1;0
                            1;3;2
                            4;2;3
                            4;3;5
                            1;5;3
                        |]
            let (vvv:T2N3V3 []),(iv: int[]) = this.Sub (alls,is)
            let mutable vID,eID = 0,0
            //let mutable tv,vv,pv = vvv |&gt; Array.map (fun v -&gt; v.TexCoord,v.Normal,v.Position) |&gt; Array.unzip3            
            GL.GenBuffers(1,&amp;vID) 
            GL.BindBuffer(BufferTarget.ArrayBuffer,vID)
            GL.BufferData(BufferTarget.ArrayBuffer,IntPtr (4 * 8 * vvv.Length),vvv,BufferUsageHint.StaticDraw)
            
            GL.GenBuffers(1,&amp;eID)
            GL.BindBuffer(BufferTarget.ElementArrayBuffer,eID)
            GL.BufferData(BufferTarget.ElementArrayBuffer,IntPtr (4 * iv.Length),iv,BufferUsageHint.StaticDraw)

            this.vboID &lt;- vID
            this.eboID &lt;- eID
            this.TriangelCount &lt;- iv.Length 
            this.IsCreate &lt;- true
            ()
         member v.GetMidValue (first:T2N3V3,second:T2N3V3) =
            let midN = Vector3.Lerp(first.Position,second.Position,0.5f) |&gt; Vector3.Normalize
            let midP = midN *(float32 rad)
            let midT = Vector2.Lerp(first.TexCoord,second.TexCoord,0.5f) |&gt; Vector2.Normalize
            let result = new T2N3V3(midT,midN,midP)
            result
        member v.Subdivide (v1:T2N3V3,v2:T2N3V3,v3:T2N3V3) =
            let vs = Array.create 6 (new T2N3V3())
            vs.[0] &lt;- v1
            vs.[1] &lt;- v.GetMidValue(v1,v2)
            vs.[2] &lt;- v.GetMidValue(v3,v1)
            vs.[3] &lt;- v2
            vs.[4] &lt;- v.GetMidValue(v2,v3)
            vs.[5] &lt;- v3
            let is = Array.create 12 0
            is.[0] &lt;- 0
            is.[1] &lt;- 1
            is.[2] &lt;- 2
            is.[3] &lt;- 2
            is.[4] &lt;- 1
            is.[5] &lt;- 4
            is.[6] &lt;- 4
            is.[7] &lt;- 1
            is.[8] &lt;- 3
            is.[9] &lt;- 2
            is.[10] &lt;-4
            is.[11] &lt;- 5
            (vs,is)
        member this.Sub(alls:T2N3V3 [],is:int []) =
            //let mutable tv,vv,pv = alls |&gt; Array.map (fun v -&gt; v.TexCoord,v.Normal,v.Position) |&gt; Array.unzip3
            let mutable allv = alls
            let mutable iv = is
            let show array = printfn "%A" array
            for j in 0 .. lev do
                let mutable av = Array.create 0 (new T2N3V3())
                let mutable ev = Array.create 0 0
                printfn "%i" allv.Length
                printfn "%i" iv.Length
                for i in 0 .. 3 .. iv.Length - 1 do
                    let (vvv,iiv) = this.Subdivide(allv.[iv.[i]],allv.[iv.[i+1]],allv.[iv.[i+2]])
                    let length = av.Length
                    av &lt;- Array.append av vvv
                    let map = iiv |&gt; Array.map (fun p -&gt; p + length)
                    ev &lt;- Array.append ev map
                allv &lt;- av
                iv &lt;- ev 
                allv |&gt; Array.map (fun p -&gt; p.Position) |&gt; show
                show iv
            allv,iv
初始化需要的二个参数,分别代表球的大小(radius),与画的细分程度(level).其中相关如何绘制球体代码在上文有讲,相当于有是把一个分别位于x,y,z各(+radius,-radius)这六个点,组成的一个八个三角形,索引点的位置如Init里的is代表的3(每个三角形)*8(8个面).对其中每个三角形一变4,level表示4的level加一次方.

GL.InterleavedArrays(InterleavedArrayFormat.T2fN3fV3f,0,IntPtr.Zero) 其中的T2fN3fV3f对应于我们的数据结构T2N3V3,这个函数分别相当于指定 GL.TexCoordPointer,GL.NormalPointer,GL.VertexPointer(还会打开相应状态),会自动给我们处理 好,我们也可以只指定顶点,如下GL.VertexPointer(3,VertexPointerType.Float,4*8,IntPtr (4*8-4*5)),这些数据之间的间隔对应与我们前面写入的 GL.BufferData(BufferTarget.ArrayBuffer,IntPtr (4 * 8 * vvv.Length),vvv,BufferUsageHint.StaticDraw)其中vvv是T2N3V3的结构.

基本的GL.BindBuffer的对应的三个处理就不细说了,在Draw 里,BindBuffer是指定我们当前格式数据在存储位置,然后分别调用InterleavedArrays设定各顶点的状态,然后是调用 DrawElements对应上面的 GL.BindBuffer(BufferTarget.ElementArrayBuffer,this.eboID)处理.

然后是立方体的绘制,其中立方体的绘制用的方法看起来会容易理解.如下


type Cube(width:float32,height:float32,length:float32,index:int) =
inherit Shape()
let mutable id = index
let xl,yl,zl =width/2.f,height/2.f,length/2.f
let mutable color = Color.White
let v8 = [|
new Vector3(xl,yl,zl)
new Vector3(-xl,yl,zl)
new Vector3(-xl,-yl,zl)
new Vector3(xl,-yl,zl)
new Vector3(xl,yl,-zl)
new Vector3(-xl,yl,-zl)
new Vector3(-xl,-yl,-zl)
new Vector3(xl,-yl,-zl)
|]
new(x,y,z) =
let rnd = System.Random().Next()
printfn "%i" rnd
Cube(x,y,z,-1)
override this.Draw() =
if this.IsCreate&lt;&gt;true then this.Init()
GL.EnableClientState(ArrayCap.VertexArray)
GL.EnableClientState(ArrayCap.NormalArray)
GL.BindBuffer(BufferTarget.ArrayBuffer,this.vboID)
GL.VertexPointer(3,VertexPointerType.Float,0,IntPtr.Zero)
GL.PushMatrix()
if id &gt;= 0 &amp;&amp; id &lt; 8 then
GL.Translate(v8.[id])
GL.Color3(this.Color:Color)
GL.Normal3(Vector3.UnitZ)
GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|0;1;2;0;2;3|])
//GL.Color3(Color.Black)
GL.Normal3(Vector3.UnitY)
GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|4;5;1;4;1;0|])
//GL.Color3(Color.Red)
GL.Normal3(Vector3.UnitX)
GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|4;0;3;4;3;7|])
//GL.Color3(Color.Green)
GL.Normal3(-Vector3.UnitY)
GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|3;2;6;3;6;7|])
//GL.Color3(Color.Blue)
GL.Normal3(-Vector3.UnitX)
GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|1;5;6;1;6;2|])
//GL.Color3(Color.DodgerBlue)
GL.Normal3(-Vector3.UnitZ)
GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|5;4;7;5;7;6|])
GL.PopMatrix()
override this.Init() =
let mutable vID = 0
GL.GenBuffers(1,&amp;vID)
GL.BindBuffer(BufferTarget.ArrayBuffer,vID)
GL.BufferData(BufferTarget.ArrayBuffer,IntPtr (4 * 3 * v8.Length),v8,BufferUsageHint.StaticDraw)
this.vboID &lt;- vID
this.IsCreate &lt;- true
let rnd = System.Random(this.GetHashCode())
this.Color &lt;- Color.FromArgb(rnd.Next(0,255),rnd.Next(0,255),rnd.Next(0,255))
()
member this.Index with get() = id and set value = id &lt;-value
member this.Color with get() = color and set value = color &lt;- value

立方体顶点索引

上图中的V8分别对应其中的0-7个顶点,GL.DrawElements后面的0;1;2;0;2;3分别是以三角形的画法来画一个正方形.

立方体的画法主要是确定宽,高,长,我们这样定义,我们站在原点上,面向Z+轴, 我们的手展开来表示X轴(对应宽度),而我们的身高表示Y轴(对应高度),和我们面向距离的长远来表示Z轴,(对应长度).绘制也是8个面,和上面一样, 也是在缓存中记录顶点,但是不一样的是,顶点索引是在绘制时没有用到顶点索引缓存,主要考虑后面有法向量的处理,还有现在没有加上的纹理贴图的处理.

在这里,我们要特别注意,顶点顺序问题,在opengl,默认正面是逆时针,而我 们可以看0;1;2;0;2;3对应图上的顺序.然后大家可能会发现,画立方体的后面5;4;7;5;7;6,这个顺序好像不对,是顺时针的.大家可以想 象下,我们在门外看门的逆时针画法与我们在门内看门外顺时针的画法是一样的.所以如果我们要画后面4,5,6,7我们以为的是逆时针是不对的,我们要想象 我们在那边来看,然后再画,应该是5,4,7,6这个方向.其中纹理贴图后面会说,和这处理也有类似.

在上面,我们看到我们都没对顶点的颜色来定义,这里没必要,因为后面我们肯定要用到灯光,用到灯光的话,设置的颜色都没用,我们会用到灯光颜色与材质的颜色.纹理贴图也有没对应处理,这里在后面我会根据讲到再来改写相关处理.

下一节,主要是讲第一人称漫游的相关处理.

[转载]如何在Android中定义容量巨大的数组-czxttkl-搜狐博客!!!

mikel阅读(1190)

来源: [转载]如何在Android中定义容量巨大的数组-czxttkl-搜狐博客!!!

背景:

本人因为某Android项目需要,需要在Android中定义一个容量为2万的float数组。这两万个float值已经存在某个文件中。
方法:
1.直接在Java文件里定义?
Java单个函数的长度限制为65535字节(不确定具体数值,但肯定是有限制的)。故在Java文件中直接定义如此之长的数组是行不通的。
2. BufferedReader 或是 Scanner?
可以创建一个文件,每行存放一个float值。通过BufferedReader.nextLine()读取每一行的字符,用Float.parseFloat(String)来将读到的字符转换成float值,最后将float值存取至数组里。也可以通过Scanner.nextFloat()这样的方法来读取文件中存放的float值。这个时候,文件里并不需要将每个float值放在单独的一行里。但是不同的float值至少需要以某些符号隔开(例如,空格)。
经 过对比,通过BufferedReader读取2W个float值比较快,使用Scanner会占用大量内存,并且不断调用GC,导致线程暂停。但是,当 要读取的文件很大的时候,即使使用BufferedReader也会出现问题:在低端的机子上运行时,Logcat会出现OutOfMemory的错误提 示。
3. 将2万个float值写入文件后做Java的内存映射。
Java内存映射网上的文章不多,可以参考:http://www.javacodegeeks.com/2013/05/power-of-java-memorymapped-file.htmlhttp://www.studytrails.com/java-io/Channels.jsp。这种方法,需要先将所有float值以byte的形式写入到文件中。接着,使用FileChannel将文件中的byte映射到内存中,生成FloatBuffer。最后在FloatBuffer中读取float值存至float数组中。在通过经测试,这种方法比BufferedReader快很多。但是如果算上写文件的时间的话,不如BufferedReader来得方便。
大家可以借鉴一下我测试对比所用的源码。第一个部分,我使用Scanner;第二个部分,我使用BufferedReader;第三部分,我将第二部分读取到的float值以byte形式存取至文件中;第四部分,我使用MappedByteBuffer将文件中的内容映射至内存,并生成新的float数组。
源码下载地址:https://db.tt/9jCbO653
以下是结果运行截图:

当然,以上测试程序均在PC java端运行。真正要移植到Android上进行内存映射,还需要:
1. 由于从assets里读文件只能获取InputStream,而调用FileChannel.map()必须从FileInputStream中获得,故需要将assets里的内存映射文件转移至sd卡上后再从sd卡上读取它们。
2. 在测试文件中,我使用了DataOutputStream.writeFloat()将float数组写入内存映射文件。该方法写入遵循 BIG_ENDIAN规则。故当进行内存映射的时候,很有可能是以LITTLE_ENDIAN的方法读取的(这还要看你是如何实现内存映射的)。
以下这段代码,给出了如何将一个存好的float数组(cubeTextureCoordinateData)以LITTLE_ENDIAN的方式写入内存映射文件:
/* Writing Memory Map Raw Data */
ByteBuffer littleEndian = ByteBuffer.allocateDirect(11160 * 4).order(ByteOrder.LITTLE_ENDIAN);
i = 0;
while (i < 11160) {
littleEndian.putFloat(cubeTextureCoordinateData[i++]);
}
littleEndian.flip();

try {
FileOutputStream fos = new FileOutputStream(“memorymap_texture_little_endian”);
FileChannel fc = fos.getChannel();
fc.write(littleEndian);
fc.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}

鸣谢北邮编程浪子张亚杰在内存映射上的支持。

在android上如何将obj文件导入至opengl

mikel阅读(1532)

背景:

若想在Android上用opengl画出复杂的3d模型,能想到的直接的 办法就是从一个已经生成好的obj文件中导入。obj文件包含了3d模型的所有vertices的坐标(以v起始),所有vertices的normal 坐标(以vn起始),所有点的texture坐标(以vt起始),以及所有face的信息(以f起始)。用Opengl ES画出3d模型,只需要知道每个vertex的坐标、normal坐标和texture坐标即可。但是,obj文件中的vertices坐标和 texture坐标数量并不相等,也就是说,并不是每一个vertex都有一个对应的texture坐标,所以直接将v、vn和vt起始的坐标定义为数组 让opengl画是行不通的。
为什么obj文件中的vertices坐标和texture坐标的数量不相等呢?如下图所示,A点作为空间坐标,只需要被定义一次。但是A点属于6个三角形,每个三角形的texture可能都不相同,导致了A点可能拥有6种texture坐标。
解决方法:
1. 我在网上找到了一个perl程序。它可以分析obj文件内容,生成等数量的vertices、texture和normal数组,并存放在.h文件中。
perl程序下载地址:https://db.tt/YWPev7Wy
使用方法为:安装好perl运行环境。在命令行中运行:perl obj2opengl.pl your_obj_file.obj
输出:同文件夹下生成同名.h文件
2. 打开生成的头文件,将里面的vertices、texture和normal数组分别存成3个文件。现在,只要在你的Renderer类中,定义3个 float数组,分别用来表示3d模型的vertices、texture和normal。这3个float数组的内容由存好的3个文件导入。
想知道在Android中通过导入文件定义大容量float数组的同学,请转:http://maider.blog.sohu.com/281585518.html
不会OpenGL ES on Android还在孜孜不倦地看这篇文章的同学,请转:http://www.learnopengles.com/android-lesson-one-getting-started/
参考:

Android:OpenGL ES现实3D动画

mikel阅读(968)

Android:OpenGL ES现实3D动画_小安空间_新浪博客,小安空间,

</blockquote>
<blockquote>public class GLRender implements Renderer
{
<wbr />public static final int <wbr />num <wbr />= 50; <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 星星数目
<wbr />boolean <wbr /> <wbr /> <wbr /> <wbr /> <wbr />twinkle = true; <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 闪烁的星星
<wbr />boolean <wbr /> <wbr /> <wbr /> <wbr /> <wbr />key;
<wbr />public Star[] <wbr /> <wbr /> <wbr />star <wbr /> <wbr />= new Star[num]; <wbr />// 存放星星的数组
<wbr />float <wbr /> <wbr /> <wbr /> <wbr /> <wbr />zoom <wbr /> <wbr />= -10.0f; <wbr /> <wbr /> <wbr /> <wbr />// 星星离观察者的距离
<wbr />float <wbr /> <wbr /> <wbr /> <wbr /> <wbr />tilt <wbr /> <wbr />= 90.0f; <wbr /> <wbr /> <wbr /> <wbr />// 星星的倾角
<wbr />float <wbr /> <wbr /> <wbr /> <wbr /> <wbr />spin; <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 闪烁星星的自转 <wbr />
<wbr />int one = 0x10000;
<wbr />Random random = new Random();
<wbr />int <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr />texture; <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 纹理
<wbr />
<wbr />IntBuffer coord = IntBuffer.wrap(new int[]{
<wbr /> <wbr /> <wbr />0,0,
<wbr /> <wbr /> <wbr />one,0,
<wbr /> <wbr /> <wbr />one,one,
<wbr /> <wbr /> <wbr />0,one,
<wbr />});
<wbr />IntBuffer vertexs = IntBuffer.wrap(new int[]{
<wbr /> <wbr /> <wbr />-one,-one,0,
<wbr /> <wbr /> <wbr />one,-one,0,
<wbr /> <wbr /> <wbr />one,one,0,
<wbr /> <wbr /> <wbr />-one,one,0,
<wbr />});
<wbr />ByteBuffer indices = ByteBuffer.wrap(new byte[]{
<wbr /> <wbr /> <wbr />1, 0, 2, 3
<wbr />});
<wbr />
<wbr />@Override
<wbr />public void onDrawFrame(GL10 gl)
<wbr />{
<wbr /> <wbr />
<wbr /> <wbr />gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 清除屏幕和深度缓存
<wbr /> <wbr />gl.glBindTexture(GL10.GL_TEXTURE_2D, texture); <wbr /> <wbr />// 选择纹理

<wbr /> <wbr />for (int i=0; i&lt;num; i++) <wbr /> <wbr /> <wbr /> <wbr />// 循环设置所有的星星
<wbr /> <wbr />{
<wbr /> <wbr /> <wbr />gl.glLoadIdentity(); <wbr /> <wbr /> <wbr /> <wbr />// 绘制每颗星星之前,重置模型观察矩阵
<wbr /> <wbr /> <wbr />gl.glTranslatef(0.0f,0.0f,zoom); <wbr /> <wbr /> <wbr />// 深入屏幕里面
<wbr /> <wbr /> <wbr />gl.glRotatef(tilt,1.0f,0.0f,0.0f); <wbr /> <wbr /> <wbr />// 倾斜视角
<wbr /> <wbr /> <wbr />gl.glRotatef(star[i].angle,0.0f,1.0f,0.0f); <wbr />// 旋转至当前所画星星的角度
<wbr /> <wbr /> <wbr />gl.glTranslatef(star[i].dist,0.0f,0.0f); <wbr />// 沿X轴正向移动
<wbr /> <wbr /> <wbr />gl.glRotatef(-star[i].angle,0.0f,1.0f,0.0f); <wbr />// 取消当前星星的角度
<wbr /> <wbr /> <wbr />gl.glRotatef(-tilt,1.0f,0.0f,0.0f); <wbr /> <wbr />// 取消屏幕倾斜

<wbr /> <wbr /> <wbr />//设置定点数组
<wbr /> <wbr /> <wbr />gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
<wbr /> <wbr /> <wbr />//设置颜色数组
<wbr /> <wbr /> <wbr />gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
<wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr />gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
<wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr />if (twinkle) <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 启用闪烁效果
<wbr /> <wbr /> <wbr />{
<wbr /> <wbr /> <wbr /> <wbr />// 使用byte型数值指定一个颜色
<wbr /> <wbr /> <wbr /> <wbr />gl.glColor4f((float)star[(num-i)-1].r/255.0f,(float)star[(num-i)-1].g/255.0f,(float)star[(num-i)-1].b/255.0f,1.0f);
<wbr /> <wbr /> <wbr /> <wbr />gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertexs);
<wbr /> <wbr /> <wbr /> <wbr />gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, coord);
<wbr /> <wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr /> <wbr />{
<wbr /> <wbr /> <wbr /> <wbr /> <wbr />coord.position(0);
<wbr /> <wbr /> <wbr /> <wbr /> <wbr />vertexs.position(0);
<wbr /> <wbr /> <wbr /> <wbr /> <wbr />indices.position(0);
<wbr /> <wbr /> <wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr /> <wbr /> <wbr />gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 4, GL10.GL_UNSIGNED_BYTE, indices);
<wbr /> <wbr /> <wbr /> <wbr />}
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> //绘制结束
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> gl.glFinish();
<wbr /> <wbr /> <wbr />}

<wbr /> <wbr /> <wbr />gl.glRotatef(spin,0.0f,0.0f,1.0f); <wbr /> <wbr /> <wbr />// 绕z轴旋转星星
<wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr />// 使用byte型数值指定一个颜色
<wbr /> <wbr /> <wbr />gl.glColor4f((float)star[(num-i)-1].r/255.0f,(float)star[(num-i)-1].g/255.0f,(float)star[(num-i)-1].b/255.0f,1.0f);
<wbr /> <wbr /> <wbr />gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertexs);
<wbr /> <wbr /> <wbr />gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, coord);
<wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr />{
<wbr /> <wbr /> <wbr /> <wbr />coord.position(0);
<wbr /> <wbr /> <wbr /> <wbr />vertexs.position(0);
<wbr /> <wbr /> <wbr /> <wbr />indices.position(0);
<wbr /> <wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr /> <wbr />gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 4, GL10.GL_UNSIGNED_BYTE, indices);
<wbr /> <wbr /> <wbr />}
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> //绘制正方形结束
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> gl.glFinish();
<wbr /> <wbr /> <wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> //取消顶点数组
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
<wbr /> <wbr /> <wbr /> <wbr /> <wbr /> gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
<wbr /> <wbr /> <wbr /> <wbr /> <wbr />
<wbr /> <wbr /> <wbr />spin+=0.01f; <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 星星的公转
<wbr /> <wbr /> <wbr />star[i].angle+=(float)(i)/(float)num; <wbr /> <wbr />// 改变星星的自转角度
<wbr /> <wbr /> <wbr />star[i].dist-=0.01f; <wbr /> <wbr /> <wbr /> <wbr />// 改变星星离中心的距离

<wbr /> <wbr /> <wbr />if (star[i].dist&lt;0.0f) <wbr /> <wbr /> <wbr />// 星星到达中心了么
<wbr /> <wbr /> <wbr />{
<wbr /> <wbr /> <wbr /> <wbr />star[i].dist+=5.0f; <wbr /> <wbr /> <wbr />// 往外移5个单位
<wbr /> <wbr /> <wbr /> <wbr />star[i].r=random.nextInt(256); <wbr /> <wbr />// 赋一个新红色分量
<wbr /> <wbr /> <wbr /> <wbr />star[i].g=random.nextInt(256); <wbr /> <wbr />// 赋一个新绿色分量
<wbr /> <wbr /> <wbr /> <wbr />star[i].b=random.nextInt(256); <wbr /> <wbr />// 赋一个新蓝色分量
<wbr /> <wbr /> <wbr />}

<wbr /> <wbr />}
<wbr />}

<wbr />@Override
<wbr />public void onSurfaceChanged(GL10 gl, int width, int height)
<wbr />{
<wbr /> <wbr />float ratio = (float) width / height;
<wbr /> <wbr />//设置OpenGL场景的大小
<wbr /> <wbr />gl.glViewport(0, 0, width, height);
<wbr /> <wbr />//设置投影矩阵
<wbr /> <wbr />gl.glMatrixMode(GL10.GL_PROJECTION);
<wbr /> <wbr />//重置投影矩阵
<wbr /> <wbr />gl.glLoadIdentity();
<wbr /> <wbr />// 设置视口的大小
<wbr /> <wbr />gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
<wbr /> <wbr />// 选择模型观察矩阵
<wbr /> <wbr />gl.glMatrixMode(GL10.GL_MODELVIEW); <wbr />
<wbr /> <wbr />// 重置模型观察矩阵
<wbr /> <wbr />gl.glLoadIdentity();
<wbr />}

<wbr />@Override
<wbr />public void onSurfaceCreated(GL10 gl, EGLConfig config)
<wbr />{
<wbr /> <wbr />gl.glShadeModel(GL10.GL_SMOOTH); <wbr /> <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 启用阴影平滑
<wbr /> <wbr />gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 黑色背景
<wbr /> <wbr />gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); <wbr /> <wbr /> <wbr />// 告诉系统对透视进行修正
<wbr /> <wbr />
<wbr /> <wbr />IntBuffer buffer = IntBuffer.allocate(1);
<wbr /> <wbr />// 创建一个纹理
<wbr /> <wbr />gl.glGenTextures(1, buffer);
<wbr /> <wbr />texture = buffer.get();
<wbr /> <wbr />// 创建一个线性滤波纹理
<wbr /> <wbr />gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
<wbr /> <wbr />gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
<wbr /> <wbr />gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
<wbr /> <wbr />GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap, 0);
<wbr /> <wbr />
<wbr /> <wbr />
<wbr /> <wbr />gl.glEnable(GL10.GL_TEXTURE_2D); <wbr /> <wbr /> <wbr /> <wbr />// 启用纹理映射
<wbr /> <wbr />gl.glShadeModel(GL10.GL_SMOOTH); <wbr /> <wbr /> <wbr /> <wbr />// 启用阴影平滑
<wbr /> <wbr />gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); <wbr /> <wbr /> <wbr />// 黑色背景
<wbr /> <wbr />gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); <wbr />// 真正精细的透视修正
<wbr /> <wbr />gl.glBlendFunc(GL10.GL_SRC_ALPHA,GL10.GL_ONE); <wbr /> <wbr /> <wbr />// 设置混色函数取得半透明效果
<wbr /> <wbr />gl.glEnable(GL10.GL_BLEND); <wbr /> <wbr /> <wbr /> <wbr /> <wbr />// 启用混色

<wbr /> <wbr />for (int i=0; i&lt;num; i++) <wbr /> <wbr /> <wbr /> <wbr />// 创建循环设置全部星星
<wbr /> <wbr />{
<wbr /> <wbr /> <wbr />Star starTMP = new Star();
<wbr /> <wbr /> <wbr />starTMP.angle=0.0f; <wbr /> <wbr /> <wbr /> <wbr />// 所有星星都从零角度开始
<wbr /> <wbr /> <wbr />starTMP.dist=((float)(i)/(float)num)*5.0f; <wbr /> <wbr />// 计算星星离中心的距离
<wbr /> <wbr /> <wbr />starTMP.r=random.nextInt(256); <wbr /> <wbr /> <wbr />// 为star[loop]设置随机红色分量
<wbr /> <wbr /> <wbr />starTMP.g=random.nextInt(256); <wbr /> <wbr /> <wbr />// 为star[loop]设置随机红色分量
<wbr /> <wbr /> <wbr />starTMP.b=random.nextInt(256); <wbr /> <wbr /> <wbr />// 为star[loop]设置随机红色分量
<wbr /> <wbr /> <wbr />star[i] = starTMP;
<wbr /> <wbr />}
<wbr />}

<wbr />public boolean onKeyUp(int keyCode, KeyEvent event)
<wbr />{
<wbr /> <wbr />twinkle=!twinkle;
<wbr /> <wbr />return false;
<wbr />}
}
class Star
{
<wbr />int <wbr /> <wbr />r, g, b; <wbr />// 星星的颜色
<wbr />float <wbr />dist; <wbr /> <wbr />// 星星距离中心的距离
<wbr />float <wbr />angle <wbr />= 0.0f;// 当前星星所处的角度
}

<wbr />

public class MainActivity extends Activity {
<wbr />GLRender render = new GLRender();
<wbr />@Override
<wbr />public void onCreate(Bundle savedInstanceState)
<wbr />{
<wbr /> <wbr />super.onCreate(savedInstanceState);
<wbr /> <wbr />GLImage.load(this.getResources());
<wbr /> <wbr />GLSurfaceView glView = new GLSurfaceView(this);
<wbr /> <wbr />
<wbr /> <wbr />glView.setRenderer(render);
<wbr /> <wbr />setContentView(glView);
<wbr />}
}
class GLImage
{
<wbr />public static Bitmap mBitmap;
<wbr />public static void load(Resources resources)
<wbr />{
<wbr /> <wbr />mBitmap = BitmapFactory.decodeResource(resources, R.drawable.star);
<wbr />}
}

 

[转载]Android OpenGL教程-第六课 - onicewalk的专栏 - 博客频道 - CSDN.NET

mikel阅读(897)

来源: [转载]Android OpenGL教程-第六课 – onicewalk的专栏 – 博客频道 – CSDN.NET

Android OpenGL 教程

第六课

纹理映射:

 

在这一课里,我将教会你如何把纹理映射到立方体的六个面。

 

激动的时刻来了,加载图片了。

复习一下Android加载图片的知识。放一个png到drawable里面。添加一个工具类,方便我们使用。


package com.xinli;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class DataManage {

private static Bitmap mBitmap;

public static void init(Resources res){
mBitmap = BitmapFactory.decodeResource(res, R.drawable.nehe);
}

public static Bitmap getBitmap(){
return mBitmap;
}
}

这样我们是不是可以直接用

Bitmap mBitmap = DataManage.getBitmap();

来获得这个bitmap了,当然需要在activity里面初始化这个DataManage。

DataManage.init(this.getResources());

 

好了,开始把bitmap放到opengl里的纹理里面。

IntBuffer intBuffer = IntBuffer.allocate(1);

gl.glGenTextures(1, intBuffer);

首先让opengl准备些纹理,这里我们准备1个。glGenTextures第二个参数要求是IntBuffer,实际上就是一个int数组的变形,allocate几个就有几个纹理。

 

texture = intBuffer.get();

取得opengl准备的纹理,为了后面把图片绑定到这个纹理里面

 

gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);

开始绑定这个2D纹理

Bitmap mBitmap = DataManage.getBitmap();

GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);

这一句才重要,此纹理是一个2D纹理 ( GL_TEXTURE_2D )。参数二代表图像的详细程度,通常就由它为零去了。参数三是数据的成分数。参数四是边框的值,一般就是“0”。据说openggl_es不支持纹理边界,所以必须设置为0。

 

gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);

gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

 

下面的两行告诉OpenGL在显示图像时,当它比放大得原始的纹理大 ( GL_TEXTURE_MAG_FILTER )或缩小得比原始得纹理小( GL_TEXTURE_MIN_FILTER )时OpenGL采用的滤波方式。通常这两种情况下我都采用 GL_LINEAR 。这使得纹理从很远处到离屏幕很近时都平滑显示。使用 GL_LINEAR 需要CPU和显卡做更多的运算。如果您的机器很慢,您也许应该采用 GL_NEAREST 。过滤的纹理在放大的时候,看起来马赛克的很。您也可以结合这两种滤波方式。在近处时使用 GL_LINEAR ,远处时 GL_NEAREST 。

 

 

有了纹理咋样弄的立方体上去呢,这里要用到纹理坐标:

先看纹理坐标数组

private float[] mTextCoordArray={

1.0f,0.0f,0.0f,0.0f,

0.0f,1.0f,1.0f,1.0f,

0.0f,0.0f,0.0f,1.0f,

1.0f,1.0f,1.0f,0.0f,

1.0f,1.0f,1.0f,0f,

0f,0f,0f,1.0f,

0,1.0f,1.0f,1.0f,

1.0f,0f,0f,0f,

0f,0f,0f,1.0f,
1.0f,1.0f,1.0f,0f,

1.0f,0f,0f,0f,

0f,1.0f,1.0f,1.0f

};

 

private FloatBuffer mTextCoordBuffer;

纹理的坐标就是用了把纹理贴到面上的坐标的对应关系

纹理的坐标是

左下角 0,0

左上角 0,1

右下角 1,0

右上角 1,1

 

这里面弄了12个面,表示六变形的12个面都画纹理。

 

OnDrawFrame里面添加的代码如下


gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//设置使用纹理数组
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mQuadsBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextCoordBuffer);
//把纹理数组指定到纹理buffer