├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── .DS_Store │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── drawable │ │ │ │ ├── back.png │ │ │ │ ├── front.png │ │ │ │ ├── left.png │ │ │ │ ├── right.png │ │ │ │ ├── top.png │ │ │ │ ├── bottom.png │ │ │ │ ├── texture.jpg │ │ │ │ ├── heightmap.png │ │ │ │ ├── air_hockey_surface.png │ │ │ │ ├── main_tv_bg.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-nodpi │ │ │ │ └── heightmap.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── raw │ │ │ │ ├── color_fragment_shader.glsl │ │ │ │ ├── heightmap_fragment_shader.glsl │ │ │ │ ├── color_vertex_shader.glsl │ │ │ │ ├── skybox_fragment_shader.glsl │ │ │ │ ├── texture_fragment_shader.glsl │ │ │ │ ├── texture_vertex_shader.glsl │ │ │ │ ├── heightmap_vertex_shader.glsl │ │ │ │ └── skybox_vertex_shader.glsl │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── wxplus │ │ │ │ └── opengles2forandroid │ │ │ │ ├── utils │ │ │ │ ├── ShaderHelper.java │ │ │ │ ├── GlobalConfig.java │ │ │ │ ├── GLog.java │ │ │ │ ├── Constants.java │ │ │ │ └── TextureUtils.java │ │ │ │ ├── obj │ │ │ │ ├── base │ │ │ │ │ ├── Circle.java │ │ │ │ │ ├── Point.java │ │ │ │ │ ├── Square.java │ │ │ │ │ ├── Cylinder.java │ │ │ │ │ └── Mallet.java │ │ │ │ ├── Table.java │ │ │ │ ├── Puck.java │ │ │ │ ├── Skybox.java │ │ │ │ ├── HeightMap.java │ │ │ │ └── Object.java │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── programs │ │ │ │ ├── HeightMapShaderProgram.java │ │ │ │ ├── ColorShaderProgram.java │ │ │ │ ├── SkyboxShaderProgram.java │ │ │ │ ├── TextureShaderProgram.java │ │ │ │ └── ShaderProgram.java │ │ │ │ ├── data │ │ │ │ └── IndexBuffer.java │ │ │ │ ├── OpenGL_04_Skybox.java │ │ │ │ ├── OpenGL_03_Simple_Object.java │ │ │ │ ├── OpenGL_01_Simple_Color.java │ │ │ │ ├── OpenGL_05_HeightMap.java │ │ │ │ └── OpenGL_02_Simple_Texture.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── wxplus │ │ │ └── opengles2forandroid │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── wxplus │ │ └── opengles2forandroid │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── .DS_Store ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── markdown-navigator │ └── profiles_settings.xml ├── vcs.xml ├── modules.xml ├── runConfigurations.xml ├── misc.xml └── markdown-navigator.xml ├── gradle.properties ├── README.md ├── .gitignore ├── gradlew.bat ├── gradlew └── LICENSE /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/.DS_Store -------------------------------------------------------------------------------- /app/src/main/res/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/.DS_Store -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | OpenGL ES 2 for Android 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/front.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/left.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/right.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/top.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/bottom.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/texture.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/heightmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/heightmap.png -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-nodpi/heightmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-nodpi/heightmap.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/air_hockey_surface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/drawable/air_hockey_surface.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/raw/color_fragment_shader.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform vec4 u_Color; 4 | 5 | void main() 6 | { 7 | gl_FragColor = u_Color; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxplus/OpenGL-ES-2.0-for-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/raw/heightmap_fragment_shader.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | varying vec3 v_Color; 4 | 5 | void main() 6 | { 7 | gl_FragColor = vec4(v_Color, 1.0); 8 | } 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/raw/color_vertex_shader.glsl: -------------------------------------------------------------------------------- 1 | uniform mat4 u_Matrix; // 正交变换 2 | 3 | attribute vec4 a_Position; // 外部赋值 4 | 5 | void main() { 6 | 7 | gl_Position = u_Matrix * a_Position; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/utils/ShaderHelper.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.utils; 2 | 3 | /** 4 | * @author WangXiaoPlus 5 | * @date 2017/11/19 6 | */ 7 | 8 | public class ShaderHelper { 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/res/raw/skybox_fragment_shader.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform samplerCube u_TextureUnit; 4 | varying vec3 v_Position; 5 | 6 | void main() 7 | { 8 | gl_FragColor = textureCube(u_TextureUnit, v_Position); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/raw/texture_fragment_shader.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform sampler2D u_TextureUnit; 4 | 5 | varying vec2 v_TextureCoordinates; 6 | 7 | void main() 8 | { 9 | gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates); 10 | } 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Oct 29 15:13:28 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/utils/GlobalConfig.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.utils; 2 | 3 | /** 4 | * @author WangXiaoPlus 5 | * @date 2017/11/19 6 | */ 7 | 8 | public class GlobalConfig { 9 | public static final boolean DEBUG = true; // 是否是debug模式 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_tv_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/base/Circle.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj.base; 2 | 3 | public class Circle { 4 | public Point center; // 圆心 5 | public float radius; // 半径 6 | 7 | public Circle(Point center, float radius) { 8 | this.center = center; 9 | this.radius = radius; 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/res/raw/texture_vertex_shader.glsl: -------------------------------------------------------------------------------- 1 | uniform mat4 u_Matrix; // 正交变换 2 | 3 | attribute vec4 a_Position; // 顶点坐标 4 | attribute vec2 a_TextureCoordinates; // Texture坐标 5 | 6 | varying vec2 v_TextureCoordinates; // 透传给Fragment Shader 7 | 8 | void main() 9 | { 10 | v_TextureCoordinates = a_TextureCoordinates; 11 | gl_Position = u_Matrix * a_Position; 12 | 13 | } -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/base/Point.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj.base; 2 | 3 | /** 4 | * @author WangXiaoPlus 5 | * @date 2017/11/20 6 | */ 7 | 8 | public class Point { 9 | public float x, y, z; 10 | 11 | public Point(float x, float y, float z) { 12 | this.x = x; 13 | this.y = y; 14 | this.z = z; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/raw/heightmap_vertex_shader.glsl: -------------------------------------------------------------------------------- 1 | uniform mat4 u_Matrix; 2 | attribute vec3 a_Position; 3 | varying vec3 v_Color; 4 | 5 | void main() 6 | { 7 | v_Color = mix(vec3(0.180, 0.467, 0.153), // A dark green 8 | vec3(0.660, 0.670, 0.680), // A stony gray 9 | a_Position.y); 10 | 11 | gl_Position = u_Matrix * vec4(a_Position, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/base/Square.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj.base; 2 | 3 | 4 | public class Square { 5 | public Point center; 6 | public float widht; 7 | public float height; 8 | 9 | public Square(Point center, float widht, float height) { 10 | this.center = center; 11 | this.widht = widht; 12 | this.height = height; 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/base/Cylinder.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj.base; 2 | 3 | 4 | public class Cylinder { 5 | public Point center; // 中心 6 | public float radius; // 半径 7 | public float height; // 高度 8 | 9 | public Cylinder(Point center, float radius, float height) { 10 | this.center = center; 11 | this.radius = radius; 12 | this.height = height; 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/test/java/wxplus/opengles2forandroid/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/raw/skybox_vertex_shader.glsl: -------------------------------------------------------------------------------- 1 | uniform mat4 u_Matrix; 2 | attribute vec3 a_Position; 3 | varying vec3 v_Position; 4 | 5 | void main() 6 | { 7 | v_Position = a_Position; 8 | // // Make sure to convert from the right-handed coordinate system of the 9 | // // world to the left-handed coordinate system of the cube map, otherwise, 10 | // // our cube map will still work but everything will be flipped. 11 | v_Position.z = -v_Position.z; 12 | // 13 | gl_Position = u_Matrix * vec4(a_Position, 1.0); 14 | gl_Position = gl_Position.xyww; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/utils/GLog.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.utils; 2 | 3 | import android.util.Log; 4 | 5 | import static wxplus.opengles2forandroid.utils.GlobalConfig.DEBUG; 6 | 7 | /** 8 | * @author WangXiaoPlus 9 | * @date 2017/11/19 10 | */ 11 | 12 | public class GLog { 13 | 14 | public static void d(String tag, String msg) { 15 | if (DEBUG) { 16 | Log.d(tag, msg); 17 | } 18 | } 19 | public static void e(String tag, String msg) { 20 | if (DEBUG) { 21 | Log.e(tag, msg); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/utils/Constants.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.utils; 2 | 3 | 4 | /** 5 | * Created by hi on 2017/10/29. 6 | */ 7 | 8 | public class Constants { 9 | public static final int BYTES_PER_FLOAT = 4; // 一个float有4个byte 10 | public static final int BYTES_PER_SHORT = 2; // 一个short有2个byte 11 | 12 | public static final int FLOATS_PER_VERTEX = 3; // 一个顶点用三个float表示(x, y, z) 13 | public static final int FLOATS_PER_TEXTURE_VERTEX = 2; // texture的一个顶点用2个float表示 14 | 15 | public static final int VERTEX_COUNT_SQUARE = 4 + 1 + 1; // 正方形需要几个Vertex 16 | } 17 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | 9 | /** 10 | * Created by hi on 2017/10/29. 11 | */ 12 | 13 | public class BaseActivity extends AppCompatActivity { 14 | 15 | protected Activity mActivity; 16 | 17 | @Override 18 | protected void onCreate(@Nullable Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | mActivity = this; 21 | setTitle(getClass().getSimpleName()); 22 | } 23 | 24 | public void startActivity(Class cls) { 25 | startActivity(new Intent(this, cls)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 项目说明 2 | 3 | 本项目包含了若干个OpenGL 2.0在Android上的应用的例子, 4 | 5 | ## 功能列表 6 | 7 | - OpenGL_01_Simple_Color 实现最基本的绘制正方形 8 | - OpenGL_02_Simple_Texture 实现最基本的加载图片Texture 9 | - OpenGL_03_Simple_Object 将绘制的物体进行封装,涉及较多矩阵变换 10 | - OpenGL_04_Skybox 实现最基本的Skybox效果 11 | - OpenGL_05_HeightMap 读取并显示HeightMap,涉及更细致的MVP Matrix的使用。 12 | 13 | ## 项目开发问题记录 14 | 15 | ### OpenGL_01_Simple_Color 16 | 17 | #### 几个可能让图形显示不出来的问题 18 | 19 | 1. 没有调用GLSurfaceView.setEGLContextClientVersion(2)来指定EGLContext的版本; 20 | 2. glsl文件中没有删掉这行代码`#version 120` 21 | 3. 在进行正交变换时,变换的Matrix没有进行Matrix.orithM初始化 22 | 23 | ### OpenGL_02_Simple_Texture 24 | 25 | 未遇到问题 26 | 27 | ### OpenGL_03_Simple_Object 28 | 29 | 未遇到问题 30 | 31 | ### OpenGL_04_Skybox 32 | 33 | 未遇到问题 34 | 35 | ### OpenGL_05_HeightMap 36 | 37 | 在使用IndexBuffer时,数据类型为float时无法显示,改成short就行了,不知为何,后续再深入研究。 38 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/Table.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj; 2 | 3 | 4 | import wxplus.opengles2forandroid.obj.base.Point; 5 | import wxplus.opengles2forandroid.obj.base.Square; 6 | 7 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_VERTEX; 8 | import static wxplus.opengles2forandroid.utils.Constants.VERTEX_COUNT_SQUARE; 9 | 10 | /** 11 | * @author WangXiaoPlus 12 | * @date 2017/11/19 13 | */ 14 | 15 | public class Table extends Object { 16 | protected Point center; 17 | protected float width; 18 | protected float height; 19 | 20 | public Table(Point center, float width, float height) { 21 | this.center = center; 22 | this.width = width; 23 | this.height = height; 24 | mVertexData = new float[VERTEX_COUNT_SQUARE * FLOATS_PER_VERTEX]; 25 | 26 | addSquare(new Square(center, width, height)); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/androidTest/java/wxplus/opengles2forandroid/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("wxplus.opengles2forandroid", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "wxplus.opengles2forandroid" 7 | minSdkVersion 14 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | buildToolsVersion '26.0.2' 20 | compileOptions { 21 | sourceCompatibility JavaVersion.VERSION_1_8 22 | targetCompatibility JavaVersion.VERSION_1_8 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(include: ['*.jar'], dir: 'libs') 28 | implementation 'com.android.support:appcompat-v7:26.0.0' 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/MainActivity.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | 6 | public class MainActivity extends BaseActivity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | getSupportActionBar().setTitle(R.string.app_name); 12 | setContentView(R.layout.activity_main); 13 | // test 14 | click_height_map(null); 15 | } 16 | 17 | 18 | // onclick start 19 | public void click_simple_color(View view) { 20 | startActivity(OpenGL_01_Simple_Color.class); 21 | } 22 | public void click_simple_texture(View view) { 23 | startActivity(OpenGL_02_Simple_Texture.class); 24 | } 25 | public void click_simple_object(View view) { 26 | startActivity(OpenGL_03_Simple_Object.class); 27 | } 28 | public void click_sky_box(View view) { 29 | startActivity(OpenGL_04_Skybox.class); 30 | } 31 | public void click_height_map(View view) { 32 | startActivity(OpenGL_05_HeightMap.class); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/Puck.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj; 2 | 3 | import wxplus.opengles2forandroid.obj.base.Circle; 4 | import wxplus.opengles2forandroid.obj.base.Cylinder; 5 | import wxplus.opengles2forandroid.obj.base.Point; 6 | 7 | /** 8 | * @author WangXiaoPlus 9 | * @date 2017/11/19 10 | *

11 | * 冰球 12 | */ 13 | 14 | public class Puck extends Object { 15 | 16 | public float radius; // 半径 17 | public float height; // 高度 18 | public Point center = new Point(0, 0, 0); // 中心点 19 | public int pointCountAroundCircle; // 圆的顶点数 20 | 21 | public Puck(Point center, float radius, float height, int pointCountAroundCircle) { 22 | this.radius = radius; 23 | this.height = height; 24 | this.center = center; 25 | this.pointCountAroundCircle = pointCountAroundCircle; 26 | 27 | mVertexData = new float[floatSizeOfVertexs(sizeOfCircleInVertex(pointCountAroundCircle) + sizeOfCylinderInVertex(pointCountAroundCircle))]; 28 | addCircle(new Circle(new Point(center.x, center.y, center.z + height / 2), radius), pointCountAroundCircle) 29 | .addOpenCylinder(new Cylinder(center, radius, height), pointCountAroundCircle); 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 16 | 17 | 21 | 22 | 26 | 27 | 31 | 32 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/programs/HeightMapShaderProgram.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.programs; 2 | 3 | import android.content.Context; 4 | 5 | import wxplus.opengles2forandroid.R; 6 | import wxplus.opengles2forandroid.obj.HeightMap; 7 | 8 | import static android.opengl.GLES20.GL_FLOAT; 9 | import static android.opengl.GLES20.glEnableVertexAttribArray; 10 | import static android.opengl.GLES20.glGetAttribLocation; 11 | import static android.opengl.GLES20.glGetUniformLocation; 12 | import static android.opengl.GLES20.glUniformMatrix4fv; 13 | import static android.opengl.GLES20.glUseProgram; 14 | import static android.opengl.GLES20.glVertexAttribPointer; 15 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_VERTEX; 16 | 17 | /** 18 | * @author WangXiaoPlus 19 | * @date 2017/12/17 20 | */ 21 | 22 | public class HeightMapShaderProgram extends ShaderProgram { 23 | 24 | protected final int uMatrixLocation; 25 | protected final int aPositionLocation; 26 | 27 | public HeightMapShaderProgram(Context context) { 28 | super(context, R.raw.heightmap_vertex_shader, R.raw.heightmap_fragment_shader); 29 | uMatrixLocation = glGetUniformLocation(program, U_MATRIX); 30 | aPositionLocation = glGetAttribLocation(program, A_POSITION); 31 | } 32 | 33 | public void bindData(float[] matrix, HeightMap heightMap) { 34 | glUseProgram(program); 35 | // Pass the matrix into the shader program. 36 | glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0); 37 | // 设置顶点数据 38 | glVertexAttribPointer(aPositionLocation, FLOATS_PER_VERTEX, GL_FLOAT, false, 0, heightMap.getVertexBuffer()); 39 | glEnableVertexAttribArray(aPositionLocation); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/base/Mallet.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj.base; 2 | 3 | import wxplus.opengles2forandroid.obj.Object; 4 | 5 | /** 6 | * @author WangXiaoPlus 7 | * @date 2017/11/19 8 | *

9 | * 球棍 10 | */ 11 | 12 | public class Mallet extends Object { 13 | 14 | public Point center; // 中心 15 | public float radiusTop; // 上面的圆柱体的半径 16 | public float heightTop; // 上面的圆柱体的高度 17 | public float radiusBottom; // 上面的圆柱体的半径 18 | public float heightBottom; // 上面的圆柱体的高度 19 | public int pointCountAroundCircleTop; // 顶部圆的顶点数 20 | public int pointCountAroundCircleBottom; // 底部圆的顶点数 21 | 22 | public Mallet(Point center, float radiusTop, float radiusBottom, float heightTop, float heightBottom, int pointCountAroundCircleTop, int pointCountAroundCircleBottom) { 23 | this.radiusTop = radiusTop; 24 | this.radiusBottom = radiusBottom; 25 | this.heightTop = heightTop; 26 | this.heightBottom = heightBottom; 27 | this.center = center; 28 | this.pointCountAroundCircleTop = pointCountAroundCircleTop; 29 | this.pointCountAroundCircleBottom = pointCountAroundCircleBottom; 30 | 31 | mVertexData = new float[floatSizeOfVertexs( 32 | sizeOfCircleInVertex(pointCountAroundCircleTop) + sizeOfCircleInVertex(pointCountAroundCircleBottom) 33 | + sizeOfCylinderInVertex(pointCountAroundCircleTop) + sizeOfCylinderInVertex(pointCountAroundCircleBottom) 34 | )]; // 两个Circle,两个Cylinder 35 | addCircle(new Circle(new Point(center.x, center.y, center.z + heightTop), radiusTop), pointCountAroundCircleTop) 36 | .addCircle(new Circle(new Point(center.x, center.y, center.z), radiusBottom), pointCountAroundCircleBottom) 37 | .addOpenCylinder(new Cylinder(new Point(center.x, center.y, center.z + heightTop / 2), radiusTop, heightTop), pointCountAroundCircleTop) 38 | .addOpenCylinder(new Cylinder(new Point(center.x, center.y, center.z - heightBottom / 2), radiusBottom, heightBottom), pointCountAroundCircleBottom); 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/Skybox.java: -------------------------------------------------------------------------------- 1 | /*** 2 | * Excerpted from "OpenGL ES for Android", 3 | * published by The Pragmatic Bookshelf. 4 | * Copyrights apply to this code. It may not be used to create training material, 5 | * courses, books, articles, and the like. Contact us if you are in doubt. 6 | * We make no guarantees that this code is fit for any purpose. 7 | * Visit http://www.pragmaticprogrammer.com/titles/kbogla for more book information. 8 | ***/ 9 | package wxplus.opengles2forandroid.obj; 10 | 11 | import java.nio.ByteBuffer; 12 | 13 | import static android.opengl.GLES20.GL_TRIANGLES; 14 | import static android.opengl.GLES20.GL_UNSIGNED_BYTE; 15 | import static android.opengl.GLES20.glDrawElements; 16 | 17 | public class Skybox extends Object { 18 | private final ByteBuffer indexArray; 19 | 20 | public Skybox() { 21 | // Create a unit cube. 22 | mVertexData = new float[]{ 23 | -1, 1, 1, // (0) Top-left near 24 | 1, 1, 1, // (1) Top-right near 25 | -1, -1, 1, // (2) Bottom-left near 26 | 1, -1, 1, // (3) Bottom-right near 27 | -1, 1, -1, // (4) Top-left far 28 | 1, 1, -1, // (5) Top-right far 29 | -1, -1, -1, // (6) Bottom-left far 30 | 1, -1, -1 // (7) Bottom-right far 31 | }; 32 | 33 | // 6 indices per cube side 34 | indexArray = ByteBuffer.allocateDirect(6 * 6) 35 | .put(new byte[]{ 36 | // Front 37 | 1, 3, 0, 38 | 0, 3, 2, 39 | 40 | // Back 41 | 4, 6, 5, 42 | 5, 6, 7, 43 | 44 | // Left 45 | 0, 2, 4, 46 | 4, 2, 6, 47 | 48 | // Right 49 | 5, 7, 1, 50 | 1, 7, 3, 51 | 52 | // Top 53 | 5, 1, 4, 54 | 4, 1, 0, 55 | 56 | // Bottom 57 | 6, 2, 7, 58 | 7, 2, 3 59 | }); 60 | indexArray.position(0); 61 | drawTaskList.add(new DrawTask() { 62 | @Override 63 | public void draw() { 64 | glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indexArray); 65 | } 66 | }); 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/data/IndexBuffer.java: -------------------------------------------------------------------------------- 1 | /*** 2 | * Excerpted from "OpenGL ES for Android", 3 | * published by The Pragmatic Bookshelf. 4 | * Copyrights apply to this code. It may not be used to create training material, 5 | * courses, books, articles, and the like. Contact us if you are in doubt. 6 | * We make no guarantees that this code is fit for any purpose. 7 | * Visit http://www.pragmaticprogrammer.com/titles/kbogla for more book information. 8 | ***/ 9 | package wxplus.opengles2forandroid.data; 10 | 11 | import java.nio.ByteBuffer; 12 | import java.nio.ByteOrder; 13 | import java.nio.FloatBuffer; 14 | 15 | import static android.opengl.GLES20.GL_ELEMENT_ARRAY_BUFFER; 16 | import static android.opengl.GLES20.GL_STATIC_DRAW; 17 | import static android.opengl.GLES20.glBindBuffer; 18 | import static android.opengl.GLES20.glBufferData; 19 | import static android.opengl.GLES20.glGenBuffers; 20 | import static wxplus.opengles2forandroid.utils.Constants.BYTES_PER_FLOAT; 21 | 22 | public class IndexBuffer { 23 | private final int bufferId; 24 | 25 | public IndexBuffer(float[] indexData) { 26 | // Allocate a buffer. 27 | final int buffers[] = new int[1]; 28 | glGenBuffers(buffers.length, buffers, 0); 29 | 30 | if (buffers[0] == 0) { 31 | throw new RuntimeException("Could not create a new index buffer object."); 32 | } 33 | 34 | bufferId = buffers[0]; 35 | 36 | // Bind to the buffer. 37 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[0]); 38 | 39 | // Transfer data to native memory. 40 | FloatBuffer indexArray = ByteBuffer 41 | .allocateDirect(indexData.length * BYTES_PER_FLOAT) 42 | .order(ByteOrder.nativeOrder()) 43 | .asFloatBuffer() 44 | .put(indexData); 45 | indexArray.position(0); 46 | 47 | // Transfer data from native memory to the GPU buffer. 48 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexArray.capacity() * BYTES_PER_FLOAT, 49 | indexArray, GL_STATIC_DRAW); 50 | 51 | // IMPORTANT: Unbind from the buffer when we're done with it. 52 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 53 | 54 | // We let the native buffer go out of scope, but it won't be released 55 | // until the next time the garbage collector is run. 56 | } 57 | 58 | public int getBufferId() { 59 | return bufferId; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/programs/ColorShaderProgram.java: -------------------------------------------------------------------------------- 1 | /*** 2 | * Excerpted from "OpenGL ES for Android", 3 | * published by The Pragmatic Bookshelf. 4 | * Copyrights apply to this code. It may not be used to create training material, 5 | * courses, books, articles, and the like. Contact us if you are in doubt. 6 | * We make no guarantees that this code is fit for any purpose. 7 | * Visit http://www.pragmaticprogrammer.com/titles/kbogla for more book information. 8 | ***/ 9 | package wxplus.opengles2forandroid.programs; 10 | 11 | import android.content.Context; 12 | 13 | import wxplus.opengles2forandroid.R; 14 | import wxplus.opengles2forandroid.obj.Object; 15 | 16 | import static android.opengl.GLES20.GL_FLOAT; 17 | import static android.opengl.GLES20.glEnableVertexAttribArray; 18 | import static android.opengl.GLES20.glGetAttribLocation; 19 | import static android.opengl.GLES20.glGetUniformLocation; 20 | import static android.opengl.GLES20.glUniform4f; 21 | import static android.opengl.GLES20.glUniformMatrix4fv; 22 | import static android.opengl.GLES20.glUseProgram; 23 | import static android.opengl.GLES20.glVertexAttribPointer; 24 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_VERTEX; 25 | 26 | public class ColorShaderProgram extends ShaderProgram { 27 | // Uniform locations 28 | private final int uMatrixLocation; 29 | private final int uColorLocation; 30 | 31 | // Attribute locations 32 | private final int aPositionLocation; 33 | 34 | public ColorShaderProgram(Context context) { 35 | super(context, R.raw.color_vertex_shader, 36 | R.raw.color_fragment_shader); 37 | 38 | // Retrieve uniform locations for the shader program. 39 | uMatrixLocation = glGetUniformLocation(program, U_MATRIX); 40 | uColorLocation = glGetUniformLocation(program, U_COLOR); 41 | 42 | // Retrieve attribute locations for the shader program. 43 | aPositionLocation = glGetAttribLocation(program, A_POSITION); 44 | } 45 | 46 | 47 | public void bindData(float[] m, Object obj, float r, float g, float b) { 48 | // 使用这个Program 49 | glUseProgram(program); 50 | // 矩阵变换 51 | glUniformMatrix4fv(uMatrixLocation, 1, false, m, 0); 52 | // 设置颜色 53 | glUniform4f(uColorLocation, r, g, b, 1f); 54 | // 设置顶点数据 55 | glVertexAttribPointer(aPositionLocation, FLOATS_PER_VERTEX, GL_FLOAT, false, 0, obj.getVertexBuffer()); 56 | glEnableVertexAttribArray(aPositionLocation); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/programs/SkyboxShaderProgram.java: -------------------------------------------------------------------------------- 1 | /*** 2 | * Excerpted from "OpenGL ES for Android", 3 | * published by The Pragmatic Bookshelf. 4 | * Copyrights apply to this code. It may not be used to create training material, 5 | * courses, books, articles, and the like. Contact us if you are in doubt. 6 | * We make no guarantees that this code is fit for any purpose. 7 | * Visit http://www.pragmaticprogrammer.com/titles/kbogla for more book information. 8 | ***/ 9 | package wxplus.opengles2forandroid.programs; 10 | 11 | import android.content.Context; 12 | 13 | import wxplus.opengles2forandroid.R; 14 | import wxplus.opengles2forandroid.obj.Object; 15 | 16 | import static android.opengl.GLES20.GL_FLOAT; 17 | import static android.opengl.GLES20.GL_TEXTURE0; 18 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP; 19 | import static android.opengl.GLES20.glActiveTexture; 20 | import static android.opengl.GLES20.glBindTexture; 21 | import static android.opengl.GLES20.glEnableVertexAttribArray; 22 | import static android.opengl.GLES20.glGetAttribLocation; 23 | import static android.opengl.GLES20.glGetUniformLocation; 24 | import static android.opengl.GLES20.glUniform1i; 25 | import static android.opengl.GLES20.glUniformMatrix4fv; 26 | import static android.opengl.GLES20.glUseProgram; 27 | import static android.opengl.GLES20.glVertexAttribPointer; 28 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_VERTEX; 29 | 30 | public class SkyboxShaderProgram extends ShaderProgram { 31 | protected static final String TAG = SkyboxShaderProgram.class.getSimpleName(); 32 | 33 | protected final int uMatrixLocation; 34 | protected final int uTextureUnitLocation; 35 | protected final int aPositionLocation; 36 | 37 | public SkyboxShaderProgram(Context context) { 38 | super(context, R.raw.skybox_vertex_shader, 39 | R.raw.skybox_fragment_shader); 40 | 41 | uMatrixLocation = glGetUniformLocation(program, U_MATRIX); 42 | uTextureUnitLocation = glGetUniformLocation(program, U_TEXTURE_UNIT); 43 | aPositionLocation = glGetAttribLocation(program, A_POSITION); 44 | } 45 | 46 | public void bindData(float[] matrix, int textureId, Object obj) { 47 | glUseProgram(program); 48 | 49 | glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0); 50 | 51 | glActiveTexture(GL_TEXTURE0); 52 | glBindTexture(GL_TEXTURE_CUBE_MAP, textureId); 53 | glUniform1i(uTextureUnitLocation, 0); 54 | 55 | // 设置顶点数据 56 | glVertexAttribPointer(aPositionLocation, FLOATS_PER_VERTEX, GL_FLOAT, false, 0, obj.getVertexBuffer()); 57 | glEnableVertexAttribArray(aPositionLocation); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/programs/TextureShaderProgram.java: -------------------------------------------------------------------------------- 1 | /*** 2 | * Excerpted from "OpenGL ES for Android", 3 | * published by The Pragmatic Bookshelf. 4 | * Copyrights apply to this code. It may not be used to create training material, 5 | * courses, books, articles, and the like. Contact us if you are in doubt. 6 | * We make no guarantees that this code is fit for any purpose. 7 | * Visit http://www.pragmaticprogrammer.com/titles/kbogla for more book information. 8 | ***/ 9 | package wxplus.opengles2forandroid.programs; 10 | 11 | import android.content.Context; 12 | 13 | import wxplus.opengles2forandroid.R; 14 | import wxplus.opengles2forandroid.obj.Object; 15 | 16 | import static android.opengl.GLES20.GL_FLOAT; 17 | import static android.opengl.GLES20.GL_LINEAR; 18 | import static android.opengl.GLES20.GL_LINEAR_MIPMAP_LINEAR; 19 | import static android.opengl.GLES20.GL_TEXTURE0; 20 | import static android.opengl.GLES20.GL_TEXTURE_2D; 21 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; 22 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; 23 | import static android.opengl.GLES20.glActiveTexture; 24 | import static android.opengl.GLES20.glBindTexture; 25 | import static android.opengl.GLES20.glEnableVertexAttribArray; 26 | import static android.opengl.GLES20.glGetAttribLocation; 27 | import static android.opengl.GLES20.glGetUniformLocation; 28 | import static android.opengl.GLES20.glTexParameteri; 29 | import static android.opengl.GLES20.glUniform1i; 30 | import static android.opengl.GLES20.glUniformMatrix4fv; 31 | import static android.opengl.GLES20.glUseProgram; 32 | import static android.opengl.GLES20.glVertexAttribPointer; 33 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_TEXTURE_VERTEX; 34 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_VERTEX; 35 | 36 | public class TextureShaderProgram extends ShaderProgram { 37 | // Uniform locations 38 | protected final int uMatrixLocation; 39 | protected final int uTextureUnitLocation; 40 | 41 | // Attribute locations 42 | protected final int aPositionLocation; 43 | protected final int aTextureCoordinatesLocation; 44 | 45 | public TextureShaderProgram(Context context) { 46 | super(context, R.raw.texture_vertex_shader, 47 | R.raw.texture_fragment_shader); 48 | 49 | // Retrieve uniform locations for the shader program. 50 | uMatrixLocation = glGetUniformLocation(program, U_MATRIX); 51 | uTextureUnitLocation = glGetUniformLocation(program, 52 | U_TEXTURE_UNIT); 53 | 54 | // Retrieve attribute locations for the shader program. 55 | aPositionLocation = glGetAttribLocation(program, A_POSITION); 56 | aTextureCoordinatesLocation = glGetAttribLocation(program, A_TEXTURE_COORDINATES); 57 | } 58 | 59 | public void bindData(float[] matrix, int textureId, Object obj) { 60 | // use Program 61 | glUseProgram(program); 62 | 63 | // Pass the matrix into the shader program. 64 | glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0); 65 | 66 | // Set the active texture unit to texture unit 0. 67 | glActiveTexture(GL_TEXTURE0); 68 | 69 | // Bind the texture to this unit. 70 | glBindTexture(GL_TEXTURE_2D, textureId); 71 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 72 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 73 | // Tell the texture uniform sampler to use this texture in the shader by 74 | // telling it to read from texture unit 0. 75 | glUniform1i(uTextureUnitLocation, 0); 76 | 77 | // 设置顶点数据 78 | glVertexAttribPointer(aPositionLocation, FLOATS_PER_VERTEX, GL_FLOAT, false, 0, obj.getVertexBuffer()); 79 | glEnableVertexAttribArray(aPositionLocation); 80 | // 设置Texture数据 81 | glVertexAttribPointer(aTextureCoordinatesLocation, FLOATS_PER_TEXTURE_VERTEX, GL_FLOAT, false, 0, obj.getTextureBuffer()); 82 | glEnableVertexAttribArray(aTextureCoordinatesLocation); 83 | } 84 | } -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/HeightMap.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | 6 | import static android.opengl.GLES20.GL_TRIANGLES; 7 | import static android.opengl.GLES20.GL_UNSIGNED_SHORT; 8 | import static android.opengl.GLES20.glDrawElements; 9 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_VERTEX; 10 | 11 | /** 12 | * @author WangXiaoPlus 13 | * @date 2017/12/17 14 | */ 15 | 16 | public class HeightMap extends Object { 17 | protected static final String TAG = HeightMap.class.getSimpleName(); 18 | 19 | protected final int width, height; 20 | 21 | public HeightMap(Bitmap bmp) { 22 | if (bmp == null) { 23 | throw new NullPointerException(TAG + ", bmp is null"); 24 | } 25 | width = bmp.getWidth(); 26 | height = bmp.getHeight(); 27 | if (width * height > Math.pow(2, 16)) { 28 | throw new RuntimeException(TAG + ", the width or height of bitmap is 0..."); 29 | } else if (width * height <= 0) { 30 | throw new RuntimeException(TAG + ", the width or height of bitmap is 0..."); 31 | } 32 | mVertexData = loadBitmapData(bmp); 33 | mIndexData = createIndexData(); 34 | drawTaskList.add(new DrawTask() { 35 | @Override 36 | public void draw() { 37 | glDrawElements(GL_TRIANGLES, mIndexData.length, GL_UNSIGNED_SHORT, getIndexBuffer()); 38 | } 39 | }); 40 | } 41 | 42 | /** 43 | * Copy the heightmap data into a vertex buffer object. 44 | */ 45 | protected float[] loadBitmapData(Bitmap bitmap) { 46 | final int[] pixels = new int[width * height]; 47 | bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 48 | bitmap.recycle(); 49 | 50 | final float[] heightmapVertices = 51 | new float[width * height * FLOATS_PER_VERTEX]; 52 | int offset = 0; 53 | for (int row = 0; row < height; row++) { 54 | for (int col = 0; col < width; col++) { 55 | // The heightmap will lie flat on the XZ plane and centered 56 | // around (0, 0), with the bitmap width mapped to X and the 57 | // bitmap height mapped to Z, and Y representing the height. We 58 | // assume the heightmap is grayscale, and use the value of the 59 | // red color to determine the height. 60 | final float xPosition = ((float) col / (float) (width - 1)) - 0.5f; 61 | final float yPosition = 62 | (float) Color.red(pixels[(row * width) + col]) / (float) 255; 63 | final float zPosition = ((float) row / (float) (height - 1)) - 0.5f; 64 | 65 | heightmapVertices[offset++] = xPosition; 66 | heightmapVertices[offset++] = yPosition; 67 | heightmapVertices[offset++] = zPosition; 68 | } 69 | } 70 | return heightmapVertices; 71 | } 72 | 73 | /** 74 | * Create an index buffer object for the vertices to wrap them together into 75 | * triangles, creating indices based on the width and height of the 76 | * heightmap. 77 | */ 78 | private short[] createIndexData() { 79 | int vertexCount = (width - 1) * (height - 1) * 2 * 3; // 有(width - 1) * (height - 1)个正方形,每个正方形可以分成两个三角形,每个三角形三个顶点 80 | final short[] indexData = new short[vertexCount]; 81 | int offset = 0; 82 | 83 | for (int row = 0; row < height - 1; row++) { 84 | for (int col = 0; col < width - 1; col++) { 85 | // Note: The (short) cast will end up underflowing the number 86 | // into the negative range if it doesn't fit, which gives us the 87 | // right unsigned number for OpenGL due to two's complement. 88 | // This will work so long as the heightmap contains 65536 pixels 89 | // or less. 90 | short topLeftIndexNum = (short) (row * width + col); 91 | short topRightIndexNum = (short) (row * width + col + 1); 92 | short bottomLeftIndexNum = (short) ((row + 1) * width + col); 93 | short bottomRightIndexNum = (short) ((row + 1) * width + col + 1); 94 | 95 | // Write out two triangles. 96 | indexData[offset++] = topLeftIndexNum; 97 | indexData[offset++] = bottomLeftIndexNum; 98 | indexData[offset++] = topRightIndexNum; 99 | 100 | indexData[offset++] = topRightIndexNum; 101 | indexData[offset++] = bottomLeftIndexNum; 102 | indexData[offset++] = bottomRightIndexNum; 103 | } 104 | } 105 | 106 | return indexData; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/OpenGL_04_Skybox.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.opengl.GLSurfaceView; 4 | import android.opengl.Matrix; 5 | import android.os.Bundle; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | 9 | import javax.microedition.khronos.egl.EGLConfig; 10 | import javax.microedition.khronos.opengles.GL10; 11 | 12 | import wxplus.opengles2forandroid.obj.Skybox; 13 | import wxplus.opengles2forandroid.programs.SkyboxShaderProgram; 14 | import wxplus.opengles2forandroid.programs.TextureShaderProgram; 15 | import wxplus.opengles2forandroid.utils.TextureUtils; 16 | 17 | import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; 18 | import static android.opengl.GLES20.glClear; 19 | import static android.opengl.GLES20.glClearColor; 20 | import static android.opengl.GLES20.glViewport; 21 | import static android.opengl.Matrix.multiplyMM; 22 | import static android.opengl.Matrix.rotateM; 23 | import static android.opengl.Matrix.setIdentityM; 24 | import static android.opengl.Matrix.translateM; 25 | 26 | /** 27 | * Created by hi on 2017/10/29. 28 | */ 29 | 30 | public class OpenGL_04_Skybox extends BaseActivity { 31 | 32 | protected GLSurfaceView mGlView; 33 | protected SimpleColorRenderer mRenderer; 34 | 35 | protected static final int sFovy = 45; // 透视投影的视角,90度 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | mGlView = new GLSurfaceView(this); 41 | // Request an OpenGL ES 2.0 compatible context. 42 | mGlView.setEGLContextClientVersion(2); 43 | mRenderer = new SimpleColorRenderer(); 44 | mGlView.setRenderer(mRenderer); 45 | setContentView(mGlView); 46 | mGlView.setOnTouchListener(new View.OnTouchListener() { 47 | float previousX, previousY; 48 | 49 | @Override 50 | public boolean onTouch(View v, MotionEvent event) { 51 | if (event != null) { 52 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 53 | previousX = event.getX(); 54 | previousY = event.getY(); 55 | } else if (event.getAction() == MotionEvent.ACTION_MOVE) { 56 | final float deltaX = event.getX() - previousX; 57 | final float deltaY = event.getY() - previousY; 58 | 59 | previousX = event.getX(); 60 | previousY = event.getY(); 61 | 62 | mGlView.queueEvent(new Runnable() { 63 | @Override 64 | public void run() { 65 | mRenderer.handleTouchDrag(deltaX, deltaY); 66 | } 67 | }); 68 | } 69 | 70 | return true; 71 | } else { 72 | return false; 73 | } 74 | } 75 | }); 76 | } 77 | 78 | protected float[] mViewMatrix = new float[16]; 79 | protected float[] mProjectionMatrix = new float[16]; 80 | protected float[] mProjectionViewMatrix = new float[16]; 81 | 82 | protected SkyboxShaderProgram mSkyboxProgram; 83 | 84 | protected int mSkyboxTexture; 85 | 86 | protected Skybox mSkybox; 87 | 88 | public class SimpleColorRenderer implements GLSurfaceView.Renderer { 89 | 90 | @Override 91 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 92 | glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 93 | mSkyboxProgram = new SkyboxShaderProgram(mActivity); 94 | mSkyboxTexture = TextureUtils.loadCubeMap(mActivity, 95 | new int[]{R.drawable.left, R.drawable.right, 96 | R.drawable.bottom, R.drawable.top, 97 | R.drawable.front, R.drawable.back} 98 | ); 99 | mSkybox = new Skybox(); 100 | } 101 | 102 | @Override 103 | public void onSurfaceChanged(GL10 gl, int width, int height) { 104 | // Set the OpenGL viewport to fill the entire surface. 105 | glViewport(0, 0, width, height); 106 | float screenAspect = width * 1.0f / height; 107 | Matrix.perspectiveM(mProjectionMatrix, 0, sFovy, screenAspect, 1f, 10f); 108 | } 109 | 110 | @Override 111 | public void onDrawFrame(GL10 gl) { 112 | glClear(GL_COLOR_BUFFER_BIT); 113 | setIdentityM(mViewMatrix, 0); 114 | rotateM(mViewMatrix, 0, -xRotation, 0, 1f, 0); 115 | rotateM(mViewMatrix, 0, -yRotation, 1f, 0, 0); 116 | multiplyMM(mProjectionViewMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); 117 | mSkyboxProgram.bindData(mProjectionViewMatrix, mSkyboxTexture, mSkybox); 118 | mSkybox.draw(); 119 | } 120 | 121 | protected float xRotation, yRotation; 122 | 123 | public void handleTouchDrag(float deltaX, float deltaY) { 124 | xRotation += deltaX / 16f; 125 | yRotation += deltaY / 16f; 126 | 127 | if (yRotation < -90) { 128 | yRotation = -90; 129 | } else if (yRotation > 90) { 130 | yRotation = 90; 131 | } 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/OpenGL_03_Simple_Object.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.opengl.GLSurfaceView; 4 | import android.opengl.Matrix; 5 | import android.os.Bundle; 6 | 7 | import javax.microedition.khronos.egl.EGLConfig; 8 | import javax.microedition.khronos.opengles.GL10; 9 | 10 | import wxplus.opengles2forandroid.obj.Puck; 11 | import wxplus.opengles2forandroid.obj.Table; 12 | import wxplus.opengles2forandroid.obj.base.Mallet; 13 | import wxplus.opengles2forandroid.obj.base.Point; 14 | import wxplus.opengles2forandroid.programs.ColorShaderProgram; 15 | import wxplus.opengles2forandroid.programs.TextureShaderProgram; 16 | import wxplus.opengles2forandroid.utils.TextureUtils; 17 | 18 | import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; 19 | import static android.opengl.GLES20.glClear; 20 | import static android.opengl.GLES20.glClearColor; 21 | import static android.opengl.GLES20.glViewport; 22 | import static android.opengl.Matrix.multiplyMM; 23 | import static android.opengl.Matrix.rotateM; 24 | import static android.opengl.Matrix.setIdentityM; 25 | import static android.opengl.Matrix.translateM; 26 | 27 | /** 28 | * Created by hi on 2017/10/29. 29 | */ 30 | 31 | public class OpenGL_03_Simple_Object extends BaseActivity { 32 | 33 | protected GLSurfaceView mGlView; 34 | 35 | 36 | protected static final int sFovy = 90; // 透视投影的视角,90度 37 | protected static final float sZ = 2; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | mGlView = new GLSurfaceView(this); 43 | // Request an OpenGL ES 2.0 compatible context. 44 | mGlView.setEGLContextClientVersion(2); 45 | mGlView.setRenderer(new CusRenderer()); 46 | setContentView(mGlView); 47 | } 48 | 49 | protected float[] mModelMatrix = new float[16]; 50 | protected float[] mViewMatrix = new float[16]; 51 | protected float[] mProjectionMatrix = new float[16]; 52 | protected float[] mProjectionViewMatrix = new float[16]; 53 | protected float[] mProjectionViewModelMatrix = new float[16]; 54 | 55 | protected TextureShaderProgram mTextureProgram; 56 | protected ColorShaderProgram mColorProgram; 57 | 58 | protected int mTexture; 59 | 60 | protected Table mTable; 61 | protected Puck mPuck; 62 | protected Mallet mTopMallet; 63 | protected Mallet mBottomMallet; 64 | 65 | public class CusRenderer implements GLSurfaceView.Renderer { 66 | 67 | @Override 68 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 69 | glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 70 | mTextureProgram = new TextureShaderProgram(mActivity); 71 | mColorProgram = new ColorShaderProgram(mActivity); 72 | mTexture = TextureUtils.loadTexture(mActivity, R.drawable.air_hockey_surface); 73 | } 74 | 75 | @Override 76 | public void onSurfaceChanged(GL10 gl, int width, int height) { 77 | // Set the OpenGL viewport to fill the entire surface. 78 | glViewport(0, 0, width, height); 79 | float focalLength = (float) (1 / Math.tan(Math.toRadians(sFovy / 2))); 80 | float screenAspect = width * 1.0f / height; 81 | Matrix.perspectiveM(mProjectionMatrix, 0, sFovy, screenAspect, 1f, 10f); 82 | setIdentityM(mViewMatrix, 0); 83 | translateM(mViewMatrix, 0, 0, 0, -sZ); 84 | rotateM(mViewMatrix, 0, -60, 1f, 0f, 0f); 85 | // Multiply the view and projection matrices together. 86 | multiplyMM(mProjectionViewMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); 87 | // 初始化Objects 88 | mTable = new Table(new Point(0, 0, 0), sZ * screenAspect / focalLength, sZ / focalLength); 89 | mPuck = new Puck(new Point(0, 0, 0), 0.1f, 0.1f, 100); 90 | mTopMallet = new Mallet(new Point(0f, 0f, 0f), 0.05f, 0.1f, 0.1f, 0.05f, 100, 100); 91 | mBottomMallet = new Mallet(new Point(0f, 0f, 0f), 0.05f, 0.1f, 0.1f, 0.05f, 100, 100); 92 | } 93 | 94 | @Override 95 | public void onDrawFrame(GL10 gl) { 96 | glClear(GL_COLOR_BUFFER_BIT); 97 | // 绘制Table 98 | positionTableInScene(); 99 | mTextureProgram.bindData(mProjectionViewModelMatrix, mTexture, mTable); 100 | mTable.draw(); 101 | // 绘制Puck 102 | positionPuckInScene(); 103 | mColorProgram.bindData(mProjectionViewModelMatrix, mPuck, 1f, 0f, 0f); 104 | mPuck.draw(); 105 | // top mallet 106 | positionTopMalletInScene(); 107 | mColorProgram.bindData(mProjectionViewModelMatrix, mTopMallet, 0, 1f, 0); 108 | mTopMallet.draw(); 109 | // bottom mallet 110 | positionBottomMalletInScene(); 111 | mColorProgram.bindData(mProjectionViewModelMatrix, mBottomMallet, 0, 0, 1f); 112 | mBottomMallet.draw(); 113 | } 114 | } 115 | 116 | protected void positionTableInScene() { 117 | setIdentityM(mModelMatrix, 0); 118 | multiplyMM(mProjectionViewModelMatrix, 0, mProjectionViewMatrix, 0, mModelMatrix, 0); 119 | } 120 | 121 | protected void positionPuckInScene() { 122 | setIdentityM(mModelMatrix, 0); 123 | translateM(mModelMatrix, 0, 0, 0, 0.05f); 124 | multiplyMM(mProjectionViewModelMatrix, 0, mProjectionViewMatrix, 0, mModelMatrix, 0); 125 | } 126 | 127 | protected void positionTopMalletInScene() { 128 | setIdentityM(mModelMatrix, 0); 129 | translateM(mModelMatrix, 0, 0, 0.5f, 0.05f); 130 | multiplyMM(mProjectionViewModelMatrix, 0, mProjectionViewMatrix, 0, mModelMatrix, 0); 131 | } 132 | 133 | protected void positionBottomMalletInScene() { 134 | setIdentityM(mModelMatrix, 0); 135 | translateM(mModelMatrix, 0, 0, -0.5f, 0.05f); 136 | multiplyMM(mProjectionViewModelMatrix, 0, mProjectionViewMatrix, 0, mModelMatrix, 0); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/OpenGL_01_Simple_Color.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.app.ActivityManager; 4 | import android.content.Context; 5 | import android.content.pm.ConfigurationInfo; 6 | import android.opengl.GLSurfaceView; 7 | import android.opengl.Matrix; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | 11 | import java.nio.ByteBuffer; 12 | import java.nio.ByteOrder; 13 | import java.nio.FloatBuffer; 14 | 15 | import javax.microedition.khronos.egl.EGLConfig; 16 | import javax.microedition.khronos.opengles.GL10; 17 | 18 | import wxplus.opengles2forandroid.utils.TextureUtils; 19 | 20 | import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; 21 | import static android.opengl.GLES20.GL_COMPILE_STATUS; 22 | import static android.opengl.GLES20.GL_FLOAT; 23 | import static android.opengl.GLES20.GL_FRAGMENT_SHADER; 24 | import static android.opengl.GLES20.GL_TRIANGLE_FAN; 25 | import static android.opengl.GLES20.GL_VERTEX_SHADER; 26 | import static android.opengl.GLES20.glAttachShader; 27 | import static android.opengl.GLES20.glClear; 28 | import static android.opengl.GLES20.glClearColor; 29 | import static android.opengl.GLES20.glCompileShader; 30 | import static android.opengl.GLES20.glCreateProgram; 31 | import static android.opengl.GLES20.glCreateShader; 32 | import static android.opengl.GLES20.glDrawArrays; 33 | import static android.opengl.GLES20.glEnableVertexAttribArray; 34 | import static android.opengl.GLES20.glGetAttribLocation; 35 | import static android.opengl.GLES20.glGetShaderiv; 36 | import static android.opengl.GLES20.glGetUniformLocation; 37 | import static android.opengl.GLES20.glLinkProgram; 38 | import static android.opengl.GLES20.glShaderSource; 39 | import static android.opengl.GLES20.glUniform4f; 40 | import static android.opengl.GLES20.glUniformMatrix4fv; 41 | import static android.opengl.GLES20.glUseProgram; 42 | import static android.opengl.GLES20.glVertexAttribPointer; 43 | import static android.opengl.GLES20.glViewport; 44 | import static wxplus.opengles2forandroid.utils.Constants.BYTES_PER_FLOAT; 45 | 46 | /** 47 | * Created by hi on 2017/10/29. 48 | */ 49 | 50 | public class OpenGL_01_Simple_Color extends BaseActivity { 51 | 52 | protected GLSurfaceView mGlView; 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | mGlView = new GLSurfaceView(this); 58 | // Request an OpenGL ES 2.0 compatible context. 59 | mGlView.setEGLContextClientVersion(2); 60 | mGlView.setRenderer(new CusRenderer()); 61 | // Check if the system supports OpenGL ES 2.0. 62 | ActivityManager activityManager = 63 | (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 64 | ConfigurationInfo configurationInfo = activityManager 65 | .getDeviceConfigurationInfo(); 66 | final boolean supportsEs2 = 67 | configurationInfo.reqGlEsVersion >= 0x20000 68 | || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1 69 | && (Build.FINGERPRINT.startsWith("generic") 70 | || Build.FINGERPRINT.startsWith("unknown") 71 | || Build.MODEL.contains("google_sdk") 72 | || Build.MODEL.contains("Emulator") 73 | || Build.MODEL.contains("Android SDK built for x86"))); 74 | setContentView(mGlView); 75 | } 76 | 77 | protected float[] mVertexArray = new float[] { // OpenGL的坐标是[-1, 1],这里的Vertex正好定义了一个居中的正方形 78 | // triangle fan x, y 79 | 0, 0, 80 | -0.5f, -0.5f, 81 | 0.5f, -0.5f, 82 | 0.5f, 0.5f, 83 | -0.5f, 0.5f, 84 | -0.5f, -0.5f 85 | }; 86 | protected FloatBuffer mVertexBuffer; 87 | protected float[] mProjectionMatrix = new float[16]; 88 | 89 | protected int uMatrixLocation; 90 | protected int aPositionLocation; 91 | protected int uColorLocation; 92 | 93 | public class CusRenderer implements GLSurfaceView.Renderer { 94 | 95 | @Override 96 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 97 | glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 98 | // 初始化顶点数据 99 | mVertexBuffer = ByteBuffer.allocateDirect(mVertexArray.length * BYTES_PER_FLOAT) 100 | .order(ByteOrder.nativeOrder()) 101 | .asFloatBuffer() 102 | .put(mVertexArray); 103 | String vertexShaderStr = TextureUtils.readShaderCodeFromResource(mActivity, R.raw.color_vertex_shader); 104 | String fragmentShaderStr = TextureUtils.readShaderCodeFromResource(mActivity, R.raw.color_fragment_shader); 105 | // 创建Shader 106 | final int vertexShaderId = glCreateShader(GL_VERTEX_SHADER); 107 | final int fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER); 108 | glShaderSource(vertexShaderId, vertexShaderStr); 109 | glShaderSource(fragmentShaderId, fragmentShaderStr); 110 | glCompileShader(vertexShaderId); 111 | glCompileShader(fragmentShaderId); 112 | final int[] compileStatus = new int[1]; 113 | glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, 114 | compileStatus, 0); 115 | // 创建Program 116 | final int programId = glCreateProgram(); 117 | glAttachShader(programId, vertexShaderId); 118 | glAttachShader(programId, fragmentShaderId); 119 | glLinkProgram(programId); 120 | // 启用这个Program 121 | glUseProgram(programId); 122 | // 找到需要赋值的变量 123 | uMatrixLocation = glGetUniformLocation(programId, "u_Matrix"); 124 | aPositionLocation = glGetAttribLocation(programId, "a_Position"); 125 | uColorLocation = glGetUniformLocation(programId, "u_Color"); 126 | // 填充数据 127 | glUniform4f(uColorLocation, 1, 0, 0, 1); 128 | mVertexBuffer.position(0); 129 | glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, false, 0, mVertexBuffer); 130 | glEnableVertexAttribArray(aPositionLocation); 131 | } 132 | 133 | @Override 134 | public void onSurfaceChanged(GL10 gl, int width, int height) { 135 | glViewport(0, 0, width, height); 136 | // 正交变换,只考虑竖屏的情况 137 | float rate = height * 1.0f / width; 138 | Matrix.orthoM(mProjectionMatrix, 0, -1, 1, -rate, rate, -1, 1); // 正交变换,防止界面拉伸 139 | glUniformMatrix4fv(uMatrixLocation, 1, false, mProjectionMatrix, 0); 140 | } 141 | 142 | @Override 143 | public void onDrawFrame(GL10 gl) { 144 | glClear(GL_COLOR_BUFFER_BIT); 145 | glDrawArrays(GL_TRIANGLE_FAN, 0, 6); 146 | } 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/utils/TextureUtils.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.util.Log; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.InputStreamReader; 13 | 14 | import static android.opengl.GLES20.GL_LINEAR; 15 | import static android.opengl.GLES20.GL_LINEAR_MIPMAP_LINEAR; 16 | import static android.opengl.GLES20.GL_TEXTURE_2D; 17 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP; 18 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; 19 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; 20 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; 21 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X; 22 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; 23 | import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; 24 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; 25 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; 26 | import static android.opengl.GLES20.glBindTexture; 27 | import static android.opengl.GLES20.glDeleteTextures; 28 | import static android.opengl.GLES20.glGenTextures; 29 | import static android.opengl.GLES20.glGenerateMipmap; 30 | import static android.opengl.GLES20.glTexParameteri; 31 | import static android.opengl.GLUtils.texImage2D; 32 | 33 | /** 34 | * @author WangXiaoPlus 35 | * @date 2017/11/19 36 | */ 37 | 38 | public class TextureUtils { 39 | public static final String TAG = TextureUtils.class.getSimpleName(); 40 | 41 | public static int loadCubeMap(Context context, int[] cubeResources) { 42 | final int[] textureObjectIds = new int[1]; 43 | glGenTextures(1, textureObjectIds, 0); 44 | 45 | if (textureObjectIds[0] == 0) { 46 | GLog.e(TAG, "Could not generate a new OpenGL texture object."); 47 | return 0; 48 | } 49 | final BitmapFactory.Options options = new BitmapFactory.Options(); 50 | options.inScaled = false; 51 | final Bitmap[] cubeBitmaps = new Bitmap[6]; 52 | for (int i = 0; i < 6; i++) { 53 | cubeBitmaps[i] = 54 | BitmapFactory.decodeResource(context.getResources(), 55 | cubeResources[i], options); 56 | 57 | if (cubeBitmaps[i] == null) { 58 | GLog.e(TAG, "Resource ID " + cubeResources[i] 59 | + " could not be decoded."); 60 | glDeleteTextures(1, textureObjectIds, 0); 61 | return 0; 62 | } 63 | } 64 | // Linear filtering for minification and magnification 65 | glBindTexture(GL_TEXTURE_CUBE_MAP, textureObjectIds[0]); 66 | 67 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 68 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 69 | texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, cubeBitmaps[0], 0); 70 | texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, cubeBitmaps[1], 0); 71 | 72 | texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, cubeBitmaps[2], 0); 73 | texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, cubeBitmaps[3], 0); 74 | 75 | texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, cubeBitmaps[4], 0); 76 | texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, cubeBitmaps[5], 0); 77 | glBindTexture(GL_TEXTURE_2D, 0); 78 | 79 | for (Bitmap bitmap : cubeBitmaps) { 80 | bitmap.recycle(); 81 | } 82 | 83 | return textureObjectIds[0]; 84 | } 85 | 86 | public static int loadTexture(Context context, int resourceId) { 87 | final int[] textureObjectIds = new int[1]; 88 | glGenTextures(1, textureObjectIds, 0); 89 | 90 | if (textureObjectIds[0] == 0) { 91 | GLog.e(TAG, "Could not generate a new OpenGL texture object."); 92 | return 0; 93 | } 94 | 95 | final BitmapFactory.Options options = new BitmapFactory.Options(); 96 | options.inScaled = false; 97 | 98 | // Read in the resource 99 | final Bitmap bitmap = BitmapFactory.decodeResource( 100 | context.getResources(), resourceId, options); 101 | 102 | if (bitmap == null) { 103 | GLog.e(TAG, "Resource ID " + resourceId + " could not be decoded."); 104 | glDeleteTextures(1, textureObjectIds, 0); 105 | return 0; 106 | } 107 | 108 | // Bind to the texture in OpenGL 109 | glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]); 110 | 111 | // Set filtering: a default must be set, or the texture will be 112 | // black. 113 | glTexParameteri(GL_TEXTURE_2D, 114 | GL_TEXTURE_MIN_FILTER, 115 | GL_LINEAR_MIPMAP_LINEAR); 116 | glTexParameteri(GL_TEXTURE_2D, 117 | GL_TEXTURE_MAG_FILTER, GL_LINEAR); 118 | // Load the bitmap into the bound texture. 119 | texImage2D(GL_TEXTURE_2D, 0, bitmap, 0); 120 | 121 | // Note: Following code may cause an error to be reported in the 122 | // ADB log as follows: E/IMGSRV(20095): :0: HardwareMipGen: 123 | // Failed to generate texture mipmap levels (error=3) 124 | // No OpenGL error will be encountered (glGetError() will return 125 | // 0). If this happens, just squash the source image to be 126 | // square. It will look the same because of texture coordinates, 127 | // and mipmap generation will work. 128 | 129 | glGenerateMipmap(GL_TEXTURE_2D); 130 | 131 | // Recycle the bitmap, since its data has been loaded into 132 | // OpenGL. 133 | bitmap.recycle(); 134 | 135 | // Unbind from the texture. 136 | glBindTexture(GL_TEXTURE_2D, 0); 137 | 138 | return textureObjectIds[0]; 139 | } 140 | 141 | public static String readShaderCodeFromResource(Context context, int resourceId) { 142 | StringBuilder body = new StringBuilder(); 143 | 144 | try { 145 | InputStream inputStream = context.getResources() 146 | .openRawResource(resourceId); 147 | InputStreamReader inputStreamReader = new InputStreamReader( 148 | inputStream); 149 | BufferedReader bufferedReader = new BufferedReader( 150 | inputStreamReader); 151 | 152 | String nextLine; 153 | 154 | while ((nextLine = bufferedReader.readLine()) != null) { 155 | body.append(nextLine); 156 | body.append('\n'); 157 | } 158 | } catch (IOException e) { 159 | throw new RuntimeException( 160 | "Could not open resource: " + resourceId, e); 161 | } catch (Resources.NotFoundException nfe) { 162 | throw new RuntimeException("Resource not found: " 163 | + resourceId, nfe); 164 | } 165 | 166 | return body.toString(); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/OpenGL_05_HeightMap.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.graphics.BitmapFactory; 4 | import android.opengl.GLSurfaceView; 5 | import android.opengl.Matrix; 6 | import android.os.Bundle; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | 10 | import javax.microedition.khronos.egl.EGLConfig; 11 | import javax.microedition.khronos.opengles.GL10; 12 | 13 | import wxplus.opengles2forandroid.obj.HeightMap; 14 | import wxplus.opengles2forandroid.obj.Skybox; 15 | import wxplus.opengles2forandroid.programs.HeightMapShaderProgram; 16 | import wxplus.opengles2forandroid.programs.SkyboxShaderProgram; 17 | import wxplus.opengles2forandroid.utils.TextureUtils; 18 | 19 | import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; 20 | import static android.opengl.GLES20.GL_CULL_FACE; 21 | import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT; 22 | import static android.opengl.GLES20.GL_DEPTH_TEST; 23 | import static android.opengl.GLES20.GL_LEQUAL; 24 | import static android.opengl.GLES20.GL_LESS; 25 | import static android.opengl.GLES20.glClear; 26 | import static android.opengl.GLES20.glClearColor; 27 | import static android.opengl.GLES20.glDepthFunc; 28 | import static android.opengl.GLES20.glEnable; 29 | import static android.opengl.GLES20.glViewport; 30 | import static android.opengl.Matrix.multiplyMM; 31 | import static android.opengl.Matrix.rotateM; 32 | import static android.opengl.Matrix.scaleM; 33 | import static android.opengl.Matrix.setIdentityM; 34 | import static android.opengl.Matrix.translateM; 35 | 36 | /** 37 | * @author WangXiaoPlus 38 | * @date 2017/12/17 39 | */ 40 | 41 | public class OpenGL_05_HeightMap extends BaseActivity { 42 | 43 | protected GLSurfaceView mGlView; 44 | protected CusRenderer mRenderer; 45 | 46 | protected static final int sFovy = 90; // 透视投影的视角,90度 47 | 48 | @Override 49 | protected void onCreate(Bundle savedInstanceState) { 50 | super.onCreate(savedInstanceState); 51 | mGlView = new GLSurfaceView(this); 52 | // Request an OpenGL ES 2.0 compatible context. 53 | mGlView.setEGLContextClientVersion(2); 54 | mRenderer = new CusRenderer(); 55 | mGlView.setRenderer(mRenderer); 56 | setContentView(mGlView); 57 | mGlView.setOnTouchListener(new View.OnTouchListener() { 58 | float previousX, previousY; 59 | 60 | @Override 61 | public boolean onTouch(View v, MotionEvent event) { 62 | if (event != null) { 63 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 64 | previousX = event.getX(); 65 | previousY = event.getY(); 66 | } else if (event.getAction() == MotionEvent.ACTION_MOVE) { 67 | final float deltaX = event.getX() - previousX; 68 | final float deltaY = event.getY() - previousY; 69 | 70 | previousX = event.getX(); 71 | previousY = event.getY(); 72 | 73 | mGlView.queueEvent(new Runnable() { 74 | @Override 75 | public void run() { 76 | mRenderer.handleTouchDrag(deltaX, deltaY); 77 | } 78 | }); 79 | } 80 | 81 | return true; 82 | } else { 83 | return false; 84 | } 85 | } 86 | }); 87 | } 88 | 89 | protected float[] mModelMatrix = new float[16]; 90 | protected float[] mViewMatrix = new float[16]; 91 | protected float[] mProjectionMatrix = new float[16]; 92 | protected float[] mProjectionViewModelMatrix = new float[16]; // mvp matrix 93 | 94 | protected SkyboxShaderProgram mSkyboxProgram; 95 | protected int mSkyboxTexture; 96 | protected Skybox mSkybox; 97 | 98 | protected HeightMapShaderProgram mHeightMapShaderProgram; 99 | protected HeightMap mHeightMap; 100 | 101 | public class CusRenderer implements GLSurfaceView.Renderer { 102 | 103 | @Override 104 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 105 | glEnable(GL_DEPTH_TEST); 106 | glEnable(GL_CULL_FACE); 107 | glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 108 | mSkyboxProgram = new SkyboxShaderProgram(mActivity); 109 | mSkyboxTexture = TextureUtils.loadCubeMap(mActivity, 110 | new int[]{R.drawable.left, R.drawable.right, 111 | R.drawable.bottom, R.drawable.top, 112 | R.drawable.front, R.drawable.back} 113 | ); 114 | mSkybox = new Skybox(); 115 | mHeightMapShaderProgram = new HeightMapShaderProgram(mActivity); 116 | mHeightMap = new HeightMap(BitmapFactory.decodeResource(getResources(), R.mipmap.heightmap)); 117 | } 118 | 119 | @Override 120 | public void onSurfaceChanged(GL10 gl, int width, int height) { 121 | // Set the OpenGL viewport to fill the entire surface. 122 | glViewport(0, 0, width, height); 123 | float screenAspect = width * 1.0f / height; 124 | Matrix.perspectiveM(mProjectionMatrix, 0, sFovy, screenAspect, 0f, 100f); 125 | setIdentityM(mViewMatrix, 0); 126 | } 127 | 128 | @Override 129 | public void onDrawFrame(GL10 gl) { 130 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 131 | drawSkybox(); 132 | drawHeightMap(); 133 | } 134 | 135 | public void drawHeightMap() { 136 | // Expand the heightmap's dimensions, but don't expand the height as 137 | // much so that we don't get insanely tall mountains. 138 | setIdentityM(mModelMatrix, 0); 139 | translateM(mModelMatrix, 0, 0, -1.5f, -2f); // 向下移动点,让山脉的底部在屏幕下面,向远处移动一些,不然看不出啥东西,离得太近 140 | scaleM(mModelMatrix, 0, 100f, 10f, 100f); // 这里放大若干倍,形成环绕的效果,最少要在左右滑动的时候看不到边 141 | updateMvpMatrix(); 142 | mHeightMapShaderProgram.bindData(mProjectionViewModelMatrix, mHeightMap); 143 | glDepthFunc(GL_LEQUAL); 144 | mHeightMap.draw(); 145 | glDepthFunc(GL_LESS); 146 | } 147 | 148 | public void drawSkybox() { 149 | setIdentityM(mModelMatrix, 0); 150 | // translateM(mModelMatrix, 0, 0, 0, -0); 151 | updateMvpMatrix(); 152 | mSkyboxProgram.bindData(mProjectionViewModelMatrix, mSkyboxTexture, mSkybox); 153 | mSkybox.draw(); 154 | } 155 | 156 | protected float xRotation, yRotation; 157 | public void handleTouchDrag(float deltaX, float deltaY) { 158 | float x = deltaX / 16f; 159 | float y = deltaY / 16f; 160 | if (yRotation + y > 90) { 161 | y = 90 - yRotation; 162 | } else if (yRotation + y < -90) { 163 | y = -90 - yRotation; 164 | } 165 | xRotation += x; 166 | yRotation += y; 167 | rotateM(mViewMatrix, 0, -x, 0, 1f, 0); 168 | rotateM(mViewMatrix, 0, -y, 1f, 0, 0); 169 | } 170 | } 171 | 172 | public void updateMvpMatrix() { 173 | float[] temp = new float[16]; 174 | multiplyMM(temp, 0, mViewMatrix, 0, mModelMatrix, 0); 175 | multiplyMM(mProjectionViewModelMatrix, 0, mProjectionMatrix, 0, temp, 0); 176 | } 177 | 178 | 179 | } 180 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/programs/ShaderProgram.java: -------------------------------------------------------------------------------- 1 | /*** 2 | * Excerpted from "OpenGL ES for Android", 3 | * published by The Pragmatic Bookshelf. 4 | * Copyrights apply to this code. It may not be used to create training material, 5 | * courses, books, articles, and the like. Contact us if you are in doubt. 6 | * We make no guarantees that this code is fit for any purpose. 7 | * Visit http://www.pragmaticprogrammer.com/titles/kbogla for more book information. 8 | ***/ 9 | package wxplus.opengles2forandroid.programs; 10 | 11 | import android.content.Context; 12 | 13 | import wxplus.opengles2forandroid.utils.GLog; 14 | import wxplus.opengles2forandroid.utils.TextureUtils; 15 | 16 | import static android.opengl.GLES20.GL_COMPILE_STATUS; 17 | import static android.opengl.GLES20.GL_FRAGMENT_SHADER; 18 | import static android.opengl.GLES20.GL_LINK_STATUS; 19 | import static android.opengl.GLES20.GL_VALIDATE_STATUS; 20 | import static android.opengl.GLES20.GL_VERTEX_SHADER; 21 | import static android.opengl.GLES20.glAttachShader; 22 | import static android.opengl.GLES20.glCompileShader; 23 | import static android.opengl.GLES20.glCreateProgram; 24 | import static android.opengl.GLES20.glCreateShader; 25 | import static android.opengl.GLES20.glDeleteProgram; 26 | import static android.opengl.GLES20.glDeleteShader; 27 | import static android.opengl.GLES20.glGetProgramInfoLog; 28 | import static android.opengl.GLES20.glGetProgramiv; 29 | import static android.opengl.GLES20.glGetShaderInfoLog; 30 | import static android.opengl.GLES20.glGetShaderiv; 31 | import static android.opengl.GLES20.glLinkProgram; 32 | import static android.opengl.GLES20.glShaderSource; 33 | import static android.opengl.GLES20.glUseProgram; 34 | import static android.opengl.GLES20.glValidateProgram; 35 | 36 | public abstract class ShaderProgram { 37 | public static final String TAG = ShaderProgram.class.getSimpleName(); 38 | 39 | // Uniform constants 40 | protected static final String U_MATRIX = "u_Matrix"; 41 | protected static final String U_COLOR = "u_Color"; 42 | protected static final String U_TEXTURE_UNIT = "u_TextureUnit"; 43 | 44 | // Attribute constants 45 | protected static final String A_POSITION = "a_Position"; 46 | protected static final String A_COLOR = "a_Color"; 47 | protected static final String A_TEXTURE_COORDINATES = "a_TextureCoordinates"; 48 | 49 | // Shader program 50 | public final int program; 51 | 52 | protected ShaderProgram(Context context, int vertexShaderResourceId, 53 | int fragmentShaderResourceId) { 54 | // Compile the shaders and link the program. 55 | program = buildProgram( 56 | TextureUtils.readShaderCodeFromResource(context, vertexShaderResourceId), 57 | TextureUtils.readShaderCodeFromResource(context, fragmentShaderResourceId)); 58 | 59 | } 60 | 61 | /** 62 | * Loads and compiles a vertex shader, returning the OpenGL object ID. 63 | */ 64 | public static int compileVertexShader(String shaderCode) { 65 | return compileShader(GL_VERTEX_SHADER, shaderCode); 66 | } 67 | 68 | /** 69 | * Loads and compiles a fragment shader, returning the OpenGL object ID. 70 | */ 71 | public static int compileFragmentShader(String shaderCode) { 72 | return compileShader(GL_FRAGMENT_SHADER, shaderCode); 73 | } 74 | 75 | /** 76 | * Compiles a shader, returning the OpenGL object ID. 77 | */ 78 | private static int compileShader(int type, String shaderCode) { 79 | // Create a new shader object. 80 | final int shaderObjectId = glCreateShader(type); 81 | 82 | if (shaderObjectId == 0) { 83 | GLog.e(TAG, "Could not create new shader."); 84 | return 0; 85 | } 86 | 87 | // Pass in the shader source. 88 | glShaderSource(shaderObjectId, shaderCode); 89 | 90 | // Compile the shader. 91 | glCompileShader(shaderObjectId); 92 | 93 | // Get the compilation status. 94 | final int[] compileStatus = new int[1]; 95 | glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, 96 | compileStatus, 0); 97 | 98 | GLog.d(TAG, "Results of compiling source:" + "\n" + shaderCode + "\n:" + glGetShaderInfoLog(shaderObjectId)); 99 | 100 | // Verify the compile status. 101 | if (compileStatus[0] == 0) { 102 | // If it failed, delete the shader object. 103 | glDeleteShader(shaderObjectId); 104 | GLog.e(TAG, "Compilation of shader failed."); 105 | return 0; 106 | } 107 | 108 | // Return the shader object ID. 109 | return shaderObjectId; 110 | } 111 | 112 | /** 113 | * Links a vertex shader and a fragment shader together into an OpenGL 114 | * program. Returns the OpenGL program object ID, or 0 if linking failed. 115 | */ 116 | public static int linkProgram(int vertexShaderId, int fragmentShaderId) { 117 | 118 | // Create a new program object. 119 | final int programObjectId = glCreateProgram(); 120 | 121 | if (programObjectId == 0) { 122 | GLog.e(TAG, "Could not create new program"); 123 | return 0; 124 | } 125 | 126 | // Attach the vertex shader to the program. 127 | glAttachShader(programObjectId, vertexShaderId); 128 | 129 | // Attach the fragment shader to the program. 130 | glAttachShader(programObjectId, fragmentShaderId); 131 | 132 | // Link the two shaders together into a program. 133 | glLinkProgram(programObjectId); 134 | 135 | // Get the link status. 136 | final int[] linkStatus = new int[1]; 137 | glGetProgramiv(programObjectId, GL_LINK_STATUS, 138 | linkStatus, 0); 139 | 140 | GLog.d(TAG, "Results of linking program:\n" + glGetProgramInfoLog(programObjectId)); 141 | 142 | // Verify the link status. 143 | if (linkStatus[0] == 0) { 144 | // If it failed, delete the program object. 145 | glDeleteProgram(programObjectId); 146 | 147 | GLog.e(TAG, "Linking of program failed."); 148 | 149 | return 0; 150 | } 151 | 152 | // Return the program object ID. 153 | return programObjectId; 154 | } 155 | 156 | /** 157 | * Validates an OpenGL program. Should only be called when developing the 158 | * application. 159 | */ 160 | public static boolean validateProgram(int programObjectId) { 161 | glValidateProgram(programObjectId); 162 | final int[] validateStatus = new int[1]; 163 | glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, 164 | validateStatus, 0); 165 | GLog.d(TAG, "Results of validating program: " + validateStatus[0] 166 | + "\nLog:" + glGetProgramInfoLog(programObjectId)); 167 | 168 | return validateStatus[0] != 0; 169 | } 170 | 171 | /** 172 | * Helper function that compiles the shaders, links and validates the 173 | * program, returning the program ID. 174 | */ 175 | public static int buildProgram(String vertexShaderSource, 176 | String fragmentShaderSource) { 177 | int program; 178 | 179 | // Compile the shaders. 180 | int vertexShader = compileVertexShader(vertexShaderSource); 181 | int fragmentShader = compileFragmentShader(fragmentShaderSource); 182 | 183 | // Link them into a shader program. 184 | program = linkProgram(vertexShader, fragmentShader); 185 | 186 | validateProgram(program); 187 | 188 | return program; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/obj/Object.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid.obj; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.ByteOrder; 5 | import java.nio.FloatBuffer; 6 | import java.nio.ShortBuffer; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import wxplus.opengles2forandroid.obj.base.Circle; 11 | import wxplus.opengles2forandroid.obj.base.Cylinder; 12 | import wxplus.opengles2forandroid.obj.base.Square; 13 | import wxplus.opengles2forandroid.programs.ShaderProgram; 14 | import wxplus.opengles2forandroid.utils.GlobalConfig; 15 | 16 | import static android.opengl.GLES20.GL_TRIANGLE_FAN; 17 | import static android.opengl.GLES20.GL_TRIANGLE_STRIP; 18 | import static android.opengl.GLES20.glDrawArrays; 19 | import static wxplus.opengles2forandroid.utils.Constants.BYTES_PER_FLOAT; 20 | import static wxplus.opengles2forandroid.utils.Constants.BYTES_PER_SHORT; 21 | import static wxplus.opengles2forandroid.utils.Constants.FLOATS_PER_VERTEX; 22 | import static wxplus.opengles2forandroid.utils.Constants.VERTEX_COUNT_SQUARE; 23 | 24 | /** 25 | * @author WangXiaoPlus 26 | * @date 2017/11/19 27 | *

28 | * 图形的基类,提供共有方法 29 | */ 30 | 31 | public class Object { 32 | public static final String TAG = Object.class.getSimpleName(); 33 | 34 | protected FloatBuffer mVertexBuffer; 35 | protected float[] mVertexData; 36 | protected int offset = 0; 37 | 38 | protected ShortBuffer mIndexBuffer; 39 | protected short[] mIndexData; 40 | 41 | protected FloatBuffer mTextureBuffer; 42 | protected static final float[] TEXTURE_DATA = { 43 | // Order of coordinates: S, T 44 | 45 | // Triangle Fan 46 | 0.5f, 0.5f, 47 | 0f, 0f, 48 | 1f, 0f, 49 | 1f, 1f, 50 | 0f, 1f, 51 | 0f, 0f 52 | }; 53 | 54 | protected List drawTaskList = new ArrayList<>(); 55 | 56 | public Object addSquare(Square square) { 57 | final int startVertex = offset / FLOATS_PER_VERTEX; 58 | final int vertexCount = VERTEX_COUNT_SQUARE; 59 | if (mVertexData == null || mVertexData.length - offset < vertexCount * FLOATS_PER_VERTEX) { 60 | return this; 61 | } 62 | // 先确定正方形中心的坐标 63 | mVertexData[offset++] = square.center.x; 64 | mVertexData[offset++] = square.center.y; 65 | mVertexData[offset++] = square.center.z; 66 | // 左下角 67 | mVertexData[offset++] = square.center.x - square.widht / 2; 68 | mVertexData[offset++] = square.center.y - square.height / 2; 69 | mVertexData[offset++] = square.center.z; 70 | // 右下角 71 | mVertexData[offset++] = square.center.x + square.widht / 2; 72 | mVertexData[offset++] = square.center.y - square.height / 2; 73 | mVertexData[offset++] = square.center.z; 74 | // 右上角 75 | mVertexData[offset++] = square.center.x + square.widht / 2; 76 | mVertexData[offset++] = square.center.y + square.height / 2; 77 | mVertexData[offset++] = square.center.z; 78 | // 左上角 79 | mVertexData[offset++] = square.center.x - square.widht / 2; 80 | mVertexData[offset++] = square.center.y + square.height / 2; 81 | mVertexData[offset++] = square.center.z; 82 | // 左下角(triangle fan) 83 | mVertexData[offset++] = square.center.x - square.widht / 2; 84 | mVertexData[offset++] = square.center.y - square.height / 2; 85 | mVertexData[offset++] = square.center.z; 86 | drawTaskList.add(new DrawTask() { 87 | @Override 88 | public void draw() { 89 | glDrawArrays(GL_TRIANGLE_FAN, startVertex, vertexCount); 90 | } 91 | }); 92 | return this; 93 | } 94 | 95 | public Object addCircle(Circle circle, int pointCount) { 96 | final int startVertex = offset / FLOATS_PER_VERTEX; 97 | final int vertexCount = sizeOfCircleInVertex(pointCount); 98 | if (mVertexData == null || mVertexData.length - offset < vertexCount * FLOATS_PER_VERTEX) { 99 | if (GlobalConfig.DEBUG) { 100 | throw new IndexOutOfBoundsException(TAG + ", addCircle, mVertexData is not big enough"); 101 | } 102 | return this; 103 | } 104 | // 先确定圆心的坐标 105 | mVertexData[offset++] = circle.center.x; 106 | mVertexData[offset++] = circle.center.y; 107 | mVertexData[offset++] = circle.center.z; 108 | // 循环赋值,确定圆上顶点的坐标(最后一个顶点赋值两次) 109 | float radian = (float) (2 * Math.PI / pointCount); // 先计算出每一份的弧度值 110 | for (int i = 0; i <= pointCount; i++) { 111 | mVertexData[offset++] = circle.center.x + circle.radius * (float) Math.cos(radian * i); 112 | mVertexData[offset++] = circle.center.y + circle.radius * (float) Math.sin(radian * i); 113 | mVertexData[offset++] = circle.center.z; 114 | } 115 | drawTaskList.add(new DrawTask() { 116 | @Override 117 | public void draw() { 118 | glDrawArrays(GL_TRIANGLE_FAN, startVertex, vertexCount); 119 | } 120 | }); 121 | return this; 122 | } 123 | 124 | public Object addOpenCylinder(Cylinder cylinder, int pointCount) { 125 | final int startVertex = offset / FLOATS_PER_VERTEX; 126 | final int vertexCount = sizeOfCylinderInVertex(pointCount); 127 | if (mVertexData == null || mVertexData.length - offset < vertexCount * FLOATS_PER_VERTEX) { 128 | if (GlobalConfig.DEBUG) { 129 | throw new IndexOutOfBoundsException(TAG + ", addOpenCylinder, mVertexData is not big enough"); 130 | } 131 | return this; 132 | } 133 | float topZ = cylinder.center.z + cylinder.height / 2; 134 | float bottomZ = cylinder.center.z - cylinder.height / 2; 135 | float radian = (float) (2 * Math.PI / pointCount); // 先计算出每一份的弧度值 136 | // 依次赋值 137 | for (int i = 0; i <= pointCount; i++) { 138 | float x = cylinder.center.x + cylinder.radius * (float) Math.cos(i + radian); 139 | float y = cylinder.center.y + cylinder.radius * (float) Math.sin(i + radian); 140 | // top 141 | mVertexData[offset++] = x; 142 | mVertexData[offset++] = y; 143 | mVertexData[offset++] = topZ; 144 | // bottom 145 | mVertexData[offset++] = x; 146 | mVertexData[offset++] = y; 147 | mVertexData[offset++] = bottomZ; 148 | } 149 | drawTaskList.add(new DrawTask() { 150 | @Override 151 | public void draw() { 152 | glDrawArrays(GL_TRIANGLE_STRIP, startVertex, vertexCount); 153 | } 154 | }); 155 | return this; 156 | } 157 | 158 | public FloatBuffer getVertexBuffer() { 159 | if (mVertexBuffer == null) { 160 | mVertexBuffer = ByteBuffer 161 | .allocateDirect(mVertexData.length * BYTES_PER_FLOAT) 162 | .order(ByteOrder.nativeOrder()) 163 | .asFloatBuffer() 164 | .put(mVertexData); 165 | } 166 | mVertexBuffer.position(0); 167 | return mVertexBuffer; 168 | } 169 | 170 | public FloatBuffer getTextureBuffer() { 171 | if (mTextureBuffer == null) { 172 | mTextureBuffer = ByteBuffer 173 | .allocateDirect(TEXTURE_DATA.length * BYTES_PER_FLOAT) 174 | .order(ByteOrder.nativeOrder()) 175 | .asFloatBuffer() 176 | .put(TEXTURE_DATA); 177 | } 178 | mTextureBuffer.position(0); 179 | return mTextureBuffer; 180 | } 181 | 182 | public ShortBuffer getIndexBuffer() { 183 | if (mIndexBuffer == null) { 184 | mIndexBuffer = ByteBuffer 185 | .allocateDirect(mIndexData.length * BYTES_PER_SHORT) 186 | .order(ByteOrder.nativeOrder()) 187 | .asShortBuffer() 188 | .put(mIndexData); 189 | } 190 | mIndexBuffer.position(0); 191 | return mIndexBuffer; 192 | } 193 | 194 | public void draw() { 195 | for (int i = 0; i < drawTaskList.size(); i++) { 196 | drawTaskList.get(i).draw(); 197 | } 198 | } 199 | 200 | public int sizeOfCircleInVertex(int pointCount) { 201 | return pointCount + 2; 202 | } 203 | 204 | public int sizeOfCylinderInVertex(int pointCount) { 205 | return (pointCount + 1) * 2; 206 | } 207 | 208 | public int floatSizeOfVertexs(int vertexCount) { 209 | return FLOATS_PER_VERTEX * vertexCount; 210 | } 211 | 212 | public interface DrawTask { 213 | void draw(); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /app/src/main/java/wxplus/opengles2forandroid/OpenGL_02_Simple_Texture.java: -------------------------------------------------------------------------------- 1 | package wxplus.opengles2forandroid; 2 | 3 | import android.app.ActivityManager; 4 | import android.content.Context; 5 | import android.content.pm.ConfigurationInfo; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.opengl.GLSurfaceView; 9 | import android.opengl.Matrix; 10 | import android.os.Build; 11 | import android.os.Bundle; 12 | 13 | import java.nio.ByteBuffer; 14 | import java.nio.ByteOrder; 15 | import java.nio.FloatBuffer; 16 | 17 | import javax.microedition.khronos.egl.EGLConfig; 18 | import javax.microedition.khronos.opengles.GL10; 19 | 20 | import wxplus.opengles2forandroid.utils.TextureUtils; 21 | 22 | import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; 23 | import static android.opengl.GLES20.GL_COMPILE_STATUS; 24 | import static android.opengl.GLES20.GL_FLOAT; 25 | import static android.opengl.GLES20.GL_FRAGMENT_SHADER; 26 | import static android.opengl.GLES20.GL_LINEAR; 27 | import static android.opengl.GLES20.GL_LINEAR_MIPMAP_LINEAR; 28 | import static android.opengl.GLES20.GL_TEXTURE0; 29 | import static android.opengl.GLES20.GL_TEXTURE_2D; 30 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; 31 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; 32 | import static android.opengl.GLES20.GL_TRIANGLE_FAN; 33 | import static android.opengl.GLES20.GL_VERTEX_SHADER; 34 | import static android.opengl.GLES20.glActiveTexture; 35 | import static android.opengl.GLES20.glAttachShader; 36 | import static android.opengl.GLES20.glBindTexture; 37 | import static android.opengl.GLES20.glClear; 38 | import static android.opengl.GLES20.glClearColor; 39 | import static android.opengl.GLES20.glCompileShader; 40 | import static android.opengl.GLES20.glCreateProgram; 41 | import static android.opengl.GLES20.glCreateShader; 42 | import static android.opengl.GLES20.glDrawArrays; 43 | import static android.opengl.GLES20.glEnableVertexAttribArray; 44 | import static android.opengl.GLES20.glGenTextures; 45 | import static android.opengl.GLES20.glGenerateMipmap; 46 | import static android.opengl.GLES20.glGetAttribLocation; 47 | import static android.opengl.GLES20.glGetShaderiv; 48 | import static android.opengl.GLES20.glGetUniformLocation; 49 | import static android.opengl.GLES20.glLinkProgram; 50 | import static android.opengl.GLES20.glShaderSource; 51 | import static android.opengl.GLES20.glTexParameteri; 52 | import static android.opengl.GLES20.glUniform1i; 53 | import static android.opengl.GLES20.glUniform4f; 54 | import static android.opengl.GLES20.glUniformMatrix4fv; 55 | import static android.opengl.GLES20.glUseProgram; 56 | import static android.opengl.GLES20.glVertexAttribPointer; 57 | import static android.opengl.GLES20.glViewport; 58 | import static android.opengl.GLUtils.texImage2D; 59 | import static android.opengl.Matrix.multiplyMM; 60 | import static android.opengl.Matrix.orthoM; 61 | import static android.opengl.Matrix.rotateM; 62 | import static android.opengl.Matrix.setIdentityM; 63 | import static android.opengl.Matrix.translateM; 64 | import static wxplus.opengles2forandroid.utils.Constants.BYTES_PER_FLOAT; 65 | 66 | /** 67 | * Created by hi on 2017/10/29. 68 | */ 69 | 70 | public class OpenGL_02_Simple_Texture extends BaseActivity { 71 | 72 | protected GLSurfaceView mGlView; 73 | 74 | @Override 75 | protected void onCreate(Bundle savedInstanceState) { 76 | super.onCreate(savedInstanceState); 77 | mGlView = new GLSurfaceView(this); 78 | // Request an OpenGL ES 2.0 compatible context. 79 | mGlView.setEGLContextClientVersion(2); 80 | mGlView.setRenderer(new CusRenderer()); 81 | // Check if the system supports OpenGL ES 2.0. 82 | ActivityManager activityManager = 83 | (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 84 | ConfigurationInfo configurationInfo = activityManager 85 | .getDeviceConfigurationInfo(); 86 | final boolean supportsEs2 = 87 | configurationInfo.reqGlEsVersion >= 0x20000 88 | || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1 89 | && (Build.FINGERPRINT.startsWith("generic") 90 | || Build.FINGERPRINT.startsWith("unknown") 91 | || Build.MODEL.contains("google_sdk") 92 | || Build.MODEL.contains("Emulator") 93 | || Build.MODEL.contains("Android SDK built for x86"))); 94 | setContentView(mGlView); 95 | } 96 | 97 | protected float[] mVertexArray = new float[] { // OpenGL的坐标是[-1, 1],这里的Vertex正好定义了一个居中的正方形 98 | // Triangle Fan x, y 99 | 0f, 0f, 100 | -0.5f, -0.5f, 101 | 0.5f, -0.5f, 102 | 0.5f, 0.5f, 103 | -0.5f, 0.5f, 104 | -0.5f, -0.5f 105 | }; 106 | protected float[] mTextureArray = new float[] { 107 | 0.5f, 0.5f, 108 | 0f, 1f, 109 | 1f, 1f, 110 | 1f, 0f, 111 | 0f, 0f, 112 | 0f, 1f 113 | }; 114 | protected FloatBuffer mVertexBuffer; 115 | protected FloatBuffer mTextureBuffer; 116 | protected float[] mProjectionMatrix = new float[16]; 117 | 118 | protected int textureId; 119 | 120 | protected int uMatrixLocation; 121 | protected int aPositionLocation; 122 | protected int aTextureCoordinatesLocation; 123 | protected int uTextureUnitLocation; 124 | 125 | public class CusRenderer implements GLSurfaceView.Renderer { 126 | 127 | @Override 128 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 129 | glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 130 | // 初始化顶点数据 131 | mVertexBuffer = ByteBuffer.allocateDirect(mVertexArray.length * BYTES_PER_FLOAT) 132 | .order(ByteOrder.nativeOrder()) 133 | .asFloatBuffer() 134 | .put(mVertexArray); 135 | mTextureBuffer = ByteBuffer.allocateDirect(mTextureArray.length * BYTES_PER_FLOAT) 136 | .order(ByteOrder.nativeOrder()) 137 | .asFloatBuffer() 138 | .put(mTextureArray); 139 | String vertexShaderStr = TextureUtils.readShaderCodeFromResource(mActivity, R.raw.texture_vertex_shader); 140 | String fragmentShaderStr = TextureUtils.readShaderCodeFromResource(mActivity, R.raw.texture_fragment_shader); 141 | // 创建Shader 142 | final int vertexShaderId = glCreateShader(GL_VERTEX_SHADER); 143 | final int fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER); 144 | glShaderSource(vertexShaderId, vertexShaderStr); 145 | glShaderSource(fragmentShaderId, fragmentShaderStr); 146 | glCompileShader(vertexShaderId); 147 | glCompileShader(fragmentShaderId); 148 | final int[] compileStatus = new int[1]; 149 | glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, 150 | compileStatus, 0); 151 | // 创建Program 152 | final int programId = glCreateProgram(); 153 | glAttachShader(programId, vertexShaderId); 154 | glAttachShader(programId, fragmentShaderId); 155 | glLinkProgram(programId); 156 | // 启用这个Program 157 | glUseProgram(programId); 158 | // 找到需要赋值的变量 159 | uMatrixLocation = glGetUniformLocation(programId, "u_Matrix"); 160 | aPositionLocation = glGetAttribLocation(programId, "a_Position"); 161 | aTextureCoordinatesLocation = glGetAttribLocation(programId, "a_TextureCoordinates"); 162 | uTextureUnitLocation = glGetUniformLocation(programId, "u_TextureUnit"); 163 | // 初始化Texture 164 | final int[] textureObjectIds = new int[1]; 165 | glGenTextures(1, textureObjectIds, 0); 166 | textureId = textureObjectIds[0]; 167 | final BitmapFactory.Options options = new BitmapFactory.Options(); 168 | final Bitmap bitmap = BitmapFactory.decodeResource( 169 | getResources(), R.drawable.texture, options); 170 | glBindTexture(GL_TEXTURE_2D, textureId); 171 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 172 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 173 | texImage2D(GL_TEXTURE_2D, 0, bitmap, 0); 174 | glGenerateMipmap(GL_TEXTURE_2D); 175 | bitmap.recycle(); 176 | // 使用该Texture 177 | glActiveTexture(GL_TEXTURE0); 178 | glUniform1i(uTextureUnitLocation, 0); 179 | // 填充数据 180 | mVertexBuffer.position(0); 181 | glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, false, 0, mVertexBuffer); 182 | glEnableVertexAttribArray(aPositionLocation); 183 | mTextureBuffer.position(0); 184 | glVertexAttribPointer(aTextureCoordinatesLocation, 2, GL_FLOAT, false, 0, mTextureBuffer); 185 | glEnableVertexAttribArray(aTextureCoordinatesLocation); 186 | } 187 | 188 | @Override 189 | public void onSurfaceChanged(GL10 gl, int width, int height) { 190 | glViewport(0, 0, width, height); 191 | // 正交投影 192 | float rate = (float) height / width; 193 | orthoM(mProjectionMatrix, 0, -1, 1, -rate, rate, -1, 1); 194 | // 赋值 195 | glUniformMatrix4fv(uMatrixLocation, 1, false, mProjectionMatrix, 0); 196 | } 197 | 198 | @Override 199 | public void onDrawFrame(GL10 gl) { 200 | glClear(GL_COLOR_BUFFER_BIT); 201 | glDrawArrays(GL_TRIANGLE_FAN, 0, 6); 202 | } 203 | } 204 | 205 | } 206 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------