运行效果图:
顶点着色器:
uniform mat4 uMVPMatrix; //总变换矩阵
attribute vec3 aPosition; //顶点位置
attribute vec2 aLongLat; //顶点经纬度
varying vec2 mcLongLat;
void main()
{
//根据总变换矩阵计算此次绘制此顶点位置
gl_Position = uMVPMatrix * vec4(aPosition,1);
//将顶点的经纬度传给片元着色器
mcLongLat=aLongLat;
}
片元着色器:
precision mediump float;
varying vec2 mcLongLat;//接收从顶点着色器过来的参数
void main()
{
vec3 bColor=vec3(0.678,0.231,0.129);//砖块的颜色
vec3 mColor=vec3(0.763,0.657,0.614);//间隔的颜色
vec3 color;
//计算当前位于奇数还是偶数行
int row=int(mod((mcLongLat.y+90.0)/12.0,2.0));
//计算当前是否在此行的砖块垂直区间中的辅助变量
float ny=mod(mcLongLat.y+90.0,12.0);
//奇偶数行x偏移
float oeoffset=0.0;
//计算当前是否在此列的砖块水平区间中的辅助变量
float nx;
if(ny>10.0)
{//不在此行的砖块垂直区间中
color=mColor;
}
else
{//在此行的砖块垂直区间中
if(row==1)
{//若为奇数行则加上列偏移
oeoffset=11.0;
}
//计算当前是否在此列的砖块水平区间中的辅助变量
nx=mod(mcLongLat.x+oeoffset,22.0);
if(nx>20.0)
{//不在此列的砖块水平区间中
color=mColor;
}
else
{//在此列的砖块水平区间中
color=bColor;
}
}
//将计算出的颜色给此片元
gl_FragColor=vec4(color,0);
}
创建球代码:
package com.bn.Sample14_1;
import java.nio.ByteBuffer;
import static com.bn.Sample14_1.Constant.*;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import android.opengl.GLES20;
//球
public class Ball {
int mProgram;//自定义渲染管线着色器程序id
int muMVPMatrixHandle;//总变换矩阵引用
int maPositionHandle; //顶点位置属性引用
int maLongLatHandle; //顶点经纬度属性引用
String mVertexShader;//顶点着色器代码脚本
String mFragmentShader;//片元着色器代码脚本
FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
FloatBuffer mLongLatBuffer;//顶点经纬度数据缓冲
int vCount = 0;
float yAngle = 0;//绕y轴旋转的角度
float xAngle = 0;//绕x轴旋转的角度
float zAngle = 0;//绕z轴旋转的角度
float r = 0.8f;
public Ball(MySurfaceView mv) {
//初始化顶点坐标与着色数据
initVertexData();
//初始化shader
initShader(mv);
}
//初始化顶点坐标数据的方法
public void initVertexData() {
//顶点坐标数据的初始化================begin============================
ArrayList<Float> alVertix = new ArrayList<Float>();//存放顶点坐标的ArrayList
ArrayList<Float> alLongLat=new ArrayList<Float>();//存放顶点经纬度的ArrayList
final int angleSpan = 10;//将球进行单位切分的角度
for (int vAngle = -90; vAngle < 90; vAngle = vAngle + angleSpan)//垂直方向angleSpan度一份
{
for (int hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan)//水平方向angleSpan度一份
{//纵向横向各到一个角度后计算对应的此点在球面上的坐标
float x0=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle))*Math.cos(Math.toRadians(hAngle)));
float y0=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle))*Math.sin(Math.toRadians(hAngle)));
float z0=(float)(r*UNIT_SIZE*Math.sin(Math.toRadians(vAngle)));
float long0=hAngle; float lat0=vAngle;
float x1=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle))*Math.cos(Math.toRadians(hAngle+angleSpan)));
float y1=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle))*Math.sin(Math.toRadians(hAngle+angleSpan)));
float z1=(float)(r*UNIT_SIZE*Math.sin(Math.toRadians(vAngle)));
float long1=hAngle+angleSpan; float lat1=vAngle;
float x2=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle+angleSpan))*Math.cos(Math.toRadians(hAngle+angleSpan)));
float y2=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle+angleSpan))*Math.sin(Math.toRadians(hAngle+angleSpan)));
float z2=(float)(r*UNIT_SIZE*Math.sin(Math.toRadians(vAngle+angleSpan)));
float long2=hAngle+angleSpan; float lat2=vAngle+angleSpan;
float x3=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle+angleSpan))*Math.cos(Math.toRadians(hAngle)));
float y3=(float)(r*UNIT_SIZE*Math.cos(Math.toRadians(vAngle+angleSpan))*Math.sin(Math.toRadians(hAngle)));
float z3=(float)(r*UNIT_SIZE*Math.sin(Math.toRadians(vAngle+angleSpan)));
float long3=hAngle; float lat3=vAngle+angleSpan;
//将计算出来的XYZ坐标加入存放顶点坐标的ArrayList
alVertix.add(x1);alVertix.add(y1);alVertix.add(z1);
alVertix.add(x3);alVertix.add(y3);alVertix.add(z3);
alVertix.add(x0);alVertix.add(y0);alVertix.add(z0);
alVertix.add(x1);alVertix.add(y1);alVertix.add(z1);
alVertix.add(x2);alVertix.add(y2);alVertix.add(z2);
alVertix.add(x3);alVertix.add(y3);alVertix.add(z3);
//将计算出来的顶点经纬度加入存放顶点经纬度的ArrayList
alLongLat.add(long1);alLongLat.add(lat1);
alLongLat.add(long3);alLongLat.add(lat3);
alLongLat.add(long0);alLongLat.add(lat0);
alLongLat.add(long1);alLongLat.add(lat1);
alLongLat.add(long2);alLongLat.add(lat2);
alLongLat.add(long3);alLongLat.add(lat3);
}
}
vCount = alVertix.size() / 3;//顶点的数量为坐标值数量的1/3,因为一个顶点有3个坐标
//将alVertix中的坐标值转存到一个float数组中
float vertices[] = new float[vCount * 3];
for (int i = 0; i < alVertix.size(); i++) {
vertices[i] = alVertix.get(i);
}
//创建顶点坐标数据缓冲
//vertices.length*4是因为一个整数四个字节
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());//设置字节顺序
mVertexBuffer = vbb.asFloatBuffer();//转换为int型缓冲
mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
mVertexBuffer.position(0);//设置缓冲区起始位置
//特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
//转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题
//将alLongLat中的经纬度值转存到一个float数组中
float[] longlat=new float[alLongLat.size()];
for(int i=0;i<alLongLat.size();i++)
{
longlat[i]=alLongLat.get(i);
}
ByteBuffer llbb = ByteBuffer.allocateDirect(longlat.length*4);
llbb.order(ByteOrder.nativeOrder());//设置字节顺序
mLongLatBuffer=llbb.asFloatBuffer();
mLongLatBuffer.put(longlat);
mLongLatBuffer.position(0);
}
//初始化着色器
public void initShader(MySurfaceView mv) {
//加载顶点着色器的脚本内容
mVertexShader = ShaderUtil.loadFromAssetsFile("vertex.sh",
mv.getResources());
//加载片元着色器的脚本内容
mFragmentShader = ShaderUtil.loadFromAssetsFile("frag.sh",
mv.getResources());
//基于顶点着色器与片元着色器创建程序
mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
//获取程序中顶点位置属性引用
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
//获取程序中总变换矩阵引用
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
//获取程序中顶点经纬度属性引用
maLongLatHandle=GLES20.glGetAttribLocation(mProgram, "aLongLat");
}
public void drawSelf() {
MatrixState.rotate(xAngle, 1, 0, 0);//绕X轴转动
MatrixState.rotate(yAngle, 0, 1, 0);//绕Y轴转动
MatrixState.rotate(zAngle, 0, 0, 1);//绕Z轴转动
//制定使用某套着色器程序
GLES20.glUseProgram(mProgram);
//将最终变换矩阵传入着色器程序
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false,
MatrixState.getFinalMatrix(), 0);
//为画笔指定顶点经纬度数据
GLES20.glVertexAttribPointer
(
maLongLatHandle,
2,
GLES20.GL_FLOAT,
false,
2*4,
mLongLatBuffer
);
//将顶点位置数据传入渲染管线
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
false, 3 * 4, mVertexBuffer);
//启用顶点位置、顶点经纬度数据
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glEnableVertexAttribArray(maLongLatHandle);
//绘制球
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
}
}
运行代码:
Ball ball;//球
ball=new Ball(MySurfaceView.this);
MatrixState.pushMatrix();
ball.drawSelf();
MatrixState.popMatrix();
源代码下载地址:在csdn中,下载->高级搜索->ID号输入:sh15285118586->点击搜索。进入后下载相关源文件。