Android DrawBitmapMesh 实现红旗飘扬效果

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class BitMapMeshView extends View {
    private int HEIGHT = 200;
    private int WIDTH = 200;
    private int mHeight = 600;
    private int mWidth = 800;
    private Bitmap mbitmap;
    private int COUNT = (WIDTH + 1) * (HEIGHT + 1);
    private float[] verts = new float[COUNT * 2];  // 因为要保存一个点的个坐标(x,y)那么这个数组长度就要 *2
    private float[] origs = new float[COUNT * 2];
    private float k;

    public BitMapMeshView(Context context) {
        this(context, null);
    }

    public BitMapMeshView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BitMapMeshView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }
    
    // 通用代码
    private void initView() {
        int index = 0;
        mbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog);
        mbitmap = setImgSize(mbitmap, mWidth, mHeight);
        float bitmapwidth = mbitmap.getWidth();
        float bitmapheight = mbitmap.getHeight();
        for (int i = 0; i < HEIGHT + 1; i++) {
            float fy = bitmapwidth / HEIGHT * i;
            for (int j = 0; j < WIDTH + 1; j++) {
                float fx = bitmapheight / WIDTH * j;
                //偶数位记录x坐标  奇数位记录Y坐标
                origs[index * 2 + 0] = verts[index * 2 + 0] = fx;
                origs[index * 2 + 1] = verts[index * 2 + 1] = fy;
                index++;
            }
        }
    }

    // 红旗摆动效果算法
    private void wave() {
        for (int i = 0; i < HEIGHT + 1; i++) {
            for (int j = 0; j < WIDTH + 1; j++) {
                //x坐标不变
                verts[(i * (WIDTH + 1) + j) * 2 + 0] += 0;
                //增加k值是为了让相位产生移动,从而可以飘动起来
                float offset = (float) Math.sin((float) j / WIDTH * 2 * Math.PI + k);
                //y坐标改变,呈现正弦曲线
                verts[(i * (WIDTH + 1) + j) * 2 + 1] = origs[(i * (WIDTH + 1) + j) * 2 + 1] + offset * 50;
            }
        }
        k += 0.4f;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        wave();
        canvas.drawBitmapMesh(mbitmap, WIDTH, HEIGHT, verts, 0, null, 0, null);
        invalidate();
    }

    private void warp(float cx, float cy) {
        for (int i = 0; i < COUNT * 2; i += 2) {
            float dx = cx - origs[i + 0];
            float dy = cy - origs[i + 1];
            float dd = dx * dx + dy * dy;
            //计算每个座标点与当前点(cx、cy)之间的距离
            float d = (float) Math.sqrt(dd);
            //计算扭曲度,距离当前点(cx、cy)越远,扭曲度越小
            float pull = 5000 / ((float) (dd * d));
            //对verts数组(保存bitmap上21 * 21个点经过扭曲后的座标)重新赋值
            if (pull >= 1) {
                verts[i + 0] = cx;
                verts[i + 1] = cy;
            } else {
                //控制各顶点向触摸事件发生点偏移
                verts[i + 0] = origs[i + 0] + dx * pull;
                verts[i + 1] = origs[i + 1] + dy * pull;
            }
        }
        //通知View组件重绘
        invalidate();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //实现红旗飘动效果
        warp(event.getX(), event.getY());
        return true;
    }

    // 调整输入图片的大小
    public Bitmap setImgSize(Bitmap bm, int newWidth, int newHeight) {
        // 获得图片的宽高.
        int width = bm.getWidth();
        int height = bm.getHeight();
        // 计算缩放比例.
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 取得想要缩放的matrix参数.
        Matrix matrix = new Matrix();
        matrix.postScale(scaleHeight, scaleWidth);
        // 得到新的图片.
        Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
        return newbm;
    }

总结:总的来说,就是改变 drawBitmapMesh 的 verts 网格的坐标。来改变图形的网格效果,呈现不同的效果。

绘制飘动的国旗绘制总结 需求 将国旗图片在OpenGL中绘制出来,再实现动效果,最后增加半透明效果实现步骤 1. 首先确定使用分割法将整张图片分割成若干份,画在一个网格组成的长方形中 2. 画出N*N格的方格 3. 将国旗图案贴到这个网格中 a) 计算网格各顶点坐标 Vertex b) 计算各顶点对应的纹理坐标 texcoord c) 计算各顶点所对应的顶点法向量 Normal d) 计算出需要绘制的各顶点的顺序 order 4. 绘制飘动效果 a) 根据正弦曲线,计算出各顶点所对应的深度值 zDepth b) 计算出正弦曲线的波动 i. 坐标点的变动 ii. 顶点法向量坐标值的变动 5. 增加灯光效果 6. 增加材质的效果 遇到的问题 1. 确定网格的密度 网格的密度决定了波动的频率大小 2. 写出绘制的递归方法 开始实现时是通过循环绘制出每一个网格的纹理贴图,组合成整个图像,绘制效率较低且浪费资源较多,而且将图像进行旋转操作的时候会变形,不能达到预想的效果,所以开始对其进行整合 3. 计算各定点坐标时是使用三维数组的形式生成的,较简单,但是OpenGL绘制的时候需要的是buffer形式的,生成buffer时需要的是一维数组,java中没有指针,所以需要自己写个方法把三维数组的内容转换到一维数组中,以求出buffer 4. 生成纹理坐标时比较简单,再生成顶点坐标的同时就可以生成,但是实现后遇到问题,问题贴图是上下颠倒的,所以需要与顶点对应的纹理坐标需要上下转换一下,虽然感觉比较麻烦,但是还是比较容易实现的 5. 计算各顶点所对应的法向量时遇到很大的麻烦,由于长时间没有接触相关的数学知识,对法向量的概念有点生疏了,后来查找资料对法向量的概念进行复习,我写的生成顶点法向量的方法比较麻烦,写了5个方法来实现顶点法向量的计算,最后还是实现了 6. 各顶点顺序的计算,需要按照纹理贴图的相应顺序将顶点顺序确定出来,我用的最笨的方法得的,计算出2*2网格的定点坐标,根据坐标计算出顶点顺序,然后写出求顶点顺序的递归算法实现了顶点顺序的计算 7. 根据正弦曲线求出各点的深度,这个方法并不难写,但是在实现的时候,由于把顶点的顺序计算的有一点问题,画出来的图形在移动时不是按照正弦曲线的规律,使得波动的规律看起来极不自然,后来把顶点的计算改正后,还是比较美观的 8. 计算波动的时候,只需要将顶点的z轴坐标依次移动就可以了,比较容易实现,对于顶点法向量的移动,同样是后一个向前一个依次移动,但是移动的是x、y、z三个变量,我绘制的正好是两个波长的波动曲线,多以可以把第一个先缓存起来,赋值给最后一个即可,如果不是整波长的波动,可以把最后一列的顶点z值和顶点法向量重新计算,但是会影响一定的效率,所以建议整波长的比较好 9. 增加灯光效果和材质属性 由于之前没有接触过,所以先进行了学习,然后再增加,遇到的问题是写增加灯光效果的时候,由于疏忽,三种光效属性中均写成了对环境光的修改,所以多费了些时间;在对材质属性进行增加的时候,由于对混合渲染不熟悉,尤其是对glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);两个参数所影响的色彩混合效果不明确,所以增加半透明效果的这块是试出来的。 10. 在不贴图的情况下,灯光效果比较明显,但是在贴图后,半透明效果有,但是灯光效果看不出来了,这块还没有解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值