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战记第六集--九层之台》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

计算理论导引

计算理论导引

[美]Michael Sipser / 张立昂、王捍贫、黄雄 / 机械工业出版社 / 2000-2 / 30.00元

本书由计算理论领域的知名权威Michael Sipser撰写。他以独特的视角,综合地描述了计算机科学理论,并以清新的笔触、生动的语言给出了宽泛的数学理论,而并非拘泥于某些低层次的技术细节。在证明之前,均有“证明思路”,帮助读者理解数学形式下蕴涵的概念。同样,对于算法描述,均以直观的文字,而非伪代码给出,从而将注意力集中于算法本身,而不是某些模型。本书的内容包括三个部分:自动机与语言、可计算性理论和一起来看看 《计算理论导引》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具