Files
Android-OpenGL-Simple/第8章 3D基本形状/Sample8_7/src/com/bn/Sample8_7/TopPart2.java
2022-09-19 18:05:01 +08:00

202 lines
6.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.bn.Sample8_7;
import static com.bn.Sample8_7.ShaderUtil.createProgram;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import android.opengl.GLES20;
/*
* 泰姬陵顶部组建2
*/
public class TopPart2 {
int mProgram;//自定义渲染管线着色器程序id
int muMVPMatrixHandle;//总变换矩阵引用
int maPositionHandle; //顶点位置属性引用
int maTexCoorHandle; //顶点纹理坐标属性引用
String mVertexShader;//顶点着色器代码脚本
String mFragmentShader;//片元着色器代码脚本
FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
FloatBuffer mTexCoorBuffer;//顶点纹理坐标数据缓冲
int vCount=0;
float xAngle=0;//绕x轴旋转的角度
float yAngle=0;//绕y轴旋转的角度
float zAngle=0;//绕z轴旋转的角度
float scale;
public TopPart2(MySurfaceView mv,float scale, int nCol ,int nRow)
{
this.scale=scale;
//调用初始化顶点数据的initVertexData方法
initVertexData(scale,nCol,nRow);
//调用初始化着色器的intShader方法
initShader(mv);
}
//自定义的初始化顶点数据的方法
public void initVertexData(float scale, int nCol ,int nRow //大小列数行数行数要保证可以被1除尽
){
//成员变量初始化
float angdegSpan=360.0f/nCol;
vCount=3*nCol*nRow*2;//顶点个数共有nColumn*nRow*2个三角形每个三角形都有三个顶点
//坐标数据初始化
ArrayList<Float> alVertix=new ArrayList<Float>();//原顶点列表(未卷绕)
ArrayList<Integer> alFaceIndex=new ArrayList<Integer>();//组织成面的顶点的索引值列表(按逆时针卷绕)
//以下是贝赛尔曲线的实现代码
BezierUtil.al.clear();//清空数据点列表
//加入数据点
BezierUtil.al.add(new BNPosition(0, 113));
BezierUtil.al.add(new BNPosition(28, 128));
BezierUtil.al.add(new BNPosition(57, 150));
BezierUtil.al.add(new BNPosition(24, 135));
BezierUtil.al.add(new BNPosition(42, 125));
BezierUtil.al.add(new BNPosition(36, 152));
BezierUtil.al.add(new BNPosition(28, 175));
BezierUtil.al.add(new BNPosition(14, 226));
BezierUtil.al.add(new BNPosition(38, 191));
BezierUtil.al.add(new BNPosition(21, 202));
BezierUtil.al.add(new BNPosition(-1, 208));
//通过数据点,获取贝赛尔曲线上的点的列表
ArrayList<BNPosition> alCurve=BezierUtil.getBezierData(1.0f/nRow);
//顶点
for(int i=0;i<nRow+1;i++)
{
double r=alCurve.get(i).x*Constant.DATA_RATIO*scale;//当前圆的半径
float y=alCurve.get(i).y*Constant.DATA_RATIO*scale;//当前y值
for(float angdeg=0;Math.ceil(angdeg)<360+angdegSpan;angdeg+=angdegSpan)//重复了一列顶点,方便了索引的计算
{
double angrad=Math.toRadians(angdeg);//当前列弧度
float x=(float) (-r*Math.sin(angrad));
float z=(float) (-r*Math.cos(angrad));
//将计算出来的XYZ坐标加入存放顶点坐标的ArrayList
alVertix.add(x); alVertix.add(y); alVertix.add(z);
}
}
//索引
for(int i=0;i<nRow;i++){
for(int j=0;j<nCol;j++){
int index=i*(nCol+1)+j;//当前索引
//卷绕索引
alFaceIndex.add(index+1);//下一列---1
alFaceIndex.add(index+nCol+2);//下一行下一列---3
alFaceIndex.add(index+nCol+1);//下一列---2
alFaceIndex.add(index+1);//下一列---1
alFaceIndex.add(index+nCol+1);//下一列---2
alFaceIndex.add(index);//当前---0
}
}
//计算卷绕顶点
float[] vertices=new float[vCount*3];
vertices=VectorUtil.calVertices(alVertix, alFaceIndex);
//顶点坐标数据初始化
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);//创建顶点坐标数据缓冲
vbb.order(ByteOrder.nativeOrder());//设置字节顺序
mVertexBuffer = vbb.asFloatBuffer();//转换为float型缓冲
mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
mVertexBuffer.position(0);//设置缓冲区起始位置
//纹理
ArrayList<Float> alST=new ArrayList<Float>();//原顶点列表(未卷绕)
float yMin=999999999;//y最小值
float yMax=0;//y最大值
for(BNPosition pos:alCurve){
yMin=Math.min(yMin, pos.y);//y最小值
yMax=Math.max(yMax, pos.y);//y最大值
}
for(int i=0;i<nRow+1;i++)
{
float y=alCurve.get(i).y;//当前y值
float t=1-(y-yMin)/(yMax-yMin);//t坐标
for(float angdeg=0;Math.ceil(angdeg)<360+angdegSpan;angdeg+=angdegSpan)//重复了一列纹理坐标,以索引的计算
{
float s=angdeg/360;//s坐标
//将计算出来的ST坐标加入存放顶点坐标的ArrayList
alST.add(s); alST.add(t);
}
}
//计算卷绕后纹理坐标
float[] textures=VectorUtil.calTextures(alST, alFaceIndex);
ByteBuffer tbb = ByteBuffer.allocateDirect(textures.length*4);//创建顶点纹理数据缓冲
tbb.order(ByteOrder.nativeOrder());//设置字节顺序
mTexCoorBuffer = tbb.asFloatBuffer();//转换为float型缓冲
mTexCoorBuffer.put(textures);//向缓冲区中放入顶点纹理数据
mTexCoorBuffer.position(0);//设置缓冲区起始位置
}
//自定义初始化着色器initShader方法
public void initShader(MySurfaceView mv)
{
//加载顶点着色器的脚本内容
mVertexShader=ShaderUtil.loadFromAssetsFile("vertex_tex.sh", mv.getResources());
//加载片元着色器的脚本内容
mFragmentShader=ShaderUtil.loadFromAssetsFile("frag_tex.sh", mv.getResources());
//基于顶点着色器与片元着色器创建程序
mProgram = createProgram(mVertexShader, mFragmentShader);
//获取程序中顶点位置属性引用id
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
//获取程序中顶点纹理坐标属性引用id
maTexCoorHandle= GLES20.glGetAttribLocation(mProgram, "aTexCoor");
//获取程序中总变换矩阵引用id
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}
public void drawSelf(int texId)
{
MatrixState.rotate(xAngle, 1, 0, 0);
MatrixState.rotate(yAngle, 0, 1, 0);
MatrixState.rotate(zAngle, 0, 0, 1);
//制定使用某套shader程序
GLES20.glUseProgram(mProgram);
//将最终变换矩阵传入shader程序
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
//传送顶点位置数据
GLES20.glVertexAttribPointer
(
maPositionHandle,
3,
GLES20.GL_FLOAT,
false,
3*4,
mVertexBuffer
);
//传送顶点纹理坐标数据
GLES20.glVertexAttribPointer
(
maTexCoorHandle,
2,
GLES20.GL_FLOAT,
false,
2*4,
mTexCoorBuffer
);
//启用顶点位置数据
GLES20.glEnableVertexAttribArray(maPositionHandle);
//启用顶点纹理数据
GLES20.glEnableVertexAttribArray(maTexCoorHandle);
//绑定纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
//绘制纹理矩形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
}
}