简体   繁体   English

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

[英]Rotation rectangle around itself in opengl es with shaders

I'm pretty new to opengl es. 我是opengl es的新手。 Right now I'm trying to make a simple scene, where rectangles of different sizes are just falling down and rotating around theirs own axis. 现在,我正在尝试制作一个简单的场景,其中大小不同的矩形刚刚落下并围绕其自身的轴旋转。

(illustration of what I want) (我想要的插图) 在此处输入图片说明

I created rectangle class, shader helper for it and also created a simple vertex and fragment shaders(just coloring through the vec4, nothing special I won't post the code). 我为其创建了矩形类,着色器助手,还创建了一个简单的顶点和片段着色器(仅通过vec4进行着色,没什么特别的,我不会发布代码)。

Well, all this stuff looks like this: 好吧,所有这些东西看起来像这样:

rectangle object 矩形对象

 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);
    }

}

vertex shader: 顶点着色器:

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*/)) ;  
}

shader helper 着色器助手

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;
}


}

but the problem is that whole scene rotates around! 但问题是整个场景旋转!

what I've got 我有什么 在此处输入图片说明

So, how to make it in right way? 那么,如何以正确的方式做到这一点? Here's renderer class 这是渲染器类

 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;

    }

The case is in that you store coordinates of the rectangles in world coordinates. 这种情况是您将矩形的坐标存储在世界坐标中。 In other words you apply translation transformation to the vertices and store them transformed. 换句话说,您将平移变换应用于顶点并存储它们。 So all rectangles are represented if a single frame with one global origin. 因此,如果单个框架具有一个全局原点,则表示所有矩形。

The rotation matrix transforms the coordinates of a give point in way that rotates this point around the origin. 旋转矩阵以使点围绕原点旋转的方式转换给定点的坐标。 To rotate a point around an arbitrary axle in space some more complicated math is required. 为了绕空间中的任意轴旋转点,需要一些更复杂的数学运算。 Thus, usually each object is represented with appropriate local frame, that allows to perform some transformation (ie rotation, scale) with respect to the local origin of the object. 因此,通常每个对象都用适当的局部框架表示,该局部框架允许相对于该对象的局部原点执行某种变换(即旋转,缩放)。 This local origin, that sometimes is referred to as pivot point usually is placed in the center of the object. 该局部原点(有时称为枢轴点)通常位于对象的中心。

Any motion can be represented as combination of two distinct types of motion: translational motion and rotational motion. 任何运动都可以表示为两种不同类型的运动的组合:平移运动和旋转运动。 There are infinite ways of decomposition of an arbitrary motion, thus it is reasonable to select the most convenient one. 分解任意运动的方法有无数种,因此选择最方便的运动是合理的。 The local (fixed to the object) frame should be select considering the fact, that it's origin(pivot point) position in global frame would not be effected by rotational transform. 应该考虑以下事实来选择局部(固定在对象上)框架:其在全局框架中的原点(枢轴点)位置不会受到旋转变换的影响。

So, summarizing all above, you should rewrite your RectObject 's constructor as follows: 因此,总结以上所有内容,您应该按如下所示重写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);
}

The origin would be in the center of the rectangle(square to be precise). 原点将在矩形的中心(准确地说是正方形)。

Moreover, I'd recommend you not to apply the size to the vertices of rectangle directly, but pass it as a uniform parameter into the vertex shader and apply as scale transformation. 此外,我建议您不要将大小直接应用于矩形的顶点,而应将其作为统一参数传递到顶点着色器中,并作为比例转换应用。 Thus you would be able to use the same array of vertices for all your rectangles. 因此,您将能够对所有矩形使用相同的顶点数组。 The coordinates of the vertices should be constructed as for the unit size rectangle for this case. 在这种情况下,应按照单位尺寸矩形构造顶点的坐标。

How to pass the transformation to the vertex shader? 如何将转换传递到顶点着色器? Usually it is done by the transformation matrix that is passed as a uniform parameter. 通常,它是通过作为统一参数传递的转换矩阵来完成的。 This transformation matrix usually are the result of multiplications of all intermediate transformations such as translations, rotations and scales. 此转换矩阵通常是所有中间转换(例如平移,旋转和缩放)相乘的结果。 So, your vertex shader should be changed as follows: 因此,您的顶点着色器应如下更改:

attribute vec2 a_Position;
uniform mat4 u_Matrix;

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

Note that you have defined the a_Position attribute as two component vector, so you must use it as a two component vector. 请注意,您已将a_Position属性定义为两个分量向量,因此必须将其用作两个分量向量。 In a shader above, a four component vector is constructed using the a_Position attribute. 在上面的着色器中,使用a_Position属性构造了四个分量的向量。

Also note that if you are going to use uv coordinates you need to add them into your vertex shader. 还要注意,如果要使用uv坐标,则需要将其添加到顶点着色器中。

You need to calculate the u_Matrix matrix as a result of multiplication of your projection, translation and rotation matrices. 由于投影,平移和旋转矩阵的相乘结果,您需要计算u_Matrix矩阵。 Constructing of these matrices depends on the math library you are using. 这些矩阵的构造取决于您使用的数学库。 Read this , this and this for a general idea how to do this. 阅读thisthisthis,以获得有关如何执行此操作的一般想法。

In general terms, for your case the transformation matrix can be calculated as follows: 一般而言,对于您的情况,可以如下计算转换矩阵:

                                           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 |

Where: 哪里:

  • x , y - position of rectangle xy-矩形的位置
  • alpha - angle of rotation alpha-旋转角度

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM