Android多媒体之GLES2战记第六集--九层之台

栏目: IOS · Android · 发布时间: 5年前

内容简介:旁白:上集说到:勇者....张风捷特烈(抢话筒):废话不多说,观看此篇,先把拿出草稿纸,自己画一画,抛开书本(发现那本书的画法思路不怎么样,不优雅)

旁白:上集说到:勇者....

张风捷特烈(抢话筒):废话不多说,观看此篇,先把 笔和草稿纸 拿出来,这非常重要!

第九副本: 擎天之柱

拿出草稿纸,自己画一画,抛开书本(发现那本书的画法思路不怎么样,不优雅)

咱们来自己算,自己画,该副本的代码在 shape/part ,琐碎的小点就省去了

一路走到这里,套路基本上都一样,本文研究的只是图形画法,基本用法不会的就前补吧

1.第一关卡: GL_TRIANGLES画圆

Android多媒体之GLES2战记第六集--九层之台

1.1:顶点的计算

Android多媒体之GLES2战记第六集--九层之台
/**
     * 初始化顶点坐标数据的方法
     *
     * @param r          半径
     * @param splitCount 切分的份数
     */
    public void initVertex(float r, int splitCount) {
        float dθ = 360.0f / splitCount;//顶角的度数
        vertexCount = 3 * splitCount;//顶点个数,共有n个三角形,每个三角形都有三个顶点
        float[] vertices = new float[vertexCount * 3];//坐标数据
        
        for (int v = 0, t = 0; v < vertexCount; v += 3, t += 3) {
            int n = v / 3;
            vertices[3 * v] = 0;//顶点坐标:p0
            vertices[3 * v + 1] = 0;
            vertices[3 * v + 2] = 0;
            vertices[3 * v + 3] = r * cos(n * dθ);//顶点坐标:p1
            vertices[3 * v + 4] = r * sin(n * dθ);
            vertices[3 * v + 5] = 0;
            vertices[3 * v + 6] = r * cos((n + 1) * dθ);//顶点坐标:p2
            vertices[3 * v + 7] = r * sin((n + 1) * dθ);
            vertices[3 * v + 8] = 0;
        }
    }
复制代码

1.2:贴图坐标的计算

Android多媒体之GLES2战记第六集--九层之台
for (int v = 0, t = 0; v < vertexCount; v += 3, t += 3) {
    int n = v / 3;
    //顶点坐标计算同上, 略 ....
    textures[2 * t] = 0.5f;//贴图:p0
    textures[2 * t + 1] = 0.5f;
    textures[2 * t + 2] = 0.5f + 0.5f * r * cos(n * dθ);//贴图:p1
    textures[2 * t + 3] = 0.5f - 0.5f * r * sin(n * dθ);
    textures[2 * t + 4] = 0.5f + 0.5f * r * cos((n + 1) * dθ);//贴图:p2
    textures[2 * t + 5] = 0.5f - 0.5f * r * sin((n + 1) * dθ);
}
复制代码

2.第二关卡:圆柱侧面

Android多媒体之GLES2战记第六集--九层之台
Android多媒体之GLES2战记第六集--九层之台
/**
  * 圆柱侧面
  * @param r          半径
  * @param h          高度
  * @param splitCount 切分的份数
  */
 public void initVertex(float r, float h, int splitCount) {
     float dθ = 360.0f / splitCount;
     vertexCount = splitCount * 4 * 3;//顶点个数,共有3*splitCount*4个三角形,每个三角形都有三个顶点
     //坐标数据初始化
     float[] vertices = new float[vertexCount * 3];
     float[] textures = new float[vertexCount * 2];//顶点纹理S、T坐标值数组

     for (int v = 0, t = 0; v < vertexCount; v += 6, t += 6) {
         int n = v / 6;
         float x = r * cos(n * dθ);
         float xNext = r * cos(n * dθ + dθ);
         float z = -r * sin(n * dθ);
         float zNext = -r * sin(n * dθ + dθ);

         vertices[3 * v + 0] = x;//底部p0
         vertices[3 * v + 1] = 0;
         vertices[3 * v + 2] = z;
         vertices[3 * v + 3] = xNext;//顶部p2
         vertices[3 * v + 4] = h;
         vertices[3 * v + 5] = zNext;
         vertices[3 * v + 6] = x;//顶部p1
         vertices[3 * v + 7] = h;//y
         vertices[3 * v + 8] = z;//z

         vertices[3 * v + 9] = x;//底部p0
         vertices[3 * v + 10] = 0;
         vertices[3 * v + 11] = z;
         vertices[3 * v + 12] = xNext;//底部p3
         vertices[3 * v + 13] = 0;//y
         vertices[3 * v + 14] = zNext;//z
         vertices[3 * v + 15] = xNext;//顶部p2
         vertices[3 * v + 16] = h;//y
         vertices[3 * v + 17] = zNext;//z

         float s = n * dθ / 360.f;
         float sNext = (n + 1) * dθ / 360.f;
         textures[2 * t + 0] = s;//贴图:p0
         textures[2 * t + 1] = 1;
         textures[2 * t + 2] = sNext;//贴图:p2
         textures[2 * t + 3] = 0;
         textures[2 * t + 4] = s;//贴图:p1
         textures[2 * t + 5] = 0;

         textures[2 * t + 6] = s;//贴图:p0
         textures[2 * t + 7] = 1;
         textures[2 * t + 8] = sNext;//贴图:p3
         textures[2 * t + 9] = 1;
         textures[2 * t + 10] = sNext;//贴图:p2
         textures[2 * t + 11] = 0;
     }

     //法向量数据初始化
     float[] normals = new float[vertices.length];
     for (int i = 0; i < vertices.length; i++) {
         if (i % 3 == 1) {
             normals[i] = 0;
         } else {
             normals[i] = vertices[i];
         }
     }
     vertexBuffer = GLUtil.getFloatBuffer(vertices);
     mNormalBuffer = GLUtil.getFloatBuffer(normals);
     mTexCoorBuffer = GLUtil.getFloatBuffer(textures);
 }
复制代码
Android多媒体之GLES2战记第六集--九层之台

侧面旋转90°

Android多媒体之GLES2战记第六集--九层之台

3.第三关卡:圆柱的拼接

Android多媒体之GLES2战记第六集--九层之台

3.1:移动和旋转的辅助方法 MatrixStack

将MatrixStack在保存状态下重置,再进行变换操作,最后restore,感觉用着蛮不错的

/**
 * 设置沿xyz轴移动 注意:本方法和restore联合使用
 *
 * @param x 移动的 x 分量
 * @param y 移动的 y 分量
 * @param z 移动的 z 分量
 */
public static void reTranslate(float[] target, float x, float y, float z) {
    save();
    reset();
    Matrix.translateM(MatrixStack.getOpMatrix(), 0, target, 0,
            x, y, z);
}
/**
 * 设置沿(x,y,z)点旋转 注意:本方法和restore联合使用
 *
 * @param deg 角度
 * @param x   旋转点的 x 分量
 * @param y   旋转点的 y 分量
 * @param z   旋转点的 z 分量
 */
public static void reRotate(float[] target, float deg, float x, float y, float z) {
    save();
    reset();
    Matrix.rotateM(MatrixStack.getOpMatrix(), 0, target, 0,
            deg, x, y, z);
}
复制代码

3.2:三块拼型: Cylinder.java

这个比较简单,圆和侧面都有了,拼起来就行了

/**
 * 作者:张风捷特烈<br/>
 * 时间:2019/1/16/016:19:22<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:圆柱类
 */
public class Cylinder extends RendererAble {
    private final Circle mBottomCircle;//底圆
    private final Circle mTopCircle;//顶圆
    private final CylinderSide mCylinderSide;
    private float mH;
    /**
     * @param context     上下文
     * @param h           高
     * @param r           底面半径
     * @param splitCount  切割数
     * @param textureIdX3 贴图id 上、下、周围贴图
     */
    public Cylinder(Context context, float r, float h, int splitCount, int[] textureIdX3) {

        super(context);
        if (textureIdX3.length != 3) {
            throw new IllegalArgumentException("the length of textureIdX3 must be 3");
        }
        mH = h;
        mBottomCircle = new Circle(context, r, splitCount, textureIdX3[0]);
        mTopCircle = new Circle(context, r, splitCount, textureIdX3[1]);
        mCylinderSide = new CylinderSide(mContext, r, h, splitCount, textureIdX3[2]);
    }

    @Override
    public void draw(float[] mvpMatrix) {
        MatrixStack.reTranslate(mvpMatrix, 0, 0, mH);
        mTopCircle.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();
        
        MatrixStack.reRotate(mvpMatrix, 90, 1, 0, 0);
        mCylinderSide.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();
        
        mBottomCircle.draw(mvpMatrix);
    }
}

复制代码

第十副本: 钻天之锥

其他立体图形的思路基本一致,就是寻找三角形坐标、贴图坐标、法向量坐标

其中法向量坐标是和光照相关的,这里暂时不讨论,后面光照会详细讨论

写了这么多感觉重复的代码很多,抽取了一个父类 EvnRender 来做一些通用的事 它的孩子只需在意:三角形坐标、贴图坐标、法向量坐标三个数组即可

Android多媒体之GLES2战记第六集--九层之台

1.第一关卡: GL_TRIANGLE_FAN绘制 三角形,拼合圆形

好处:顶点少 以前是: 3*splitCount ,现在是 splitCount+2

Android多媒体之GLES2战记第六集--九层之台
Android多媒体之GLES2战记第六集--九层之台
/**
 * 初始化顶点坐标数据的方法
 *
 * @param r          半径
 * @param splitCount 切分的份数
 */
public void initVertex(float r, int splitCount) {
    float dθ = 360.0f / splitCount;//顶角的度数
    int vertexCount = splitCount + 2;//顶点个数,共有n个三角形,每个三角形都有三个顶点
    float[] vertices = new float[vertexCount * 3];//坐标数据
    float[] textures = new float[vertexCount * 2];//顶点纹理S、T坐标值数组
    vertices[0] = 0;
    vertices[1] = 0;
    vertices[2] = 0;
    textures[0] = 0.5f;
    textures[1] = 0.5f;
    for (int n = 1; n < vertexCount; n++) {
        //顶点坐标
        vertices[n * 3 + 0] = r * cos((n - 1) * dθ);//x
        vertices[n * 3 + 1] = r * sin((n - 1) * dθ);//y
        vertices[n * 3 + 2] = 0;//z
        //纹理坐标
        textures[2 * n] = 0.5f + 0.5f * cos((n - 1) * dθ);
        textures[2 * n + 1] = 0.5f - 0.5f * sin((n - 1) * dθ);
    }
}
复制代码

2.第二关卡: 圆锥侧面方式一:GL_TRIANGLES

Android多媒体之GLES2战记第六集--九层之台
/**
 * 初始化顶点
 * @param r          半径
 * @param h          高度
 * @param splitCount 切分的份数
 */
public void initVertexData(float r, float h, int splitCount) {
    float dθ = 360.0f / splitCount;
    int vCount = splitCount * 3;//顶点个数,共有3*splitCount*4个三角形,每个三角形都有三个顶点
    //坐标数据初始化
    float[] vertices = new float[vCount * 3];
    float[] textures = new float[vCount * 2];//顶点纹理S、T坐标值数组
    float[] normals = new float[vertices.length];//法向量数组
    for (int v = 0, t = 0; v < vCount; v += 3, t += 3) {
        int n = v / 3;
        float x = r * cos(n * dθ);
        float xNext = r * cos(n * dθ + dθ);
        float z = r * sin(n * dθ);
        float zNext = r * sin(n * dθ + dθ);
        //顶点坐标
        vertices[3 * v + 0] = 0;//p0
        vertices[3 * v + 1] = h;
        vertices[3 * v + 2] = 0;
        vertices[3 * v + 3] = x;//p1
        vertices[3 * v + 4] = 0;
        vertices[3 * v + 5] = z;
        vertices[3 * v + 6] = xNext;//p2
        vertices[3 * v + 7] = 0;
        vertices[3 * v + 8] = zNext;
        //纹理坐标
        float s = n * dθ / 360.f;
        float sNext = (n + 1) * dθ / 360.f;
        textures[2 * t + 0] = 0.5f;//p0
        textures[2 * t + 1] = 0f;
        textures[2 * t + 2] = s;//p1
        textures[2 * t + 3] = 1f;
        textures[2 * t + 4] = sNext;//p2
        textures[2 * t + 5] = 1f;
    }
}
复制代码

3.第三关卡: 圆锥侧面方式二:GL_TRIANGLE_FAN

省顶点,而且写起来简单

/**
 * 初始化顶点
 *
 * @param r          半径
 * @param h          高度
 * @param splitCount 切分的份数
 */
public void initVertexData(float r, float h, int splitCount) {
    float dθ = 360.0f / splitCount;
    int vCount = splitCount + 2;//顶点个数,共有3*splitCount*4个三角形,每个三角形都有三个顶点
    //坐标数据初始化
    float[] vertices = new float[vCount * 3];
    float[] textures = new float[vCount * 2];//顶点纹理S、T坐标值数组
    float[] normals = new float[vertices.length];//法向量数组
    //顶点坐标
    vertices[0] = 0;//p0
    vertices[1] = h;
    vertices[2] = 0;
    textures[0] = 0.5f;//p0
    textures[1] = 0f;
    for (int n = 1; n < vCount; n++) {
        float x = r * cos(n * dθ);
        float z = r * sin(n * dθ);
        //顶点坐标
        vertices[3 * n + 0] = x;//p1
        vertices[3 * n + 1] = 0;
        vertices[3 * n + 2] = z;
        //纹理坐标
        float s = n * dθ / 360.f;
        textures[2 * n + 0] = s;//p1
        textures[2 * n + 1] = 1f;
    }
}
复制代码

4.第三关卡: 拼接圆锥

Android多媒体之GLES2战记第六集--九层之台
/**
 * 作者:张风捷特烈<br/>
 * 时间:2019/1/16/016:19:22<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:圆锥类
 */
public class Cone extends RenderAble {
    private  CircleFanEvn mBottomCircleTris;//底圆
    private  ConeSideFanEvn mConeSide;//侧面
    private float mH;

    /**
     * @param context     上下文
     * @param h           高
     * @param r           底面半径
     * @param splitCount  切割数
     * @param textureIdX2 贴图id 下、周围贴图
     */
    public Cone(Context context, float r, float h, int splitCount, int[] textureIdX2) {
        super(context);
        if (textureIdX2.length != 2) {
            throw new IllegalArgumentException("the length of textureIdX3 must be 2");
        }
        mH = h;
        mBottomCircleTris = new CircleFanEvn(context, textureIdX2[0], r, splitCount);
        mConeSide = new ConeSideFanEvn(context, textureIdX2[1], r, h,splitCount);
    }


    @Override
    public void draw(float[] mvpMatrix) {
        MatrixStack.reRotate(mvpMatrix, 90, 1, 0, 0);
        mConeSide.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();
        mBottomCircleTris.draw(mvpMatrix);
    }
}
复制代码
Android多媒体之GLES2战记第六集--九层之台

第十一副本: 立方之魔

封装立方,拼合魔方

Android多媒体之GLES2战记第六集--九层之台

1.第一关卡:面封装

Android多媒体之GLES2战记第六集--九层之台
/**
 * 作者:张风捷特烈<br/>
 * 时间:2019/1/17/017:11:28<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:与Y轴组成的面
 */
public class RectangleEvn extends EvnRender {
    public RectangleEvn(Context context, int tId, float x, float y, float z) {
        super(context, tId, GLES20.GL_TRIANGLE_STRIP);
        initVertex(x, y, z);
    }

    private void initVertex(float x, float y, float z) {
        int vertexCount = 4;//顶点个数,共有n个三角形,每个三角形都有三个顶点
        float[] vertices = new float[vertexCount * 3];//坐标数据
        float[] textures = new float[vertexCount * 2];//顶点纹理S、T坐标值数组
        float[] normals = new float[vertices.length];

        //顶点坐标
        vertices[0] = 0;//p0
        vertices[1] = 0;
        vertices[2] = 0;

        vertices[3] = 0;//p1
        vertices[4] = y;
        vertices[5] = 0;

        vertices[6] = x;//p3
        vertices[7] = 0;
        vertices[8] = z;

        vertices[9] = x;//p2
        vertices[10] = y;
        vertices[11] = z;

        //贴图坐标
        textures[0] = 0;//p0
        textures[1] = 1;

        textures[2] = 0;//p1
        textures[3] = 0;

        textures[4] = 1;//p3
        textures[5] = 1;

        textures[6] = 1;//p2
        textures[7] = 0;
        init(vertices, textures, normals);
    }
}
复制代码

2.第二关卡:封装立方

Android多媒体之GLES2战记第六集--九层之台
/**
 * 作者:张风捷特烈<br/>
 * 时间:2019/1/9 0009:20:09<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:贴图立方
 */
public class Cube3d extends RenderAble {
    private final RectangleEvn mRectA;
    private final RectangleEvn mRectB;
    private final RectangleEvn mRectD;
    private final RectangleEvn mRectC;
    private final RectangleEvn mRectE;
    private final RectangleEvn mRectF;

    private float rate;

    private float mX;
    private float mY;
    private float mZ;

    public Cube3d(Context context, float x, float y, float z, int[] textureIdX6) {
        super(context);
        if (textureIdX6.length != 6) {
            throw new IllegalArgumentException("the length of textureIdX3 must be 6");
        }
        mX = x;
        mY = y;
        mZ = z;

        mRectA = new RectangleEvn(mContext, textureIdX6[0], 0, y, z);
        mRectB = new RectangleEvn(mContext, textureIdX6[1], 0, y, z);
        mRectC = new RectangleEvn(mContext, textureIdX6[2], 0, y, z);
        mRectD = new RectangleEvn(mContext, textureIdX6[3], 0, y, z);
        mRectE = new RectangleEvn(mContext, textureIdX6[4], 0, y, z);
        mRectF = new RectangleEvn(mContext, textureIdX6[5], 0, y, z);
    }

    @Override
    public void draw(float[] mvpMatrix) {

        mRectA.draw(mvpMatrix);

        MatrixStack.reTranslate(mvpMatrix, 0, 0, mZ);
        MatrixStack.rotate(90, 0, 1, 0);
        mRectB.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();

        MatrixStack.reTranslate(mvpMatrix, mX, 0, 0);
        MatrixStack.rotate(90, 0, -1, 0);
        mRectD.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();


        MatrixStack.reTranslate(mvpMatrix, 0, 0, 0);
        MatrixStack.rotate(-90, 0, 0, 1);

        MatrixStack.translate(0, 0, mZ);
        MatrixStack.rotate(180, 0, 1, 0);
        mRectF.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();

        MatrixStack.reTranslate(mvpMatrix, 0, mY, 0);
        MatrixStack.rotate(-90, 0, 0, 1);
        mRectE.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();


        MatrixStack.reTranslate(mvpMatrix, mX, 0, mZ);
        MatrixStack.rotate(-180, 0, 1, 0);
        mRectC.draw(MatrixStack.getOpMatrix());
        MatrixStack.restore();
    }

    public void setRate(float rate) {
        this.rate = rate;
    }
}
复制代码

3.第三关卡:拼合魔方

Android多媒体之GLES2战记第六集--九层之台
---->[WorldShape#draw]----------
//立方的偏移数组
 mTrans = new float[]{
         0, 0, 0,
         0, 0, 0.5f,
         0, 0, -0.5f,

         0, 0.5f, 0,
         0, 0.5f, 0.5f,
         0, 0.5f, -0.5f,

         0.5f, 0.5f, 0,
         0.5f, 0.5f, 0.5f,
         0.5f, 0.5f, -0.5f,

         0.5f, 0f, 0,
         0.5f, 0f, 0.5f,
         0.5f, 0f, -0.5f,

         0.5f, -0.5f, 0,
         0.5f, -0.5f, 0.5f,
         0.5f, -0.5f, -0.5f,

         0f, -0.5f, 0,
         0f, -0.5f, 0.5f,
         0f, -0.5f, -0.5f,

         -0.5f, -0.5f, 0,
         -0.5f, -0.5f, 0.5f,
         -0.5f, -0.5f, -0.5f,

         -0.5f, 0f, 0,
         -0.5f, 0f, 0.5f,
         -0.5f, 0f, -0.5f,

         -0.5f, 0.5f, 0,
         -0.5f, 0.5f, 0.5f,
         -0.5f, 0.5f, -0.5f,
 };
 
 
---->[WorldShape#draw]----------

for (int i = 0; i < mTrans.length / 3; i++) {
    MatrixStack.reTranslate(mvpMatrix, mTrans[3 * i], mTrans[3 * i + 1], mTrans[3 * i + 2]);
    mCube3d.draw(MatrixStack.getOpMatrix());
    MatrixStack.restore();
}
复制代码

第十二副本: GLES2战记下季预告

到此,我们已经可以对OpenGL的世界有了简单的认识,如果你和我一路走来

相信你的运算能力和代码控制力以及学习能力都会有一定的提高,之后的路还要自己去走

第一季到此结束: 九层之台,起于累土;千里之行,始于足下 ,切莫眼高手低

下一季(如果有的话)我们再见,临走,丢几个图...自己实现去。

接下来继续原来的多媒体路线。

Android多媒体之GLES2战记第六集--九层之台
Android多媒体之GLES2战记第六集--九层之台
Android多媒体之GLES2战记第六集--九层之台

后记:捷文规范

1.本文成长记录及勘误表

项目源码 日期 备注
V0.1-github 2018-1-17 Android多媒体之GLES2战记第六集--九层之台

2.更多关于我

笔名 QQ 微信 爱好
张风捷特烈 1981462002 zdl1994328 语言
我的github 我的简书 我的掘金 个人网站

3.声明

1----本文由张风捷特烈原创,转载请注明

2----欢迎广大编程爱好者共同交流

3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正

4----看到这里,我在此感谢你的喜欢与支持

Android多媒体之GLES2战记第六集--九层之台

以上所述就是小编给大家介绍的《Android多媒体之GLES2战记第六集--九层之台》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Implementing Responsive Design

Implementing Responsive Design

Tim Kadlec / New Riders / 2012-7-31 / GBP 27.99

New devices and platforms emerge daily. Browsers iterate at a remarkable pace. Faced with this volatile landscape we can either struggle for control or we can embrace the inherent flexibility of the w......一起来看看 《Implementing Responsive Design》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具