OpenGL ES: 画球

画球

球坐标公式

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

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公式编辑器

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值