OpenglES2.0 for Android:来画个球吧

OpenGLES2.0移动游戏与图形编程实战 OpenGLES(OpenGL for Embedded Systems)是一个为嵌入式系统,如智能手机和平板电脑等设备优化的图形API标准。OpenGLES2.0作为该系列标准中的一个重要版本,它提供了适用于2D和3D图形的丰富特性集,允许开发者在遵守硬件限制的前提下,实现高度视觉化的内容和复杂的图形处理。控制流在GLSL中包括条件语句和循环语句。if-else语句可以实现条件逻辑,而循环可以通过forwhile和do-while来实现。函数定义在GLSL中使用void。 阅读详情

OpenglES2.0 for Android:来画个球吧


理解球坐标系

首先看下球的坐标系 ,如图 :


                            (图来自百度百科 )

设球上有一点 A ,球心为O ,OA在 xOy上的投影与X轴夹角为 φ (范围为 0 到360 ,单位 :度),   
OA在与Z的夹角为 θ (范围为 0 到 180  ,单位:度 ),球的半径为r,则有 ;
     r * sin θ = y / sin φ    r * sinθ  = x / cos φ   z = r * cos θ
由此可得 X,Y,Z坐标
我们前面已经知道,在OpenglES中任何形状的3D物体都是用三角形来实现了,我们的球自然不能免俗,
那我们该如何用一堆三角形来完成这个球的绘制呢?回想一下我们的圆是怎么绘制的,对于圆,我们实际绘制的是一个正N边形,
当N足够大时我们看起来就是一个圆了,类比一下我们的球也是一样 :



当我们分割的足够多的时候 就像个球了:


球的顶点坐标及绘制

按照矩形的方式来看,我们绘制的球实际上是这样 :


我们实际上是想要绘制这一个个的矩形,我们把其中一个矩形单独拿来作分析 :

问题一,我们如何确定这个矩形的位置?我们只需要知道这个矩形的左上角的顶点坐标就可以确定该矩形的位置,这个顶点坐标显然与三个值有关,角度φ (范围为 0 到360 ,单位 :度) ,角度θ (范围为 0 到 180  ,单位:度 ),以及球的半径  r  ,r可以是一个固定值 ,因此我们通过双重循环就可以得到所有的矩形的左上角顶点坐标了。我们先写一个计算该顶点的代码 :
public void initVertexData(){
		int angleSpan = 90;//// 将球进行切分的角度
		float r = 0.6f;//球的半径
		final float UNIT_SIZE = 1.0f;
		for (int vAngle = 0; vAngle < 180; vAngle = vAngle + angleSpan)
		{
			for (int hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan)
			{
				float x0 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.cos(Math
						.toRadians(hAngle)));
				float y0 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.sin(Math
						.toRadians(hAngle)));
				float z0 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle)));
			}
		}
	}
每次循环我们都得到一个四边形的左上角的顶点坐标。我们知道如何求该顶点坐标后,其他三个坐标就很容易求得了,
OK,开始我们画球计划正式的第一步 ,我们直接在上节工程的基础上(我们要用到前面的工具类等,不要从零开始哦 )来做,
在shape目录下新建一个Ball类 (Ball.java):
package com.cumt.shape;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
public class Ball {

	private static final float UNIT_SIZE = 1.0f;// 单位尺寸
	private float r = 0.6f; // 球的半径
	final int angleSpan = 10;// 将球进行单位切分的角度
	private FloatBuffer vertexBuffer;// 顶点坐标
	int vCount = 0;// 顶点个数,先初始化为0
	// float类型的字节数
	private static final int BYTES_PER_FLOAT = 4;
	// 数组中每个顶点的坐标数
	private static final int COORDS_PER_VERTEX = 3;

	public void initVertexData() {
		ArrayList<Float> alVertix = new ArrayList<Float>();// 存放顶点坐标的ArrayList
		for (int vAngle = 0; vAngle < 180; vAngle = vAngle + angleSpan)// 垂直方向angleSpan度一份
		{
			for (int hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan)// 水平方向angleSpan度一份
			{
				// 纵向横向各到一个角度后计算对应的此点在球面上的坐标
				float x0 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.cos(Math
						.toRadians(hAngle)));
				float y0 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.sin(Math
						.toRadians(hAngle)));
				float z0 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle)));
				// Log.w("x0 y0 z0","" + x0 + "  "+y0+ "  " +z0);

				float x1 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.cos(Math
						.toRadians(hAngle + angleSpan)));
				float y1 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.sin(Math
						.toRadians(hAngle + angleSpan)));
				float z1 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle)));
				// Log.w("x1 y1 z1","" + x1 + "  "+y1+ "  " +z1);

				float x2 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.cos(Math.toRadians(hAngle + angleSpan)));
				float y2 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.sin(Math.toRadians(hAngle + angleSpan)));
				float z2 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle + angleSpan)));
				// Log.w("x2 y2 z2","" + x2 + "  "+y2+ "  " +z2);
				float x3 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.cos(Math.toRadians(hAngle)));
				float y3 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.sin(Math.toRadians(hAngle)));
				float z3 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle + angleSpan)));
				// Log.w("x3 y3 z3","" + x3 + "  "+y3+ "  " +z3);
				// 将计算出来的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);
			}
		}
		vCount = alVertix.size() / COORDS_PER_VERTEX;// 顶点的数量
		// 将alVertix中的坐标值转存到一个float数组中
		float vertices[] = new float[vCount * COORDS_PER_VERTEX];
		for (int i = 0; i < alVertix.size(); i++) {
			vertices[i] = alVertix.get(i);
		}
		vertexBuffer = ByteBuffer
    			.allocateDirect(vertices.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐标们加入FloatBuffer中
        vertexBuffer.put(vertices);
        // 设置buffer,从第一个坐标开始读
        vertexBuffer.position(0);
	}
}
我们使用ArrayList来保存顶点坐标,要注意顺序的问题,因为我们的四边形也是由三角形组成的,我们实际上还是绘制两个三角形。
这六个点应该应该正好组成这两个三角形。
下面我们来新建顶点着色器和片段着色器,在res / raw 目录下新建 :
<span style="font-size:14px;">//vertex_shader_ball.glsl
uniform mat4 u_Matrix;//最终的变换矩阵
attribute vec4 a_Position;//顶点位置
void main()                    
{                              
    gl_Position = u_Matrix * a_Position;
} </span>
<span style="font-size:14px;">precision mediump float;
void main()                         
{
   gl_FragColor=vec4(0.2,1.0,0.129,0);
}</span>
接下来和前面一样,编译链接~~  等等,此时代码如下 (Ball.java ):
package com.cumt.shape;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import android.content.Context;
import android.opengl.GLES20;
import com.cumt.opengeschange.R;
import com.cumt.utils.MatrixState;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;

public class Ball {

	private Context context;
	private static final float UNIT_SIZE = 1.0f;// 单位尺寸
	private float r = 0.6f; // 球的半径
	final int angleSpan = 10;// 将球进行单位切分的角度
	private FloatBuffer vertexBuffer;// 顶点坐标
	int vCount = 0;// 顶点个数,先初始化为0
	// float类型的字节数
	private static final int BYTES_PER_FLOAT = 4;
	// 数组中每个顶点的坐标数
	private static final int COORDS_PER_VERTEX = 3;
	
	private int program;
	private static final String A_POSITION = "a_Position";
	private static final String U_MATRIX = "u_Matrix";
	private int uMatrixLocation;
	private int aPositionLocation;
	
	public Ball(Context context){
		this.context = context;
		initVertexData();
		getProgram();
		aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);
		uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
		//---------传入顶点数据数据
		GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,
						GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aPositionLocation);
	}

	public void initVertexData() {
		ArrayList<Float> alVertix = new ArrayList<Float>();// 存放顶点坐标的ArrayList
		for (int vAngle = 0; vAngle < 180; vAngle = vAngle + angleSpan)// 垂直方向angleSpan度一份
		{
			for (int hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan)// 水平方向angleSpan度一份
			{
				// 纵向横向各到一个角度后计算对应的此点在球面上的坐标
				float x0 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.cos(Math
						.toRadians(hAngle)));
				float y0 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.sin(Math
						.toRadians(hAngle)));
				float z0 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle)));
				// Log.w("x0 y0 z0","" + x0 + "  "+y0+ "  " +z0);

				float x1 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.cos(Math
						.toRadians(hAngle + angleSpan)));
				float y1 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle)) * Math.sin(Math
						.toRadians(hAngle + angleSpan)));
				float z1 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle)));
				// Log.w("x1 y1 z1","" + x1 + "  "+y1+ "  " +z1);

				float x2 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.cos(Math.toRadians(hAngle + angleSpan)));
				float y2 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.sin(Math.toRadians(hAngle + angleSpan)));
				float z2 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle + angleSpan)));
				// Log.w("x2 y2 z2","" + x2 + "  "+y2+ "  " +z2);
				float x3 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.cos(Math.toRadians(hAngle)));
				float y3 = (float) (r * UNIT_SIZE
						* Math.sin(Math.toRadians(vAngle + angleSpan)) * Math
						.sin(Math.toRadians(hAngle)));
				float z3 = (float) (r * UNIT_SIZE * Math.cos(Math
						.toRadians(vAngle + angleSpan)));
				// Log.w("x3 y3 z3","" + x3 + "  "+y3+ "  " +z3);
				// 将计算出来的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);
			}
		}
		vCount = alVertix.size() / COORDS_PER_VERTEX;// 顶点的数量
		// 将alVertix中的坐标值转存到一个float数组中
		float vertices[] = new float[vCount * COORDS_PER_VERTEX];
		for (int i = 0; i < alVertix.size(); i++) {
			vertices[i] = alVertix.get(i);
		}
		vertexBuffer = ByteBuffer
    			.allocateDirect(vertices.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐标们加入FloatBuffer中
        vertexBuffer.put(vertices);
        // 设置buffer,从第一个坐标开始读
        vertexBuffer.position(0);
	}
	
	//获取program
    private void getProgram(){
    	//获取顶点着色器文本
    	String vertexShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.vertex_shader_ball);
    	//获取片段着色器文本
		String fragmentShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.fragment_shader_ball);
		//获取program的id
		program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);
		GLES20.glUseProgram(program);
    }
    
    public void draw(){
    	//将最终变换矩阵写入
		GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);
		GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }
}

然后是在我们的MyRender创建球的对象,并设置摄像机和透视投影并绘制 ,此时代码如下 (MyRender.java):

package com.cumt.render;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import com.cumt.shape.Ball;
import com.cumt.utils.MatrixState;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glViewport;

public class MyRender implements Renderer {
	
	private Context context;
	
	Ball ball;
	
	public MyRender(Context context){
		this.context = context;
	}
	
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		Log.w("MyRender","onSurfaceCreated");
		//设置屏幕背景色RGBA
        glClearColor(0.5f,0.5f,0.5f, 1.0f);  
		//打开深度检测
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        //打开背面剪裁   
        GLES20.glEnable(GLES20.GL_CULL_FACE); 
        ball = new Ball(context);
	}

	public void onSurfaceChanged(GL10 gl, int width, int height) {
		glViewport(0,0,width,height);
		float ratio = (float) width / height;
		// 调用此方法计算产生透视投影矩阵
        MatrixState.setProjectFrustum(-ratio,ratio, -1, 1, 20, 100);
		// 调用此方法产生摄像机9参数位置矩阵
     	MatrixState.setCamera(0, 0, 30, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
	}

	public void onDrawFrame(GL10 gl) {
		//清除深度缓冲与颜色缓冲
        glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        ball.draw();
	}
}

然后我们来实现通过获取屏幕点击事件来旋转绘制的物体 ,在原来的MySurfaceView中实现该功能 ,如下 (MySurfaceView.java):
package com.cumt.opengeschange;

import com.cumt.render.MyRender;
import com.cumt.utils.MatrixState;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
import android.view.View;

public class MySurfaceView extends GLSurfaceView {
	
	private MyRender myRender;

	public MySurfaceView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		myRender = new MyRender(context);
		this.setEGLContextClientVersion(2);
		this.setRenderer(myRender);
		// 设置渲染模式为主动渲染
		this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
		
		this.setOnTouchListener(new OnTouchListener() {
			
			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN://检测到点击事件时
					MatrixState.rotate(20f, 0, 1, 0);//绕y轴旋转
				}
				return true;
			}
		});
	}
}

运行一下看下结果吧:



棋盘纹理

!!!什么状况,分明是个圆~~而且点击屏幕之后也没什么变化~~,事实上我们已经完成了球的绘制,只是没有给它光照或纹理等很难看出它是个球
我们下面来想办法使这个球更容易看出来 ,我们先不说光照 ,考虑一下棋盘纹理着色器 ,所谓棋盘纹理如下所示 :




考虑棋盘纹理的绘制策略:

想象一下我们的球是一个立方体切割出来的,这个立方体的边长就是 2 * r ,r是球的半径,我们把这个立方体切割成
一个个的小立方体,每个小立方体的位置由其所在的层数,行数和列数共同确定,类比到球的表面,现在球的表面
是一个个分割后的小矩形,每个小矩形的位置由其所在的层数,行数和列数共同确定。假设我们已知分割的层数,
行数和列数都是 n ,一个顶点的坐标是(x ,y,z),求该点所在的层数,行数和列数 ? 求解过程如下 :球的半径
为 r  ,则直径为 2 * r  ,则每个小正方形的边长为  2 * r / n  。该顶点在Y轴方向坐标为y ,则其距离底层距离为 y + r ,则其所在
层数为 (y + r )/ (2 * r / n ),同理我们求得该点所在行数为 :(x + r )/ (2 * r / n ),所在列数为:(z + r )/ (2 * r / n )。
顶点坐标所在层数,行数,列数三者相加必定是一个奇数或者偶数,如果这三者的和是奇数则该顶点坐在片元颜色设置为
一种颜色,若这三者的和是偶数则该顶点坐在片元颜色设置为另一种颜色,如此就完成了我们的棋盘着色策略。

下面我们来修改一下我们的着色器程序(顶点着色器和片元着色器 ),此时两者代码如下 :

//vertex_shader_ball.glsl
uniform mat4 u_Matrix;//最终的变换矩阵
attribute vec4 a_Position;//顶点位置
varying vec4 vPosition;//用于传递给片元着色器的顶点位置
void main()                    
{                              
    gl_Position = u_Matrix * a_Position;
    vPosition = a_Position;
} 

我们在顶点着色器中新加了一个varying vec4 vPosition,用于将顶点数据传递给片元着色器,这样在片元着色器中我们就可以同样定义一个varying vec4 vPosition来接收顶点着色器传来的顶点坐标了 。此时片元着色器代码如下 :

precision mediump float;
varying vec4 vPosition;//接收从顶点着色器过来的顶点位置

void main()                         
{
   float uR = 0.6;//球的半径
   vec4 color;
   float n = 8.0;//分为n层n列n行
   float span = 2.0*uR/n;//正方形长度
   //计算行列层数
   int i = int((vPosition.x + uR)/span);//行数
   int j = int((vPosition.y + uR)/span);//层数
   int k = int((vPosition.z + uR)/span);//列数
   int colorType = int(mod(float(i+j+k),2.0));
   if(colorType == 1) {//奇数时为绿色
   		color = vec4(0.2,1.0,0.129,0);
   }
   else {//偶数时为白色
   		color = vec4(1.0,1.0,1.0,0);//白色
   }
   //将计算出的颜色给此片元
   gl_FragColor=color;
}  

OK,来运行下看下结果吧 :


good job !点击屏幕我们也可以看到球绕Y轴的旋转了 














opengles绘制圆锥体 opengles绘制圆锥体 (光照+纹理) 立即下载

相关推荐

opengles绘制可旋转的球体

opengles绘制可旋转的球体

android opengles 球体坐标,Android OpenGL入门实例:绘制球体.docx

Android OpenGL入门实例:绘制球体相比曲线而言,曲面的坐标计算要复杂许多。在其他OpenGL平台上,绘制一个球体也就是一个GLU API 的事,但是Android为上GLU被严重削减了,总共不到10个API。不过我们可以很方便的将它们的源码拷贝过来。这里要说的是大家不必纠结于算法的实现(通过修改参数,可以大致了解算法过程),在实际应用中,都是通过3ds max建好模型然后导入到Open...

weixin_29281941的博客 283

android OpenGL ES 地球仪绘制——球体绘制及纹理映射——源码

支持如下: (1)opengl es绘制三角形拼成球体 (2)图片作为纹理映射到整个球面上 (3)双点触控缩放球体 (4)拖动旋转球体

OpenglES2.0 for Android:来画个矩形吧

OpenglES2.0 for Android:来画个矩形吧 上一节中我们绘制了一个三角形,我们在上一节的基础上来完成矩形的绘制 。 OK,开始动手做吧,首先在上一节的项目中的shape目录下新建一个类——Square (Square.java),然后定义矩形的四个顶点的坐标,此时代码如下(Square.java): package com.cumt.shape;

cassiePython的专栏 7743

Android平台openg es实现的CoverFlow特效源码

个人实现的类似于苹果的coverflow(封面)特效,带有倒影,边缘淡入淡出,封面图片数和切换效果都有宏定义,可自行定制;若有更好建议,或不明白可以联系作者 6047621@qq.com

LoRa项目实战:手把手教你为ESP32选配和焊接天线(从PCB到信号测试)

本文详细介绍了为ESP32选配和焊接LoRa天线的全流程,包括天线选型、PCB布局设计、焊接工艺及信号测试。重点解析了PCB板载天线、导线天线和陶瓷贴片天线的适用场景与性能特点,并提供专业的焊接技巧和信号测试方案,帮助开发者优化LoRa模块的无线通信性能。

weixin_30470643的博客 393

OpenglES2.0 for Android:再谈纹理映射

OpenglES2.0 for Android:再谈纹理映射 上一节我们实现了一个简单的纹理映射的例子——一个简单的贴图,这节我们来做一些稍微复杂一点的例子,最后再使用我们前面实现的立方体来做一个骰子。 纹理拉伸  重复拉伸方式 这种是经常使用的一张纹理拉伸方式,常用于绘制一些重复的元素,比如我们在游戏绘制一幅方格式的地图时。使用重复拉伸方式

cassiePython的专栏 8027

【笔记】2022.6.7 数据分析概论

已完结

SpriteNym的博客 1372

OpenGL.ES在Android上的简单实践:13-全景(画个球)

OpenGL.ES在Android上的简单实践: 13-全景(画个球) 1、画个球 继续上一节的操作,我们已经通过两次for循环遍历了一个球的所有网格矩形的顶点,并用List存储起来。并且用另外的一个List存储所要画的三角形顶点的索引值。接下来,我们就要开始使用VBO-IBO画出网格矩形,最终画出整个球体出来。 private void initVertexData...

vx number:zzr_admin,拉入技术交流群。 1915

保姆级教程:用OSSH免费版+FreeRADIUS+FreeAC NAC,从零搭建一套企业级无线Portal认证系统

本文提供了一套基于OSSH免费版、FreeRADIUS和FreeAC NAC的企业级无线Portal认证系统搭建教程。从环境规划、核心组件安装到认证策略与用户管理,详细介绍了如何利用开源工具构建高效、安全的认证体系,特别适用于预算有限但需求严格的企业场景。

weixin_27032989的博客 392

【OpenClaw企业级智能体实战】第32篇:政企版OpenClaw安全落地指南——奇安信55页报告深度拆解与实战

2026年Q2,OpenClaw(俗称“龙虾”)安全风险集中爆发,公安部、工信部等监管机构密集发声,23万公网暴露实例、155个高危漏洞让企业“养虾”安全压力骤增。奇安信发布的55页《政企版龙虾安全使用指南》,以“看得清、管得住、用得好”为核心,构建了“端-网-云”三层防护体系。本文深度拆解这份报告的九大安全面与三大趋势,全景扫描奇安信、腾讯、360等头部厂商安全方案,提炼企业最低安全基线与实操配置,通过金融机构虚拟案例演示落地全流程,提供从资产摸底、规范制定到工具部署的完整解决方案。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 572

Android OpenGLES2.0(六)——构建圆锥、圆柱和球体

之前的博客中,我们绘制了三角形、正方形、圆形、立方体,今天我们将绘制圆锥、圆柱和球体。能够绘制这些基本的常规几何形体后,其他的常见几何形体的绘制对于我们来说就基本没问题了。绘制圆锥由之前的博客,我们大家也应该都知道了,OpenGL ES2.0中物体的绘制重点就是在于把这个物体表面分解成三角形,分解成功后,绘制自然就不成问题了。圆锥我们很容易就能想到把它拆解成一个圆形和一个锥面,锥面的顶点与圆形的顶点

偶尔记录的一些学习笔记 1万+

Jenkins自动化部署服务到Kubernetes环境

通过Jenkins实现自动化部署可以大大提高软件交付的效率和质量。本文介绍的部署流程涵盖了从代码编译、Maven依赖管理、Docker镜像构建到Kubernetes部署的完整流程,并提供了通知机制以便及时了解部署状态。特别需要注意的是Maven与私服的配置,这是确保构建过程能够正常访问依赖包的关键。通过Jenkins的凭据管理功能,可以安全地管理私服的认证信息,避免敏感信息泄露。在实际应用中,您可能需要根据具体的项目需求和环境特点调整部署脚本。

探索云原生与智能化驱动下的安全运维新范式。关注DevSecOps、可观测性、AIOps等前沿领域,与您共赴技术前沿。 527

OpenglES2.0 for Android:来画个圆吧

OpenglES2.0 for Android:来画个圆吧 首先看看本节的流程: 计算圆的顶点坐标: 我们先要明白OpenglES中圆是怎么画的,前面我们已经知道三角形扇的绘制方式,我们的圆其实也可以看成以圆心为中心点的三角形扇,如下图所示: 看到圆的内部是一个正多边形,当我们的正多边形的边数(或三角形的个数)足够多的话,我们肉眼看起来就变成

cassiePython的专栏 1万+

基于Dify实现对Excel的数据分析

在dify部署完成后,大家就可以基于此进行各种应用场景建设,目前dify支持聊天助手(包括对话工作流)、工作流、agent等模式的场景建设,我们在日常工作中经常会遇到各种各样的数据清洗、格式转换处理、数据统计成图等数据分析工作,本次主要基于对话工作流模式对Excel文件、csv文件进行解析处理,并进行成图等数据分析工作。主要用到的插件有LLM节点,文档提取器、参数提取器、自定义代码节点、echart插件等。实现解析Excel数据,经过上述不同节点的处理分析流程,最终实现数据统计图展示。

hhue2007的专栏 1万+

YOLO26涨点改进| CVPR 2026 | 独家创新首发、特征融合改进篇 | 引入 LFSB 差分双维注意融合模块,通过交替特征融合与分离策略,能够精准区分目标特征,顶会助力YOLO26有效涨点

本文提出LSFB差分双维注意融合模块,用于改进YOLO26目标检测模型。该模块通过融合-分离交替策略和差分注意力机制,有效提升模型在复杂场景下的特征分离能力,特别是在处理重叠物体或反射干扰时表现优异。LSFB采用双向投影、双维注意力计算和跨流减法算子,实现特征共享与独立提取的平衡。实验表明,该模块能显著减少特征混淆,提高检测精度和鲁棒性。文章还详细介绍了模块实现的核心代码、YAML配置文件修改方法以及三种改进方案,为YOLO26模型性能提升提供了创新解决方案。

Ai缝合怪、助力小伙伴高效发论文 326

opengles 绘制球

1. 准备知识gles最基本的图元时三角形,复杂的图元都可以分解为三角形 球有经纬度,根据经纬度可以将球分解为四边形,再将四边形分解为三角形。现在只需要求出四边形的坐标即可。 任意球面上的点,三维坐标 (x0, y0, z0) 计算:(R为球半径)x0 = R * cos(a) * sin(b); y0 = R * sin(a); z0 = R * cos(a) * cos(b);demo:

with_dream的博客 2168

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android OpenGLES2.0(十七)——球形天空盒VR效果实现

在3D游戏中通常都会用到天空盒,在3D引擎中也一般会存在天空盒组件,让开发者可以直接使用。那么天空盒是什么?天空盒又是如何实现的呢?本篇博客主要介绍如何在Android中利用OpenGLES绘制一个天空盒,并实现VR效果。天空盒、天空穹、天空球和VR虽然大多数人知道这些东西是啥,但是我觉得我还是有必要把他们的定义“搬”过来,万一有人不知道呢。 天空盒(Sky Box)是放到场景中的一个立方体,经常是

偶尔记录的一些学习笔记 1万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

OpenGL ES之十二——地球仪和VR图

一 地球仪 1.1 不会动的地球仪 顶点 #version 300 es in vec4 aPosition; in vec2 aCoordinate; //顶点着色器 uniform mat4 uProjMatrix; uniform mat4 uViewMatrix; uniform mat4 uModelMatrix; uniform mat4 uRotateMatrix; out vec2...

gongxiaoou的博客 6372

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

从零开始学OpenGLES开发——第四章

这一章主要讲变换,所以能物体的外观什么的就不在乎了。前面三章的演示程序里面,视角视线都是固定死的。 既然视线和视角都要运动,那么就需要一个变量因子随时间变化而变化,然后动态修改每一次渲染的时候我们的视角和视线。 为了容易观察,我们需要设置一个参考系(默认屏幕背景全黑,根本感觉不到哪是天,哪是地)。在3D世界里唯一的参考系就是坐标是死的,其他的任何模型都是人加进去的,所以不准确。 所以

「花岗岩是甜的」的专栏 2585

OpenGL---实例 球体 画圆锥

用OpenGL 的接口直接创出对应的实心球,圆锥体,圆环

heyuchang666的专栏 1万+

opengles拾取,碰撞检测,相交检测

本例用AABB来实现opengl中的拾取功能,AABB在opengl中可用来做相交检测,碰撞检测,本例用于检测鼠标指向的射线是否和物体相交 AABB实现类 template class AxisAlignedBox { public: enum Extent { EXTENT_NULL, //是否被初始

hb707934728的博客 2812

qt opengl 3d基本形状圆锥

   圆锥与上一节的圆柱很相似,其侧面的顶点坐标同样拆分成很多个小三角形,顶点位于一点,底面顶点和圆柱计算底面顶点的方法一样,都是(r*cos(弧度),-h/2,r*sin(弧度));底面顶点纹理坐标的计算是一样的,而顶点的纹理坐标就是(0.5,1)了;其法向量计算有所不同;       顶点的法向量为各个棱所在法向量的平均值,由于圆锥为对称图形,可知法向量为(0,1,0);       底面...

wanghualin033的博客 1926

OpenglES2.0 for Android:来画个立方体吧

OpenglES2.0 for Android:来画个立方体吧 前言: 前面一直在说OpenglES2.0二维图形的绘制,接下来我们步入三维的世界 ,三维世界远比二维要有趣的多,与此同时复杂性也要高得多,在unity3D中我们可以很容易的就创建 一个立方体,而在OpenglES2.0中这个过程要复杂得多,但是更加有趣 。先来看下我们的整个流程:

cassiePython的专栏 8233

OpenglES2.0 for Android:各种变换来一波

OpenglES2.0 for Android:各种变换来一波 监听屏幕事件 在进行各种变换之前,我们先来了解一下如何监听屏幕的事件。我们下面的变换都需要用立方体来演示,所以我们继续使用上一节的绘制立方体的内容 首先新建一个项目 OpengESChange ,将上一节中关于绘制立方体的代码复制过来 。在前面我们一直在使用 android.opengl.GLSurfaceView

cassiePython的专栏 6884
上一篇: OpenglES2.0 for Android:各种变换来一波
下一篇: OpenglES2.0 for Android:纹理映射
cassiePython
博客等级 码龄12年 303粉丝 135原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值