重庆seowhy整站优化,如何建立自己网站视频教程,管理咨询公司经营范围包括哪些,一级造价工程师报名时间2024年一.概述
今天使用OpenGLES实现一个圆心是玫红色#xff0c;向圆周渐变成蓝色的圆。
本篇博文的内容也是后续绘制3D图形的基础。
实现过程中#xff0c;需要重点关注的点是#xff1a;如何使用数学公式求得图形的顶点#xff0c;以及加载颜色值。
废话不多说#xff0c…一.概述
今天使用OpenGLES实现一个圆心是玫红色向圆周渐变成蓝色的圆。
本篇博文的内容也是后续绘制3D图形的基础。
实现过程中需要重点关注的点是如何使用数学公式求得图形的顶点以及加载颜色值。
废话不多说开工吧
二.Render类
Render类中需要关注的重点是createCirclePositions()
这个函数中实现了圆形的顶点创建和颜色值加载
已知如下两个变量
圆半径R圆周的点与X轴的夹角θ
求圆的顶点坐标需要求得两种坐标
圆心的顶点坐标圆周的顶点坐标
圆心坐标比较简单(00)
圆周上点的坐标
x R * cos(θ)y R * sin(θ)
知道如何求得圆的顶点坐标后如下就是Render类的实现代码
public class CircleRender implements GLSurfaceView.Renderer {private final String TAG CubeRender.class.getSimpleName();private final Context mContext;//圆形顶点位置private float vertexData[];//顶点的颜色private float colorData[];private FloatBuffer vertexBuffer;private FloatBuffer colorBuffer;//MVP矩阵private float[] mMVPMatrix new float[16];//shader程序/渲染器private int shaderProgram;//返回属性变量的位置//变换矩阵private int uMatrixLocation;//位置private int aPositionLocation;//颜色private int aColorLocation;private float ratio;public CircleRender(Context context) {mContext context;}Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {Log.v(TAG, onSurfaceCreated());glClearColor(0.0f, 0.0f, 0.0f, 1.0f);initGLES();}public void initGLES() {Log.v(TAG, initGLES!);/************** 着色器程序/渲染器 **************///创建并连接 着色器程序shaderProgram ShaderUtils.createAndLinkProgram(mContext,circle_vertex_shader.glsl,circle_fragtment_shader.glsl);if (shaderProgram 0) {Log.v(TAG, create And Link ShaderProgram Fail!);return;}//使用着色器源程序glUseProgram(shaderProgram);createCirclePositions(0.8f, 60);/************** 着色器变量 **************///获取着色器中的变量uMatrixLocation glGetUniformLocation(shaderProgram, u_Matrix);aPositionLocation glGetAttribLocation(shaderProgram, vPosition);aColorLocation glGetAttribLocation(shaderProgram, aColor);//为顶点、颜色、索引数据配置内存vertexBuffer ShaderUtils.getFloatBuffer(vertexData);colorBuffer ShaderUtils.getFloatBuffer(colorData);//启动深度测试glEnable(GL_DEPTH_TEST);}Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {Log.v(TAG, onSurfaceChanged(): width x height);glViewport(0, 0, width, height);//计算宽高比ratio (float) width / height;}Overridepublic void onDrawFrame(GL10 gl) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(0.95f, 0.95f, 0.95f, 0.95f);mMVPMatrix TransformUtils.getCircleMVPMatrix(ratio);//将变换矩阵传入顶点渲染器glUniformMatrix4fv(uMatrixLocation, 1, false, mMVPMatrix, 0);//准备顶点坐标和颜色数据glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer);glVertexAttribPointer(aColorLocation, 4, GL_FLOAT, false, 0, colorBuffer);//启用顶点位置和顶点颜色句柄glEnableVertexAttribArray(aPositionLocation);glEnableVertexAttribArray(aColorLocation);//绘制glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData.length / 3);//禁止顶点数组的句柄glDisableVertexAttribArray(aPositionLocation);glDisableVertexAttribArray(aColorLocation);}private void createCirclePositions(float radius, int n) {ArrayListFloat data new ArrayList();data.add(0.0f); //设置圆心坐标data.add(0.0f);data.add(0.0f);float angDegSpan 360f / n;for (float i 0; i 360 angDegSpan; i angDegSpan) {data.add((float) (radius * Math.sin(i * Math.PI / 180f)));data.add((float) (radius * Math.cos(i * Math.PI / 180f)));data.add(0.0f);}float[] f new float[data.size()];for (int i 0; i f.length; i) {f[i] data.get(i);}vertexData f;//处理各个顶点的颜色colorData new float[f.length * 4 / 3];ArrayListFloat temp0 new ArrayList();ArrayListFloat temp2 new ArrayList();ArrayListFloat temp1 new ArrayList();temp1.add(1.0f);temp1.add(0.0f);temp1.add(1.0f);temp1.add(0.0f);temp0.add(0.0f);temp0.add(0.0f);temp0.add(1.0f);temp0.add(0.0f);for (int i 0; i f.length / 3; i) {if (i 0) {temp2.addAll(temp1);} else {temp2.addAll(temp0);}}for (int i 0; i temp2.size(); i) {colorData[i] temp2.get(i);}}
}三.ShaderUtils相关函数
与之前的一样常规代码
3.1 createAndLinkProgram() /** 创建和链接着色器程序* 参数顶点着色器、片段着色器程序ResId* 返回成功创建、链接了顶点和片段着色器的着色器程序Id*/public static int createAndLinkProgram(Context context, String vertexShaderFN, String fragShaderFN) {//创建着色器程序int shaderProgram glCreateProgram();if (shaderProgram 0) {Log.e(TAG, Failed to create shaderProgram );return 0;}//获取顶点着色器对象int vertexShader loadShader(GL_VERTEX_SHADER, loadShaderSource(context, vertexShaderFN));if (0 vertexShader) {Log.e(TAG, Failed to load vertexShader);return 0;}//获取片段着色器对象int fragmentShader loadShader(GL_FRAGMENT_SHADER, loadShaderSource(context, fragShaderFN));if (0 fragmentShader) {Log.e(TAG, Failed to load fragmentShader);return 0;}//绑定顶点着色器到着色器程序glAttachShader(shaderProgram, vertexShader);//绑定片段着色器到着色器程序glAttachShader(shaderProgram, fragmentShader);//链接着色器程序glLinkProgram(shaderProgram);//检查着色器链接状态int[] linked new int[1];glGetProgramiv(shaderProgram, GL_LINK_STATUS, linked, 0);if (linked[0] 0) {glDeleteProgram(shaderProgram);Log.e(TAG, Failed to link shaderProgram);return 0;}return shaderProgram;}
3.2 getFloatBuffer() public static FloatBuffer getFloatBuffer(float[] array) {//将顶点数据拷贝映射到 native 内存中以便opengl能够访问FloatBuffer buffer ByteBuffer.allocateDirect(array.length * BYTES_PER_FLOAT)//直接分配 native 内存不会被gc.order(ByteOrder.nativeOrder())//和本地平台保持一致的字节序大/小头.asFloatBuffer();//将底层字节映射到FloatBuffer实例方便使用buffer.put(array)//将顶点拷贝到 native 内存中.position(0);//每次 put position 都会 1需要在绘制前重置为0return buffer;}
四.TransformUtils相关函数
与以往不同的是这次绘制需要求得mvp矩阵。
也就是model、view和project三个矩阵最终再求得一个总的mvpMatrix矩阵
同时还需要设置投影方式是透视投影还是正交投影。
相关理论知识可以参看官网的这一章《坐标系统 - LearnOpenGL CN》
本篇博文不再复述
代码 public static float[] getCircleMVPMatrix(float ratio) {float[] modelMatrix getIdentityMatrix(16, 0); //模型变换矩阵float[] viewMatrix getIdentityMatrix(16, 0); //观测变换矩阵/相机矩阵float[] projectionMatrix getIdentityMatrix(16, 0); //投影变换矩阵//设置透视投影Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);//设置相机位置Matrix.setLookAtM(viewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);//计算变换矩阵float[] mvpMatrix new float[16];Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0);return mvpMatrix;}
五.着色器代码
5.1 circle_vertex_shader.glsl
#version 300 eslayout (location 0) in vec4 vPosition;
layout (location 1) in vec4 aColor;uniform mat4 u_Matrix;out vec4 vColor;void main() {gl_Position u_Matrix * vPosition;vColor aColor;
}
5.2 circle_fragtment_shader.glsl
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;in vec4 vColor;out vec4 outColor;void main(){outColor vColor;
}六.UI实现
Render、GLSurfaceView与Activity、Fragment等之间的实现逻辑请根据自己项目的实际情况去实现
这里只贴出Render在GLSurfaceView中设置的代码 mGLSurfaceView rootView.findViewById(R.id.Circle_GLSurfaceView);//设置GLES版本mGLSurfaceView.setEGLContextClientVersion(3);//创建Render对象并将其设置到GLSurfaceViewmCircleRender new CircleRender(getActivity());mGLSurfaceView.setRenderer(mCircleRender);mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
七.最终效果
最终效果如下