gregoiregentil
gregoiregentil

Reputation: 1889

Move pixels around in OpenGL-ES (Android)

I have a texture that I can render in OpenGL-ES with an orthogonal identity matrix:

gst_gl_shader_set_uniform_matrix_4fv(shader, "u_transformation", 1, FALSE, identity_matrix);

I want to move "the pixels around": half of the top is going to the left, half of the bottom is going to the right as shown on the image below. Is there an "easy" way to do that? I'm on Android.

On this related answered question How to crop/clip in OpenGL using u_transformation, I was able to keep the top part 'a' or the bottom part 'e'. Would there be a way to do a "double gst_gl_shader_set_uniform_matrix_4fv" after "cutting" the scene in two?

enter image description here

Upvotes: 0

Views: 534

Answers (2)

gregoiregentil
gregoiregentil

Reputation: 1889

The formula described in Reto answers 'semi' work as they only produce the "a" on the left or the "e" on the right but not both at the same time.

The solution I found is to double the number of vertices and indices and play around with the vertices coordinates like this:

static const GLfloat vertices[] = {
1.0f,  1.0f, 0.0f, 1.0f, 0.0f,
0.0f,  1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f, 0.5f,
1.0f, -1.0f, 0.0f, 1.0f, 0.5f,

0.0f,  1.0f, 0.0f, 1.0f, 0.5f,
-1.0f,  1.0f, 0.0f, 0.0f, 0.5f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.0f, -1.0f, 0.0f, 1.0f, 1.0f
};

static const GLushort indices[] = { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7 };

Upvotes: 0

Reto Koradi
Reto Koradi

Reputation: 54592

The transformation that you want here cannot be represented by a transformation matrix. Matrices can only represent certain classes of transformations. In 3D space:

  • A 3x3 matrix represents a linear transformation. Typical examples include rotation, scaling, mirroring, shearing.
  • A 4x3 matrix represents an affine transformation. On top of the above, this includes translations.
  • If you extend the 3D space to homogenous coordinates with 4 components, a 4x4 matrix can represent additional classes of transformations, like projections.

The transformation in your sketch is none of the above. So applying a matrix to your vertices will not be able to do this.

So what can you do? Two options come to mind:

  1. If you can easily draw the two parts (top/bottom, left/right) separately, you can obviously do that, and simply change the transformation between rendering the two parts.
  2. Apply the logic in your shader code.

For option 2, you could do this either in the vertex or fragment shader. If you have no primitives that cross the boundary between the two parts, handling it in the vertex shader would be more efficient. Otherwise, similar logic can be used in the fragment shader.

Sketching the critical parts for the vertex shader case, let's say you currently have the following that gives you the arrangement in the left side of your sketch:

// Calculate output position and store it in variable "pos".
gl_Position = pos;

To get the second arrangement, the logic could look like this (completely untested...):

if (pos.y > 0.0) {
    gl_Position = vec4(0.5 * pos.x - 0.5, 2.0 * pos.y - 1.0, pos.zw)
} else {
    gl_Position = vec4(0.5 * pos.x + 0.5, 2.0 * pos.y + 1.0, pos.zw);
}

The idea is that you check whether the vertex is in the top or bottom half, and scale/shift it accordingly to map the top half of the coordinate space into the left half, and the bottom half of the coordinate space into the right half.

This could be streamlined some more by replacing the conditional with a sign operation:

float s = sign(pos.y);
gl_Position = vec4(0.5 * pos.x - sign * 0.5, 2.0 * pos.y - sign, pos.zw);

Some more care will be needed if pos.w is not 1.0, which happens if you e.g. applied a perspective projection to your vertices. In that case, you'll have to incorporate the division by w in the calculations above.

Upvotes: 1

Related Questions