OpenGL ES: 画球

来源:互联网 发布:网络拓扑图的简要描述 编辑:程序博客网 时间:2024/06/04 00:44

画球

球坐标公式

球坐标可以用如下公式表示:

x=Rcosαcosβ

y=Rsinαcosβ

z=Rsinβ

在Eclipse中新建工程DrawBall, 新建Ball类, 添加成员方法初始化顶点数组,获取球坐标代码如下:

/**     * 初始化顶点数组     * ANGLE_SPAN角度进行划分     *         p3   p2 (beta + ANGLE_SPAN)     *         p0   p1 (alpha + ANGLE_SPAN)     * 画两个三角形 p0p1p2, p0p2p3     */    private void initVertex() {        vertex = new ArrayList<Float>();        for (int alpha = 0; alpha <= 360; alpha += ANGLE_SPAN) {            for (int beta = -90; beta <= 90; beta += ANGLE_SPAN) {                // 第一个点的坐标                float x0 = (float) (RADIAN * Math.cos(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta)));                float y0 = (float) (RADIAN * Math.sin(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta)));                float z0 = (float) (RADIAN * Math.sin(Math.toRadians(beta)));                // 第二个点的坐标                float x1 = (float) (RADIAN * Math.cos(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta)));                float y1 = (float) (RADIAN * Math.sin(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta)));                float z1 = (float) (RADIAN * Math.sin(Math.toRadians(beta)));                // 第三个点的坐标                float x2 = (float) (RADIAN * Math.cos(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float y2 = (float) (RADIAN * Math.sin(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float z2 = (float) (RADIAN * Math.sin(Math.toRadians(beta + ANGLE_SPAN)));                // 第三个点的坐标                float x3 = (float) (RADIAN * Math.cos(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float y3 = (float) (RADIAN * Math.sin(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float z3 = (float) (RADIAN * Math.sin(Math.toRadians(beta + ANGLE_SPAN)));                vertex.add(x0);                vertex.add(y0);                vertex.add(z0);                vertex.add(x1);                vertex.add(y1);                vertex.add(z1);                vertex.add(x2);                vertex.add(y2);                vertex.add(z2);                vertex.add(x0);                vertex.add(y0);                vertex.add(z0);                vertex.add(x2);                vertex.add(y2);                vertex.add(z2);                vertex.add(x3);                vertex.add(y3);                vertex.add(z3);            }        }        numVertex = vertex.size();    }

顶点着色器、片段着色器

新建顶点着色器和片段着色器
res/raw/vertex_shader.glsl

attribute vec4 aPosition;uniform mat4 vMatrix;void main() {    gl_Position = vMatrix * aPosition;}

res/raw/fragment_shader.glsl

uniform vec4 uColor;void main(){    gl_FragColor = uColor;}

给Ball类添加构造函数,编译链接程序,

package com.example.drawball;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import java.util.ArrayList;import com.example.drawball.utils.BufferHelper;import com.example.drawball.utils.Logit;import com.example.drawball.utils.MatrixState;import com.example.drawball.utils.ShaderHelper;import com.example.drawball.utils.TextResourceReader;import com.example.drawcircle.R;import android.content.Context;import android.opengl.GLES30;public class Ball {    private static final String TAG = "Circle";    private Context context;    private FloatBuffer vertexBuffer;    private FloatBuffer colorBuffer;    private static final int BYTES_PER_FLOAT = 4; //浮点字节个数    private static final int COORS_PER_VERTEX = 3; // 顶点坐标分量个数    private static final int ANGLE_SPAN = 10; // 圆周划分角度10度    private static final float RADIANS = 0.5f;    private int numVertex;    private ArrayList<Float> vertex;    private int program; //应用程序句柄    private static final String A_POSITION = "aPosition";    private static final String U_COLOR = "uColor";    private static final String V_MATRIX = "vMatrix";    private int vMatrixLocation;    public Ball(Context context) {        this.context = context;        initVertex();        vertexBuffer = BufferHelper.getFloatBuffer(vertex);        getProgram();        int aPositionLocation = GLES30.glGetAttribLocation(program, A_POSITION); // 对应于 vertex_shader.glsl 中 attribute属性        Logit.d(TAG, "aPosition location: " + aPositionLocation);        GLES30.glVertexAttribPointer(aPositionLocation, COORS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, vertexBuffer); // 区别glVertexAttribIPointer        GLES30.glEnableVertexAttribArray(aPositionLocation);  //启用顶点属性数组        int uColorLocation = GLES30.glGetUniformLocation(program, U_COLOR);  // 对应与 fragment_shader 中uniform属性        Logit.d(TAG, "uColor Location: " + uColorLocation);        GLES30.glUniform4f(uColorLocation, 1, 0, 0, 1); // 设置着色器中变量的值        vMatrixLocation = GLES30.glGetUniformLocation(program, V_MATRIX);    }    /**     * 初始化顶点数组     * angleSpan角度进行划分     *         point3   point2 (beta + angleSpan)     *         point0   point1 (alpha + angleSpan)     */    private void initVertex() {        vertex = new ArrayList<Float>();        for (int alpha = 0; alpha <= 360; alpha += ANGLE_SPAN) {            for (int beta = -90; beta <= 90; beta += ANGLE_SPAN) {                // 第一个点的坐标                float x0 = (float) (RADIANS * Math.cos(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta)));                float y0 = (float) (RADIANS * Math.sin(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta)));                float z0 = (float) (RADIANS * Math.sin(Math.toRadians(beta)));                // 第二个点的坐标                float x1 = (float) (RADIANS * Math.cos(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta)));                float y1 = (float) (RADIANS * Math.sin(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta)));                float z1 = (float) (RADIANS * Math.sin(Math.toRadians(beta)));                // 第三个点的坐标                float x2 = (float) (RADIANS * Math.cos(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float y2 = (float) (RADIANS * Math.sin(Math.toRadians(alpha + ANGLE_SPAN)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float z2 = (float) (RADIANS * Math.sin(Math.toRadians(beta + ANGLE_SPAN)));                // 第三个点的坐标                float x3 = (float) (RADIANS * Math.cos(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float y3 = (float) (RADIANS * Math.sin(Math.toRadians(alpha)) * Math.cos(Math.toRadians(beta + ANGLE_SPAN)));                float z3 = (float) (RADIANS * Math.sin(Math.toRadians(beta + ANGLE_SPAN)));                vertex.add(x0);                vertex.add(y0);                vertex.add(z0);                vertex.add(x1);                vertex.add(y1);                vertex.add(z1);                vertex.add(x2);                vertex.add(y2);                vertex.add(z2);                vertex.add(x0);                vertex.add(y0);                vertex.add(z0);                vertex.add(x2);                vertex.add(y2);                vertex.add(z2);                vertex.add(x3);                vertex.add(y3);                vertex.add(z3);            }        }        numVertex = vertex.size();    }    private void getProgram() {        String vertexSource = TextResourceReader.readTextFileFromResource(context, R.raw.vertex_shader);        String fragmentSource = TextResourceReader.readTextFileFromResource(context, R.raw.fragment_shader);//      int vertexShader = ShaderHelper.compileVertexShader(vertexSource);//      int fragmentShader = ShaderHelper.compileFragmentShader(fragmentSource);        //获取program的id          program  = ShaderHelper.buildProgram(vertexSource, fragmentSource);          Logit.d(TAG, "program: " + program);        GLES30.glUseProgram(program); // 不要忘记设置,否则不会起作用    }    public void draw() {//      GLES30.glUniform4f(2, 1, 0, 1, 0);//      GLES30.glDrawElements(GLES30.GL_TRIANGLES, 3, GLES30.GL_FLOAT, vertexBuffer);        GLES30.glUniformMatrix4fv(vMatrixLocation, 1, false, MatrixState.getFinalMatrix(), 0);        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, numVertex);    }}

设置相机位置和透视投影

添加BallRenderer类,设置相机和透视投影
src/com/example/drawball/BallRenderer.java

package com.example.drawball;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.content.Context;import android.opengl.GLES30;import android.opengl.GLSurfaceView.Renderer;import com.example.drawball.utils.Logit;import com.example.drawball.utils.MatrixState;public class BallRenderer implements Renderer{    private static final String TAG = "CircleRenderer";    private Ball ball;    private Context  context;    public BallRenderer(Context context) {        // TODO Auto-generated constructor stub        this.context = context;    }    @Override    public void onSurfaceCreated(GL10 gl, EGLConfig config) {        // TODO Auto-generated method stub        Logit.d(TAG, "onSurfaceCreated.");        ball = new Ball(context);        GLES30.glClearColor(1, 1, 1, 1);    }    @Override    public void onSurfaceChanged(GL10 gl, int width, int height) {        // TODO Auto-generated method stub        Logit.d(TAG, "onSurfaceChanded...");//      GLES30.glViewport(0, 0, width, height);        float ratio = 1.0f * width / height;//先转换成浮点数再做运算        MatrixState.setCamera(0, 0, 7, 0, 0, 0, 0, 1, 0);        MatrixState.setProjectOrtho(-ratio, ratio, -1, 1, 5, 9);    }    @Override    public void onDrawFrame(GL10 gl) {        // TODO Auto-generated method stub        Logit.d(TAG, "onDrawFrame");        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);        ball.draw();    }}
package com.example.drawball;import android.app.Activity;import android.content.Context;import android.opengl.GLSurfaceView;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;public class BallActivity extends Activity {    private GLSurfaceView mTriGLView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);//        setContentView(R.layout.activity_tri);        mTriGLView = new CircleGLSurfaceView(this);        setContentView(mTriGLView);    }    static class CircleGLSurfaceView extends GLSurfaceView {        public CircleGLSurfaceView(Context context) {            super(context);            setEGLContextClientVersion(3);            setRenderer(new BallRenderer(context));            setRenderMode(RENDERMODE_WHEN_DIRTY);        }    }}

运行结果
drawball

渐变色球

将顶点位置作为颜色值传给片段着色器颜色值来绘制, 顶点着色器中添加varying 变量vColor存储顶点位置,传递给片段着色器, 如下:

顶点着色器、片段着色器

res/raw/vertex_shader1.glsl

attribute vec4 aPosition;uniform mat4 vMatrix;varying  vec3 vColor;void main() {    gl_Position = vMatrix * aPosition;    vColor = aPosition.xyz;}

res/raw/fragment_shader1.glsl

uniform vec4 uColor;varying vec3 vColor;void main(){    gl_FragColor = vec4(vColor, 1.0);}

运行结果:
drawball

下载DrawBall
LaTeX公式编辑器