OpenglES2.0 for Android:来做个地球吧

OpenGL ES 实现 Android 3D 地球仪绘制及交互 OpenGL ES(Open Graphics Library for Embedded Systems)是OpenGL的子集,专为移动设备设计的3D图形API。它支持多种图形处理任务,并以高效的性能著称,被广泛应用于移动游戏和应用程序开发中。 阅读详情

OpenglES2.0 for Android:来做个地球吧

前言 

上两节中我们说了纹理映射,也利用纹理给我们的平面图形以及立方体穿上了漂亮的衣服,在继续学习其他知识之前,让我们先来用纹理映射以及我们前面做的球
来实现一个地球的贴图。整体效果如下 图所示:



素材资源下载 :http://download.youkuaiyun.com/detail/cassiepython/9551772
里面放了两张图片,都是可以用的,我们用其中一张就可以。

Ok , 现在回到我们前面绘制球的项目(http://blog.youkuaiyun.com/cassiepython/article/details/51620114),前面我们已经完成了球的绘制,而且使用了棋盘纹理,

这次我们需要使用上面的图片来做纹理贴图,所以我们先删除掉原来的关于棋盘纹理的代码。然后将纹理工具类copy到工具类目录下,准备工作完成。

(最后会给出整个项目的代码,如果你不想从原来的开始改的话可以直接看这个)


看下我们的步骤 :

1 修改着色器代码加入纹理

 这个在上两节已经说过,直接看更改后的代码:

 

<span style="font-size:12px;">//vertex_shader_ball.glsl
uniform mat4 u_Matrix;//最终的变换矩阵
attribute vec4 a_Position;//顶点位置
attribute vec2 a_TextureCoordinates;
varying vec2 v_TextureCoordinates;
void main()                    
{                              
    gl_Position = u_Matrix * a_Position;
    v_TextureCoordinates = a_TextureCoordinates;	 
} </span>

<span style="font-size:12px;">//fragment_shader_ball.glsl
precision mediump float;
uniform sampler2D u_TextureUnit;      	 								
varying vec2 v_TextureCoordinates;
void main()                         
{
   gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);  
}   </span>

2 纹理坐标计算 

前面我们说过做纹理贴图最关键的地方是确定我们的顶点坐标与纹理坐标的对应关系。对于二维的图像以及比较规则的三维图像比较容易确定,但是对于球该如何处理呢?看我们原先是如何计算球的顶点坐标的。我们通过半径r (确定量)和两个角度 θ (范围0到180)和φ(范围0到360)来计算绘制球时的一个小方格的左上角顶点的坐标,同时知道分割的间距singleSpan  ,由此可以确定这个小方格的其余三个顶点坐标。同理我们如何能确定左上角顶点坐标的对应的纹理坐标,其余的也就容易求了。于是问题转化成这样:要求一个球的纹理坐标只需要确定绘制球的某个小方格的四个顶点对应的纹理坐标,进一步讲如何确定小方格的左上角顶点与相应纹理坐标的关系。

现在我们以及清楚了问题,下面考虑具体的。我们绘制球时是一个个的小方格(矩形),纹理应该也是分成一个个的小方格(矩形),然后与球的一个个的小方格一一对应。绘制球的确定小方格位置的两个变量(θ 和φ)的范围分别为 0 到180 ,0到360 ,对应纹理的T (1到0 ,注意为什么不是0到1 见上一节最后)和 S ( 0到1), 于是通过比例g关系我们有如下:

当前角度 θ /  180  = 1– 纹理 t坐标 / 1

当前角度φ / 360 = 纹理 s坐标 / 1

通过这两个角度我们确定了顶点坐标也确定了相应的纹理坐标,由此我们就知道了顶点对应的纹理坐标。下面我们就可以具体编码实现了。


此时Ball.java代码如下 :

package com.cumt.shape;

import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.glActiveTexture;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glUniform1i;
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.openglesearth.R;
import com.cumt.utils.MatrixState;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import com.cumt.utils.TextureHelper;

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 static final int TEXTURE_COORDIANTES_COMPONENT_COUNT = 2; // 每个纹理坐标为 S T两个
    private static final String A_TEXTURE_COORDINATES = "a_TextureCoordinates";//纹理
	private static final String U_TEXTURE_UNIT = "u_TextureUnit";//纹理
	private FloatBuffer textureBuffer;// 纹理坐标
	private int uTextureUnitLocation;
    private int aTextureCoordinates;
    private int texture;
	// ***********************************************************************
	
	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);
		// ***********************************************************************
		initTexture();
		// **********************************************************************
		//---------传入顶点数据数据
		GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,
						GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aPositionLocation);
		
		// ***********************************************************************
		GLES20.glVertexAttribPointer(aTextureCoordinates, TEXTURE_COORDIANTES_COMPONENT_COUNT,
				GLES20.GL_FLOAT, false, 0, textureBuffer);
		GLES20.glEnableVertexAttribArray(aTextureCoordinates);
		// **********************************************************************
		
	}

	public void initVertexData() {
		ArrayList<Float> alVertix = new ArrayList<Float>();// 存放顶点坐标的ArrayList
		// ***************************************
		ArrayList<Float> textureVertix = 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)));
				
				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);

				// *****************************************************************
				float s0 = hAngle / 360.0f;
				float s1 = (hAngle + angleSpan)/360.0f ;
				float t0 = 1 - vAngle / 180.0f;
				float t1 = 1 - (vAngle + angleSpan) / 180.0f;
				
				textureVertix.add(s1);// x1 y1对应纹理坐标
				textureVertix.add(t0);
				textureVertix.add(s0);// x3 y3对应纹理坐标
				textureVertix.add(t1);
				textureVertix.add(s0);// x0 y0对应纹理坐标
				textureVertix.add(t0);
				
				// *****************************************************************
				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);
				
				// *****************************************************************
				textureVertix.add(s1);// x1 y1对应纹理坐标
				textureVertix.add(t0);
				textureVertix.add(s1);// x2 y3对应纹理坐标
				textureVertix.add(t1);
				textureVertix.add(s0);// x3 y3对应纹理坐标
				textureVertix.add(t1);
				// *****************************************************************
			}
		}
		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);
        // *****************************************************************
        float textures[] = new float[textureVertix.size()];
        for(int i=0;i<textureVertix.size();i++){
        	textures[i] = textureVertix.get(i);
        }
        textureBuffer = ByteBuffer
    			.allocateDirect(textures.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐标们加入FloatBuffer中
        textureBuffer.put(textures);
        // 设置buffer,从第一个坐标开始读
        textureBuffer.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);
    }
    
    // *******************************************************
    //初始化加载纹理
    private void initTexture(){
    	aTextureCoordinates = GLES20.glGetAttribLocation(program, A_TEXTURE_COORDINATES);
		uTextureUnitLocation = GLES20.glGetAttribLocation(program, U_TEXTURE_UNIT);
		texture = TextureHelper.loadTexture(context, R.drawable.logo,false);
		// Set the active texture unit to texture unit 0.
        glActiveTexture(GL_TEXTURE0);
        // Bind the texture to this unit.
        glBindTexture(GL_TEXTURE_2D, texture);
        // Tell the texture uniform sampler to use this texture in the shader by
        // telling it to read from texture unit 0.
        glUniform1i(uTextureUnitLocation, 0);
    }
    // *******************************************************
    public void draw(){
    	//将最终变换矩阵写入
		GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);
		GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }
}
其中 //****************************与 //**********************************之间的内容是我们相比原来绘制球新增加的内容。

相比前面的知识并没有新增什么,只是要注意纹理坐标的求法。
运行结果就如我们开头处展示的那样,这样使用原来会只球的代码,点击屏幕会绕y轴旋转,大家可以自由发挥

增添一些额外的变换。


3 源码下载

最后给出源码下载 

http://download.youkuaiyun.com/detail/cassiepython/9551962






android OpenGL ES 地球仪绘制——球体绘制及纹理映射——源码 支持如下: (1)opengl es绘制三角形拼成球体 (2)图片作为纹理映射到整个球面上 (3)双点触控缩放球体 (4)拖动旋转球体 立即下载

相关推荐

Android旋转的地球源码

一个Android的旋转地球效果,用来做界面非常好,用的是3d做的,不是帧动画

OpenGL ES for Android 绘制旋转的地球

No 图 No Code,我们先来欣赏下旋转的地球: 是不是很酷炫,要想绘制出上面酷炫的效果需要3个步骤: 计算球体顶点数据 地球纹理贴图 通过MVP矩阵旋转地球 计算球体顶点数据 我们知道OpenGL中最基本的图元是三角形,任何复杂的图形都可以分解为一个个的三角形,球体也不例外,假设球体上有“经纬度”,通过“经纬度”将球体分割为一个个的四边形,如下图: 在把这些四边形分割为2个三角形,所...

老孟Flutter 7284

简单的Android地球旋转的例子

简单的Android地球旋转的例子AndroidEarthAnimation

【小沐学GIS】基于Android绘制三维数字地球Earth(OpenGL)

Android是一个开源的,基于Linux的移动设备操作系统,主要使用于移动设备,如智能手机和平板电脑。Android是由谷歌及其他公司带领的开放手机联盟开发的。

爱看书的小沐 4190

mapbox-gl-native,在原生android、ios、macos、node.js和qt应用程序中提供交互式、完全可定制的地图,由vector tiles和opengl提供支持.zip

一个库,用于将交互式、可自定义的矢量地图嵌入到多个平台上的本机应用程序中。它接受符合mapbox样式规范的样式表,将它们应用于符合mapbox矢量平铺规范的矢量平铺,并使用opengl进行渲染。mapbox gl js是基于web gl的对应项,设计用于web。

从BIOS到路由器:深入拆解SPI NOR Flash的硬件连接与‘芯片内执行’(XIP)奥秘

本文深入解析SPI NOR Flash的硬件连接与‘芯片内执行’(XIP)技术,从BIOS到路由器的应用场景出发,详细介绍了其架构精髓、典型连接方案、时序设计及性能优化方法。通过实际案例和参数对比,帮助开发者掌握NOR Flash在嵌入式系统中的关键作用与设计技巧,提升电路设计效率与可靠性。

weixin_30522183的博客 491

在android与debian上用opengles2绘制一个3D的旋转地球

换了个公司, 工作内容bian

Jim_Jing的专栏 2395

数据库和BI工程师面试题

 一.数据库 1.Oracle数据库,视图与表的区别?普通视图与物化视图的区别?物化视图的作用? 2.Oracle数据库,有哪几类索引,分别有什么特点? 3.Union与Union All的区别? 4.对游标的理解?游标的分类?使用方法? 5.如何查找和删除表中的重复数据?给出方法或SQL。 6.不借助第三方工具,怎么查看SQL的执行计划? 7.创建索引有哪些需要注意的要点?

web_go_run的专栏 1万+

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

DLPFC.h5ad格式数据简便获取方式+STAGATE论文复现问题

简便获取DLPFC.h5ad格式的数据方式

apple_74057836的博客 2257

ESP32-P4开发板实战:从零配置VSCode环境到点亮MIPI-DSI屏幕(避坑指南)

本文详细介绍了ESP32-P4开发板在VSCode环境下的配置流程,包括SDK安装、idf_component.yml依赖管理,以及MIPI-DSI屏幕驱动的实现方法。通过实战指南帮助开发者避开常见配置陷阱,快速完成从环境搭建到屏幕点亮的全流程,适用于物联网和嵌入式开发场景。

pp12345的博客 741

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

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

android开发笔记 768

CH340驱动安装全攻略:从Windows到MacOS的避坑指南(2025最新版)

本文提供2025年最新版CH340驱动安装全攻略,涵盖Windows、MacOS和Linux三大操作系统。详细解析了驱动安装的核心原理、标准流程,并针对Windows设备管理器报错、MacOS系统安全限制等常见“坑点”提供了深度排错与解决方案,旨在帮助开发者快速稳定地完成USB转串口通信配置。

earth的博客 426

视频教程-OpenGLES自定义相机-Android

OpenGLES自定义相机 从事Android移动端开发多年。讲解过多款视频...

weixin_27718667的博客 336

GEE APP:基于Sentinel-2遥感影像的植被指数(NDVI)和水体指数(NDWI)可视化应用

本文介绍了利用Google Earth Engine(GEE)平台处理Sentinel-2卫星数据的方法,重点讲解NDVI(归一化植被指数)和NDWI(归一化水体指数)的计算与应用。内容包括环境准备、数据加载与处理、指数计算原理、可视化方法以及实际应用案例。教程详细展示了如何定义研究区域、加载影像数据、进行指数运算,并生成专业统计报告和图例。文章还提供了常见问题解答和最佳实践建议,为生态环境监测、农业评估和水资源管理等场景提供了实用工具。通过JavaScript代码示例,读者可以快速掌握GEE平台的遥感影像

此星光明博客 272

机器学习笔记 - 神经辐射场(NeRF)的简要概述

神经辐射场十分重要。在表示和渲染 3D 场景领域,神经辐射场 (NeRF) 在准确性方面取得了巨大突破。给定底层场景的多个图像,NeRF 可以从任意视点重建该场景的高分辨率、2D 渲染图。与局部光场融合 (LLFF) 和场景表示网络 (SRN) 等现有技术相比,NeRF 更能够捕获场景外观和几何形状的复杂组成部分(例如,依赖于视图的反射和复杂的材料)。NeRF的研究目的是合成同一场景不同视角下的图像。

学以致用 知行合一 1692

OpenGL ES for Android 总览

经过半年的准备OpenGL ES for Android系列文章终于要和大家见面了,在这里定一个小目标-先吸引1000个粉丝,万一实现了呢。写关于OpenGL ES的文章开始是有一些犹豫的,因为OpenGL ES的一些概念非常晦涩难懂,很多需要懂得计算机图形算法学相关的知识,您可能学了很久都找不到门道,知其然不知其所以然是常有的事。 本系列的文章并不会深入的研究计算机图形算法相关的知识,而是从工...

老孟Flutter 5744

华为OD机试 - 停车场费用统计 - HashSet(Python/JS/C/C++ 双机位C卷 100分)

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。停车场统计当日总收费,包月的车不统计,不包月的车半个小时收一块钱,不满半小时不收费,如果超过半小时,零头不满半小时按半小时算,每天11:30-13:30时间段不收费,如果一辆车停车时间超过8小时后不收费。现提供停车场进出车辆的统计信息,需要你来计

学Java,找哪吒 238

NDK_OpenGLES_3_0环境配置:从零搭建Android OpenGL开发环境

NDK_OpenGLES_3_0是一套Android OpenGL ES 3.0从入门到精通的系统性学习教程,通过本指南,你将快速掌握如何从零搭建完整的Android OpenGL开发环境,开启高效的图形开发之旅。 ## 📋 开发环境准备清单 搭建Android OpenGL ES 3.0开发环境需要准备以下工具和资源: - Android Studio 4.0及以上版本 - NDK 21.

gitblog_01139的博客 886

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

OpenGL ES之二——Android中的OpenGL ES概述

概述 上一篇主要想要脱离Android平台介绍一下OpenGL和OpenGL ES到底是什么,从本篇起开始从零开始搭建自己的Android平台下OpenGL ES知识体系。 一.Android基本架构中OpenGL ES 1.1 OpenGL ES在Android的基本架构中位置 如下图,我们从Android的基本架构中找到OpenGL ES的位置。 OpenGL ES就在Libraries里面...

gongxiaoou的博客 3685

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

ndk jni Android OpenGL es 2.0 课程分享

根据android3d游戏开发技术宝典的教程改成ndk版

chrisfxs的专栏 1350

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

在Android中使用OpenGL ES进行开发第(二)节:定义图形

  一、前期基础知识储备 笔者计划写三篇文章来详细分析OpenGL ES基础的同时也是入门关键的三个点: ①OpenGL ES是什么?与OpenGL的关系是什么?——概念部分 ②使用OpenGLES绘制2D/3D图形的第一步:定义图形;——运用部分 ③使用OpenGL ES绘制出②步骤中定义好的图形:——运用部分,难点所在 通过这三篇文章的分析,就像给万丈高楼垫定了基石,万丈高楼平地起...

Chin_Style的博客 5718
上一篇: OpenglES2.0 for Android:再谈纹理映射
下一篇: Android NDK : NDK开发概要
cassiePython
博客等级 码龄12年 303粉丝 135原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值