在带有着色器的opengl中围绕自身旋转矩形

时间:2014-10-25 14:29:30

标签: java android opengl-es rotation shader

我对opengl es很新。现在我正试图制作一个简单的场景,不同大小的矩形正在倒下并绕着自己的轴旋转。

(我想要的插图) enter image description here

我为它创建了矩形类,着色器助手,还创建了一个简单的顶点和片段着色器(只是通过vec4着色,没有什么特别的,我不会发布代码)。

嗯,所有这些东西都是这样的:

矩形对象

 public class RectObject{
    private static final int POSITION_COMPONENT_COUNT = 2;
    private static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2;
    private static final int STRIDE = (POSITION_COMPONENT_COUNT 
        + TEXTURE_COORDINATES_COMPONENT_COUNT) * BYTES_PER_FLOAT;

    private final VertexArray vertexArray;

    public RectObject(float x, float y, float size){
        float[] newCoordinates = {
                x, y, 0.5f, 0.5f, 
                (x-size), (y-size),0f, 1.0f,  
                (x+size), (y-size),1f, 1.0f, 
                (size + x), (size + y),1f, 0.1f, 
                (x-size), (size + y),0f, 0.1f, 
                (x-size), (y-size), - 0f, 1.0f 
        };

        vertexArray = new VertexArray(newCoordinates);
    }

    public void bindData(RectShaderProgram textureProgram) {

        vertexArray.setVertexAttribPointer(
            0, 
            textureProgram.getPositionAttributeLocation(), 
            POSITION_COMPONENT_COUNT,
            STRIDE);
    }

    public void draw(RectShaderProgram shader, float velocity) { 
        glUniform4f(shader.getMoveLocation(), 0.0f, velocity, 0.0f, 0.0f);
        glUniform1f(shader.getTimerLocation(),  (float)(System.nanoTime()/10000000000.0f));
        glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
    }

}

顶点着色器:

attribute vec4 a_Position;
uniform vec4 u_Move;
uniform mat4 u_Matrix;
uniform float timer;

void main()
{
    mat4 rotation = mat4(
     cos(timer), -sin(timer), 0.0, 0.0,
     sin( timer), cos(timer), 0.0, 0.0,
     0.0,  0.0, 1.0, 0.0,
     0.0,  0.0, 0.0, 1.0 );

    gl_Position = u_Matrix * rotation* ((a_Position /*+ u_Move*/)) ;  
}

着色器助手

public class RectShaderProgram extends ShaderProgram{

private final int uMatrixLocation;
private final int uMoveLocation;
private final int TimerLocation;
// Attribute locations
private final int aPositionLocation;

public RectShaderProgram(Context context ) {
    super(context, R.raw.rect_vertex_shader,
            R.raw.rect_fragment_shader);
    // TODO Auto-generated constructor stub
       // Retrieve uniform locations for the shader program.

    // Retrieve attribute locations for the shader program.
    aPositionLocation = glGetAttribLocation(program, A_POSITION);
    uMatrixLocation = glGetUniformLocation(program, U_MATRIX);
    uMoveLocation= glGetUniformLocation(program, U_MOVE);
    TimerLocation = glGetUniformLocation(program, TIMER);
}

public void setUniforms(float[] matrix) {
    glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);

}

public int getPositionAttributeLocation() {
    return aPositionLocation;
}
public int getMoveLocation() {
    return uMoveLocation;
}
public int getTimerLocation() {
    return TimerLocation;
}


}

但问题是整个场景都在旋转!

我得到了什么 enter image description here

那么,如何正确地做到这一点? 这是渲染器类

 public class ProjectRenderer implements Renderer{

    private final float[] projectionMatrix = new float[16];
    private final float[] modelMatrix = new float[16];

    private int uMatrixLocation;

    private Background wall;
    //private RectObject myobject, myobject2;
    private TextureShaderProgram textureProgram;
    private ColorShaderProgram colorProgram;  
    private RectShaderProgram rectProgram;  
    private int texture;
    private float velocity, time;
    private ArrayList<RectObject> rlist = new ArrayList<RectObject>();

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // TODO Auto-generated method stub
        glClearColor(0.0f,0.0f,0.0f,0.0f);
        velocity = 0.1f;
        wall = new Background();
        //myobject = new RectObject(0.1f,0.1f, 0.1f);
        //myobject2 = new RectObject(0.2f,0.4f, 0.1f);
         Random rand = new Random();
        for (int i = 0; i < 15; i++){
            rlist.add(new RectObject( (float)0.2*rand.nextInt(15)-1, (float)0.2*rand.nextInt(15)-1, (float)0.1*rand.nextInt(3)));
        }


           textureProgram = new TextureShaderProgram(context);
           colorProgram = new ColorShaderProgram(context);        
           rectProgram = new RectShaderProgram(context);
           texture = TextureHelper.loadTexture(context, R.drawable.sas);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // TODO Auto-generated method stub
        glViewport(0, 0, width, height);
        // Construct the projection matrix
        MatrixHelper.perspectiveM(projectionMatrix,45,(float)width
                /(float)height,1f,10f);
        // Make the modelMatrix identity matrix
        setIdentityM(modelMatrix,0);
        // Add offset of 2.5 in direction of z axle
        translateM(modelMatrix,0,0f,0f,-2.0f);
        // Rotation by 60 degrees in direction of x axle
        //rotateM(modelMatrix,0,-60f,1f,0f,0f);
        // Projection matrix * model matrix 
        final float[] temp=new float[16];
        multiplyMM(temp,0,projectionMatrix,0,modelMatrix,0);
        System.arraycopy(temp,0,projectionMatrix,0,temp.length);


    }

    @Override
    public void onDrawFrame(GL10 gl) {
        // TODO Auto-generated method stub
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         // Draw the table.
        textureProgram.useProgram();
        textureProgram.setUniforms(projectionMatrix, texture);
        wall.bindData(textureProgram);
        wall.draw();

        velocity = velocity - 0.005f;

        rectProgram.useProgram();
        rectProgram.setUniforms(projectionMatrix);
        for(Iterator<RectObject> i = rlist.iterator(); i.hasNext(); ) {
            RectObject item = i.next();
            item.bindData(rectProgram);
            item.draw(rectProgram, velocity);

        }
    }

    public ProjectRenderer(Context context){
        this.context = context;

    }

1 个答案:

答案 0 :(得分:2)

案例在于您将矩形的坐标存储在世界坐标中。换句话说,您将平移变换应用于顶点并将它们存储为变换。因此,如果具有一个全局原点的单个帧,则表示所有矩形。

旋转矩阵以围绕原点旋转此点的方式变换给定点的坐标。要在空间中围绕任意轴旋转点,需要更复杂的数学运算。因此,通常每个对象用适当的局部帧表示,这允许相对于对象的本地原点执行一些变换(即旋转,缩放)。此本地原点(有时称为轴点)通常位于对象的中心。

任何运动都可以表示为两种不同类型运动的组合:平移运动和旋转运动。任意运动都有无限的分解方式,因此选择最方便的运动是合理的。应该选择局部(固定到对象)框架,考虑到它在全局框架中的原点(枢轴点)位置不会受到旋转变换的影响。

因此,总结以上所有内容,您应该重写 RectObject 的构造函数,如下所示:

public RectObject(float x, float y, float size){
    float[] newCoordinates = {
            0, 0, 0.5f, 0.5f, 
            -size, -size, 0f, 1.0f,  
            size, -size, 1f, 1.0f, 
            size, size, 1f, 0.1f, 
            -size, size, 0f, 0.1f, 
            -size, -size, - 0f, 1.0f 
    };

    vertexArray = new VertexArray(newCoordinates);
}

原点位于矩形的中心(准确地说是方形)。

此外,我建议您不要直接将大小应用于矩形的顶点,而是将其作为均匀参数传递到顶点着色器并应用为缩放变换。因此,您可以为所有矩形使用相同的顶点数组。对于这种情况,顶点的坐标应该构造为单位尺寸矩形。

如何将变换传递给顶点着色器?通常由转换矩阵完成,该转换矩阵作为统一参数传递。该变换矩阵通常是所有中间变换(例如平移,旋转和缩放)的乘法的结果。因此,您的顶点着色器应更改如下:

attribute vec2 a_Position;
uniform mat4 u_Matrix;

void main()
{
    gl_Position = u_Matrix * vec4(a_Position, vec2(0.0, 1.0));  
}

请注意,您已将 a_Position 属性定义为两个组件向量,因此必须将其用作双组件向量。在上面的着色器中,使用 a_Position 属性构造了一个四分量向量。

另请注意,如果您要使用紫外线坐标,则需要将它们添加到顶点着色器中。

由于投影,平移和旋转矩阵的相乘,您需要计算 u_Matrix 矩阵。构造这些矩阵取决于您使用的数学库。请阅读thisthisthis,了解如何执行此操作。

一般而言,对于您的情况,转换矩阵可以按如下方式计算:

                                           Translation         Rotation
|                |     |            |     | 1  0  0  0 |     | cos(alpha)  -sin(alpha)  0  0 |
| Transformation |  =  | Projection |  X  | 0  1  0  0 |  X  | sin(alpha)   cos(alpha)  0  0 |
| matrix         |     | matrix     |     | 0  0  1  0 |     | 0            0           1  0 |
|                |     |            |     | x  y  0  1 |     | 0            0           0  1 |

其中:

  • x y - 矩形的位置
  • alpha - 旋转角度