第2章 GLES一个示例

你好,三角形:

■ 先给出完整源代码 ■

AndroidMainfest.xml中添加:

<!-- Tell the system this application requires OpenGL ES 3.0. -->
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
public class HelloTriangleRenderer implements GLSurfaceView.Renderer {
	// Member variables
	private int mProgramObject;
	private int mWidth;
	private int mHeight;
	private FloatBuffer mVertices;
	private static String TAG = "HelloTriangleRenderer";

	private final float[] mVerticesData = { 
            0.0f, 0.5f, 0.0f, 
            -0.5f, -0.5f, 0.0f, 
            0.5f, -0.5f, 0.0f 
	};

	// Constructor
	public HelloTriangleRenderer(Context context) {
		mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
		mVertices.put(mVerticesData).position(0);
	}

	// Create a shader object, load the shader source, and compile the shader.
	private int LoadShader(int type, String shaderSrc) {
		int shader;
		int[] compiledStatus = new int[1];

		// Create the shader object
		shader = GLES30.glCreateShader(type);

		if (shader == 0) {
			return 0;
		}

		// Load the shader source
		GLES30.glShaderSource(shader, shaderSrc);

		// Compile the shader
		GLES30.glCompileShader(shader);

		// Check the compile status
		GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compiledStatus, 0);

		if (compiledStatus[0] == 0) {
			Log.e(TAG, GLES30.glGetShaderInfoLog(shader));
			GLES30.glDeleteShader(shader);
			return 0;
		}
		return shader;
	}

	// Initialize the shader and program object
	@Override
	public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
		String vShaderStr = "#version 300 es             \n" 
				  + "in vec4 vPosition;          \n"
				  + "void main()                 \n" 
				  + "{                           \n"
				  + "   gl_Position = vPosition; \n" 
				  + "}                           \n";

		String fShaderStr = "#version 300 es                            \n"
				  + "precision mediump float;                   \n" 
				  + "out vec4 fragColor;                        \n"
				  + "void main()                                \n" 
				  + "{                                          \n"
				  + "  fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n" 
				  + "}                                          \n";

		int vertexShader;
		int fragmentShader;
		int programObject;
		int[] linkedStatus = new int[1];

		// Load the vertex/fragment shaders
		vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER, vShaderStr);
		fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER, fShaderStr);

		// Create the program object
		programObject = GLES30.glCreateProgram();

		if (programObject == 0) {
			return;
		}

		GLES30.glAttachShader(programObject, vertexShader);
		GLES30.glAttachShader(programObject, fragmentShader);

		// Bind vPosition to attribute 0
		GLES30.glBindAttribLocation(programObject, 0, "vPosition");

		// Link the program
		GLES30.glLinkProgram(programObject);

		// Check the link status
		GLES30.glGetProgramiv(programObject, GLES30.GL_LINK_STATUS, linkedStatus, 0);

		if (linkedStatus[0] == 0) {
			Log.e(TAG, "Error linking program:");
			Log.e(TAG, GLES30.glGetProgramInfoLog(programObject));
			GLES30.glDeleteProgram(programObject);
			return;
		}

		// Store the program object
		mProgramObject = programObject;

		GLES30.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
	}

	// Handle surface changes
	@Override
	public void onSurfaceChanged(GL10 glUnused, int width, int height) {
		mWidth = width;
		mHeight = height;
	}

	// Draw a triangle using the shader pair created in onSurfaceCreated()
	@Override
	public void onDrawFrame(GL10 glUnused) {
		// Set the viewport
		GLES30.glViewport(0, 0, mWidth, mHeight);

		// Clear the color buffer
		GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);

		// Use the program object
		GLES30.glUseProgram(mProgramObject);

		// Load the vertex data
		GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, mVertices);
		GLES30.glEnableVertexAttribArray(0);

		GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3);
	}
}
public class HelloTriangle extends Activity {
	private final int CONTEXT_CLIENT_VERSION = 3;
	private GLSurfaceView mGLSurfaceView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mGLSurfaceView = new GLSurfaceView(this);

		if (detectOpenGLES30()) {
			// Tell the surface view we want to create an OpenGL ES 3.0-compatible
			// context, and set an OpenGL ES 3.0-compatible renderer.
			mGLSurfaceView.setEGLContextClientVersion(CONTEXT_CLIENT_VERSION);
			mGLSurfaceView.setRenderer(new HelloTriangleRenderer(this));
		} else {
			Log.e("HelloTriangle", "OpenGL ES 3.0 not supported on device.  Exiting...");
			finish();

		}
		setContentView(mGLSurfaceView);
	}

	private boolean detectOpenGLES30() {
		ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
		ConfigurationInfo info = am.getDeviceConfigurationInfo();
		return (info.reqGlEsVersion >= 0x30000);
	}

	@Override
	protected void onResume() {
		// Ideally a game should implement onResume() and onPause()
		// to take appropriate action when the activity looses focus
		super.onResume();
		mGLSurfaceView.onResume();
	}

	@Override
	protected void onPause() {
		// Ideally a game should implement onResume() and onPause()
		// to take appropriate action when the activity looses focus
		super.onPause();
		mGLSurfaceView.onPause();
	}
}
public class GLES30 extends GLES20
java.lang.Object
   ↳	android.opengl.GLES20
 	   ↳	android.opengl.GLES30
Known direct subclasses
GLES31
Known indirect subclasses
GLES32

public class GLSurfaceView
extends SurfaceView implements SurfaceHolder.Callback2

java.lang.Object
   ↳	android.view.View
 	   ↳	android.view.SurfaceView
 	 	   ↳	android.opengl.GLSurfaceView

An implementation of SurfaceView that uses the dedicated surface for displaying OpenGL rendering.
GLSurfaceView.setRenderer(Renderer)

Public methods:
abstract void onDrawFrame(GL10 gl)
● Called to draw the current frame.

abstract void onSurfaceChanged(GL10 gl, int width, int height)
● Called when the surface changed size.

abstract void onSurfaceCreated(GL10 gl, EGLConfig config)
● Called when the surface is created or recreated.

 

记住:OpenGL ES 3.0完全基于着色器,这意味着,如果没有加载和绑定合适的着色器,就无法绘制任何几何形状。也就是说,渲染需要比使用固定功能处理的桌面OpenGL更多的设置代码。着色器,至少要有顶点着色器和片段着色器。

最终渲染效果:

可见,顶点着色器决定了三个顶点构造的三角形GL_TRIANGLES,片段着色器决定了图元的颜色vec4(1.0,0.0,0.0,1.0)。

一旦应用程序为顶点和片段着色器创建了着色器对象,就需要创建一个程序对象。从概念上说,程序对象可以视为最终链接的程序。不同的着色器编译为一个着色器对象之后,它们必须连接到一个程序对象并一起链接,才能绘制图形。

显示后台缓冲区:

到了将三角形绘制到帧缓冲区时,必须介绍最后一个细节:如何在屏幕上真正显示帧缓冲区的内容。

先讨论双缓冲区(Double Buffering)的概念。

屏幕上可见的帧缓冲区由一个像素数据的二维数组表示。我们可以将在屏幕上显示图像视为在绘制时简单地更新可见帧缓冲区中的像素数据。但是,直接在可显示缓冲区上更新像素有一个严重的问题——也就是说,在典型的显示系统中,物理屏幕以固定的速率从帧缓冲区内存中更新。如果我们直接绘制到帧缓冲区,那么用户在部分更新帧缓冲区时会看到伪像。

为了解决这个问题,我们使用所谓的双缓冲区。在这种方案中,有两个缓冲区:前台缓冲区和后台缓冲区。所有渲染都发生在后台缓冲区,它位于不可见屏幕的内存区域。当所有渲染完成时,这个缓冲区被“交换”到前台缓冲区(或者可见缓冲区)。然后前台缓冲区变成下一帧的后台缓冲区。使用这种技术,我们在一帧上的所有渲染完成之前不显示可见表面。

在Linux环境中使用EGL(Embedded OpenGL Library)绘制图形通常需要在C++中配合OpenGL ES。以下是一个简单的示例,展示了如何在EGL上下文中创建一个窗口并渲染一个红色的正方形: ```cpp #include <EGL/egl.h> #include <GLES2/gl2.h> #include <iostream> // 创建EGL显示上下文 Display* eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (eglDisplay == EGL_NO_DISPLAY) { std::cerr << "Failed to get EGL display" << std::endl; return; } int eglInitResult = eglInitialize(eglDisplay, NULL, NULL); if (eglInitResult != EGL_TRUE) { std::cerr << "Failed to initialize EGL" << std::endl; return; } // 获取配置信息 const EGLint configAttributes[] = { EGL_SURFACE_TYPE , EGL_WINDOW_BIT, EGL_RED_SIZE , 8, EGL_GREEN_SIZE , 8, EGL_BLUE_SIZE , 8, EGL_ALPHA_SIZE , 8, EGL_NONE }; EGLConfig eglConfig; EGLint numConfigs; eglChooseConfig(eglDisplay, configAttributes, &eglConfig, 1, &numConfigs); // 创建窗口 Window *window = createWindow(); // 这部分取决于您的环境,创建一个EGL支持的窗口 // 创建EGLSurface EGLSurface eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, window->nativeWindow, NULL); if (eglSurface == EGL_NO_SURFACE) { std::cerr << "Failed to create EGL surface" << std::endl; return; } // 创建EGLContext EGLContext eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, NULL); if (eglContext == EGL_NO_CONTEXT) { std::cerr << "Failed to create EGL context" << std::endl; return; } // 绑定EGLContext到Surface eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); // 初始化OpenGL ES glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 清除背景色 glClear(GL_COLOR_BUFFER_BIT); // 渲染一个全屏的红色 // 绘制红色正方形 glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // 设置颜色 glRectf(-0.5f, -0.5f, 0.5f, 0.5f); // 绘制正方形 // 刷新屏幕 eglSwapBuffers(eglDisplay, eglSurface); // 释放资源 eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(eglDisplay, eglContext); eglDestroySurface(eglDisplay, eglSurface); delete window; eglTerminate(eglDisplay); ``` 注意,这只是一个基本的示例,实际应用可能还需要处理错误、添加事件监听等。同时,`createWindow()`函数需根据具体的环境实现,比如X11、Wayland等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzyjr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值