Android开发笔记(一百五十七)使用OpenGL实现翻书动画

上一篇文章介绍了如何通过纹理渲染绘制地球仪,当然OpenGL的三维图形处理能力是很强大的,只要善于利用OpenGL,就能很方便地虚拟各种现实生活中的动画效果。本文再来谈谈使用OpenGL实现浏览电子书时候的翻书动画。

博主早期的博文《 Android开发笔记(十八)书籍翻页动画》已经介绍了如何通过贝塞尔曲线实现翻书动画的过程,不过该方式展示动画时存在卡顿的现象,并且在书页范围之外还会经常拖着长长的影子,实在是有碍观瞻。现在有了OpenGL,借助三维图形技术能够让翻书动画显得更为平滑、更加逼真。正好博主偶然间淘到了一个外国人写的OpenGL翻书动画,感觉显示效果还不错,故而简单改造了一下贡献出来,方便有需要的朋友。

通过OpenGL描绘三维图形的原理,可参见前面几篇文章,这里就不啰嗦了,下面直接观看使用OpenGL实现翻书动画的效果。
首先是从前往后翻页的效果动画:


然后是从后往前翻页的效果动画:


怎么样,还比较流畅吧,其实就是翻书的时候把图片展示为翻卷的立体效果罢了。
具体的Activity实现代码如下所示:
public class GlTurnActivity extends Activity {
	private final static String TAG = "GlTurnActivity";
	private CurlView cv_content;
	private String[] imgArray = {"000.jpg", "001.jpg", "002.jpg", "003.jpg"};
	private int cv_height;
	private ArrayList<String> imgList = new ArrayList<String>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_gl_turn);
		cv_content = (CurlView) findViewById(R.id.cv_content);
		copyImage();
		showImage();
	}
	
	// 把图片文件从assets目录复制到SD卡
	private void copyImage() {
		cv_height = cv_content.getMeasuredHeight();
        String dir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
        for (int i=0; i<imgArray.length; i++) {
        	String imgName = imgArray[i];
        	String imgPath = dir + imgName;
        	AssetsUtil.Assets2Sd(this, imgName, imgPath);
        	imgList.add(imgPath);
        	if (i == 0) {
        		Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
        		cv_height = (int) (bitmap.getHeight() * 1.2);
        	}
        }
	}
	
	// 载入并显示书籍的图片,一开始显示第一页
	private void showImage() {
		LayoutParams params = cv_content.getLayoutParams();
		params.height = cv_height;
		cv_content.setLayoutParams(params);
		cv_content.setPageProvider(new PageProvider(imgList));
		cv_content.setSizeChangedObserver(new SizeChangedObserver());
		cv_content.setCurrentIndex(0);
		cv_content.setBackgroundColor(Color.LTGRAY);
	}

	// 定义页面的提供者,传入图片文件的路径数组
	private class PageProvider implements CurlView.PageProvider {
		private ArrayList<String> mPathArray = new ArrayList<String>();
		
		public PageProvider(ArrayList<String> pathArray) {
			mPathArray = pathArray;
		}
		
		@Override
		public int getPageCount() {
			return mPathArray.size();
		}

		private Bitmap loadBitmap(int width, int height, int index) {
			Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
			b.eraseColor(0xFFFFFFFF);
			Canvas c = new Canvas(b);
			//Drawable d = getResources().getDrawable(mBitmapIds[index]);
			Bitmap image = BitmapFactory.decodeFile(mPathArray.get(index));
			BitmapDrawable d = new BitmapDrawable(getResources(), image);

			int margin = 0;
			int border = 1;
			Rect r = new Rect(margin, margin, width - margin, height - margin);

			int imageWidth = r.width() - (border * 2);
			int imageHeight = imageWidth * d.getIntrinsicHeight() / d.getIntrinsicWidth();
			if (imageHeight > r.height() - (border * 2)) {
				imageHeight = r.height() - (border * 2);
				imageWidth = imageHeight * d.getIntrinsicWidth() / d.getIntrinsicHeight();
			}

			r.left += ((r.width() - imageWidth) / 2) - border;
			r.right = r.left + imageWidth + border + border;
			r.top += ((r.height() - imageHeight) / 2) - border;
			r.bottom = r.top + imageHeight + border + border;

			Paint p = new Paint();
			p.setColor(0xFFC0C0C0);
			c.drawRect(r, p);
			r.left += border;
			r.right -= border;
			r.top += border;
			r.bottom -= border;

			d.setBounds(r);
			d.draw(c);
			return b;
		}

		@Override
		public void updatePage(CurlPage page, int width, int height, int index) {
			Bitmap front = loadBitmap(width, height, index);
			page.setTexture(front, CurlPage.SIDE_BOTH);
		}
	}

	// 定义书籍尺寸的变化监听器
	private class SizeChangedObserver implements CurlView.SizeChangedObserver {
		@Override
		public void onSizeChanged(int w, int h) {
			cv_content.setViewMode(CurlView.SHOW_ONE_PAGE);
			cv_content.setMargins(0f, 0f, 0f, 0f);
		}
	}

}

完整的工程代码见博主的github,该工程的demo地址为 https://github.com/aqi00/note/tree/master/ExmOpenGL


点此查看Android开发笔记的完整目录
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Java代码示例,演示如何在Android使用OpenGL实现逐帧动画的播放效果: ```java public class MyGLRenderer implements GLSurfaceView.Renderer { private Context mContext; private int[] mTextures; private int mCurrentFrame = 0; private int mFrameCount; private int mFrameWidth; private int mFrameHeight; public MyGLRenderer(Context context, int frameCount, int frameWidth, int frameHeight) { mContext = context; mFrameCount = frameCount; mFrameWidth = frameWidth; mFrameHeight = frameHeight; mTextures = new int[frameCount]; } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // 初始化OpenGL ES gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); // 加载动画帧图像资源 for (int i = 0; i < mFrameCount; i++) { Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.frame_1 + i); gl.glGenTextures(1, mTextures, i); gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[i]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); bitmap.recycle(); } } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // 设置视口大小 gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluOrtho2D(gl, 0, width, 0, height); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); } @Override public void onDrawFrame(GL10 gl) { // 绘制纹理 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[mCurrentFrame]); float ratio = (float) mFrameWidth / mFrameHeight; gl.glPushMatrix(); gl.glTranslatef((gl.glGetParameter(GL10.GL_VIEWPORT, 0) - mFrameWidth) / 2, (gl.glGetParameter(GL10.GL_VIEWPORT, 1) - mFrameHeight) / 2, 0); gl.glScalef(Math.min(gl.glGetParameter(GL10.GL_VIEWPORT, 2) / (float) mFrameWidth, gl.glGetParameter(GL10.GL_VIEWPORT, 3) / (float) mFrameHeight), Math.min(gl.glGetParameter(GL10.GL_VIEWPORT, 2) / (float) mFrameWidth, gl.glGetParameter(GL10.GL_VIEWPORT, 3) / (float) mFrameHeight) * ratio, 1); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); float vertices[] = {0, 0, 0, mFrameHeight, mFrameWidth, mFrameHeight, mFrameWidth, 0}; gl.glVertexPointer(2, GL10.GL_FLOAT, 0, FloatBuffer.wrap(vertices)); float texCoords[] = {0, 0, 0, 1, 1, 1, 1, 0}; gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, FloatBuffer.wrap(texCoords)); gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glPopMatrix(); // 更新当前显示的纹理 mCurrentFrame = (mCurrentFrame + 1) % mFrameCount; } } ``` 你可以将以上代码添加到你的Android项目中,并根据实际需求进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值