如何处理 Opengl ES 中的方向变化
How to deal with orientation change in Open GL ES
我正在为 android 试用 Open GL 2。到目前为止,我已经能够初始化 GLES20 并在其上绘制一些简单的形状。问题是我找不到关于应该如何为屏幕方向更改配置 GLES20 的信息,因为现在我只是在设备旋转后出现黑屏。 GLSurfaceView 甚至可以在屏幕旋转后旋转,还是我必须使用一些矩阵手动旋转?
打开 GL 初始化代码:
object OpenGLBuilder {
val vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}"
val fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}"
var mProgram = -1;
init {
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram().also {
// add the vertex shader to program
GLES20.glAttachShader(it, vertexShader)
// add the fragment shader to program
GLES20.glAttachShader(it, fragmentShader)
// creates OpenGL ES program executables
GLES20.glLinkProgram(it)
}
}
fun loadShader(type: Int, shaderCode: String): Int {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
return GLES20.glCreateShader(type).also { shader ->
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode)
GLES20.glCompileShader(shader)
}
}
}
我的形状class:
class Triangle(val triangleCoords: FloatArray) {
// Set color with red, green, blue and alpha (opacity) values
val color = floatArrayOf(0.63671875f, 0.76953125f, 0.22265625f, 1.0f)
private var vertexBuffer: FloatBuffer =
// (number of coordinate values * 4 bytes per float)
ByteBuffer.allocateDirect(triangleCoords.size * 4).run {
// use the device hardware's native byte order
order(ByteOrder.nativeOrder())
// create a floating point buffer from the ByteBuffer
asFloatBuffer().apply {
// add the coordinates to the FloatBuffer
put(triangleCoords)
// set the buffer to read the first coordinate
position(0)
}
}
private val COORDS_PER_VERTEX = 3
private var positionHandle = 0
private var mColorHandle = 0;
private val vertexCount = triangleCoords.size / COORDS_PER_VERTEX
private val vertexStride = COORDS_PER_VERTEX * 4
fun draw(program: Int) {
GLES20.glUseProgram(program)
positionHandle = GLES20.glGetAttribLocation(program, "vPosition").also {
GLES20.glEnableVertexAttribArray(it)
GLES20.glVertexAttribPointer(
it,
COORDS_PER_VERTEX,
GLES20.GL_FLOAT,
false,
vertexStride,
vertexBuffer
)
}
mColorHandle = GLES20.glGetUniformLocation(program, "vColor").also{
GLES20.glUniform4fv(mColorHandle, 1, color, 0)
}
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)
GLES20.glDisableVertexAttribArray(positionHandle)
}
}
然后我只创建并使用这样的单个形状实例:
object SceneObjects {
val triangle1 = Triangle(floatArrayOf(
0f, 0.5f, 0f,
-0.5f, -0.3f, 0f,
0.5f, -0.3f, 0f
))
val square1 = Square2(floatArrayOf(
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f
))
}
和 GLSurfaceView:
class MyGLSurfaceView(context: Context) : GLSurfaceView(context), GLSurfaceView.Renderer {
init{
setEGLContextClientVersion(2)
setRenderer(this)
// Render the view only when there is a change in the drawing data
renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
}
override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
}
override fun onDrawFrame(unused: GL10) {
// Redraw background color
SceneObjects.triangle1.draw(OpenGLBuilder.mProgram)
}
override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
}
}
我认为您需要做两件事来巧妙地处理方向变化。
首先,默认情况下,您的 OpenGL 上下文和所有创建的对象在进入后台时都会被销毁。有一种观点认为您应该让它发生并添加代码以重新创建所有资源,但如果您希望过上轻松的生活,那么只需使用 setPreserveEGLContextOnPause,再也不用担心它了。
您可能会想“但这是方向改变,我的应用程序没有进入后台”。好吧,默认情况下 Android activity 会在方向改变后重新启动,这可能会把事情搞砸。此行为详细 here。您可能想在您的 activity 的清单中使用此批次:android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
我正在为 android 试用 Open GL 2。到目前为止,我已经能够初始化 GLES20 并在其上绘制一些简单的形状。问题是我找不到关于应该如何为屏幕方向更改配置 GLES20 的信息,因为现在我只是在设备旋转后出现黑屏。 GLSurfaceView 甚至可以在屏幕旋转后旋转,还是我必须使用一些矩阵手动旋转?
打开 GL 初始化代码:
object OpenGLBuilder {
val vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}"
val fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}"
var mProgram = -1;
init {
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram().also {
// add the vertex shader to program
GLES20.glAttachShader(it, vertexShader)
// add the fragment shader to program
GLES20.glAttachShader(it, fragmentShader)
// creates OpenGL ES program executables
GLES20.glLinkProgram(it)
}
}
fun loadShader(type: Int, shaderCode: String): Int {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
return GLES20.glCreateShader(type).also { shader ->
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode)
GLES20.glCompileShader(shader)
}
}
}
我的形状class:
class Triangle(val triangleCoords: FloatArray) {
// Set color with red, green, blue and alpha (opacity) values
val color = floatArrayOf(0.63671875f, 0.76953125f, 0.22265625f, 1.0f)
private var vertexBuffer: FloatBuffer =
// (number of coordinate values * 4 bytes per float)
ByteBuffer.allocateDirect(triangleCoords.size * 4).run {
// use the device hardware's native byte order
order(ByteOrder.nativeOrder())
// create a floating point buffer from the ByteBuffer
asFloatBuffer().apply {
// add the coordinates to the FloatBuffer
put(triangleCoords)
// set the buffer to read the first coordinate
position(0)
}
}
private val COORDS_PER_VERTEX = 3
private var positionHandle = 0
private var mColorHandle = 0;
private val vertexCount = triangleCoords.size / COORDS_PER_VERTEX
private val vertexStride = COORDS_PER_VERTEX * 4
fun draw(program: Int) {
GLES20.glUseProgram(program)
positionHandle = GLES20.glGetAttribLocation(program, "vPosition").also {
GLES20.glEnableVertexAttribArray(it)
GLES20.glVertexAttribPointer(
it,
COORDS_PER_VERTEX,
GLES20.GL_FLOAT,
false,
vertexStride,
vertexBuffer
)
}
mColorHandle = GLES20.glGetUniformLocation(program, "vColor").also{
GLES20.glUniform4fv(mColorHandle, 1, color, 0)
}
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)
GLES20.glDisableVertexAttribArray(positionHandle)
}
}
然后我只创建并使用这样的单个形状实例:
object SceneObjects {
val triangle1 = Triangle(floatArrayOf(
0f, 0.5f, 0f,
-0.5f, -0.3f, 0f,
0.5f, -0.3f, 0f
))
val square1 = Square2(floatArrayOf(
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f
))
}
和 GLSurfaceView:
class MyGLSurfaceView(context: Context) : GLSurfaceView(context), GLSurfaceView.Renderer {
init{
setEGLContextClientVersion(2)
setRenderer(this)
// Render the view only when there is a change in the drawing data
renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
}
override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
}
override fun onDrawFrame(unused: GL10) {
// Redraw background color
SceneObjects.triangle1.draw(OpenGLBuilder.mProgram)
}
override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
}
}
我认为您需要做两件事来巧妙地处理方向变化。
首先,默认情况下,您的 OpenGL 上下文和所有创建的对象在进入后台时都会被销毁。有一种观点认为您应该让它发生并添加代码以重新创建所有资源,但如果您希望过上轻松的生活,那么只需使用 setPreserveEGLContextOnPause,再也不用担心它了。
您可能会想“但这是方向改变,我的应用程序没有进入后台”。好吧,默认情况下 Android activity 会在方向改变后重新启动,这可能会把事情搞砸。此行为详细 here。您可能想在您的 activity 的清单中使用此批次:android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"