Android OpenGL圆圈(球体)看起来像椭圆..没有投影/相机

时间:2016-08-01 16:33:50

标签: android opengl-es geometry ellipse

enter image description here

  

还附加了来自设备的屏幕截图,   你可以帮我解决这个问题吗?   其Android KitKat版本

public class Balloon
{
    private final String vertexShaderCode =
            // This matrix member variable provides a hook to manipulate
            // the coordinates of the objects that use this vertex shader
                    "attribute vec4 vPosition;" +
                    "void main() {" +
                    "gl_PointSize = 5.0;                  "+
                    "  gl_Position =  vPosition;" +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    private FloatBuffer vertexBuffer;
    private final int mProgram;
    private int mPositionHandle;
    private int mColorHandle;
    private int mMVPMatrixHandle;

    private float[] data = new float[126];

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;

    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

    float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };

    /**
     * Sets up the drawing object data for use in an OpenGL ES context.
     */
    public Balloon() {

        // prepare shaders and OpenGL program
        int vertexShader = MyGLRenderer.loadShader(
                GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = MyGLRenderer.loadShader(
                GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        mProgram = GLES20.glCreateProgram();             
        // create empty OpenGL Program
        GLES20.glAttachShader(mProgram, vertexShader);   
        // add the vertex shader to program
        GLES20.glAttachShader(mProgram, fragmentShader); 
        // add the fragment shader to program
        GLES20.glLinkProgram(mProgram);                  
       // create OpenGL program executables

    }

    private void FillBalloon(float x1,float y1,float r1)
    {
        int i=0,j=0;
        float angle = 0;

        float twicePI = (float)2.0 * (float)3.1415926;


        float angle_stepsize = 0.1f;

        // go through all angles from 0 to 2 * PI radians
        for(;angle < twicePI;angle = (angle + angle_stepsize))
        {
            // calculate x, y from a vector with known length and angle
            data[j++] = x1 + r1 * (float)Math.cos(angle);
            data[j++] = y1 + r1 * (float)Math.sin(angle);

        }

        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (number of coordinate values * 4 bytes per float)
                j * 4);
        // use the device hardware's native byte order
        bb.order(ByteOrder.nativeOrder());

        // create a floating point buffer from the ByteBuffer
        vertexBuffer = bb.asFloatBuffer();
        // add the coordinates to the FloatBuffer
        vertexBuffer.put(data);
        // set the buffer to read the first coordinate
        vertexBuffer.position(0);

    }


    /**
     * Encapsulates the OpenGL ES instructions for drawing this shape.
     *
     */
    public void draw() {
        // Add program to OpenGL environment
        GLES20.glUseProgram(mProgram);

        float posX = 0.0f,posY = 0.0f,radius =0.2f;

        FillBalloon(posX, posY, radius);

        // get handle to vertex shader's vPosition member
        mPositionHandle = 
                GLES20.glGetAttribLocation(mProgram,"vPosition");

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // Prepare the balloon coordinate data

        GLES20.glVertexAttribPointer(mPositionHandle, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer);

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

        // Set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        MyGLRenderer.checkGlError("mColorHandle");


        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 63);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}

还附有设备屏幕截图, 你可以帮我解决这个问题吗? 它的Android KitKat版本

2 个答案:

答案 0 :(得分:1)

这是预期的行为。每个轴的openGL默认坐标系为[-1,1]。这意味着最左边的点将包含x=-1,最右边x=1,最顶层y=1和最底层y=-1。现在,根据您的屏幕比例,结果将具有相同的拉伸比率。

您可以随意处理场景以绘制形状。一种方法是在生成顶点数据时对其进行缩放,但我强烈建议您不要这样做,因为模型顶点数据应该按照它们的意图。另一种方法是简单地创建一个方形表面视图,然后限制您的绘图表面,因此它不是最好的方法。另一种方法是使用视口并设置一个矩形,您可以在其中绘制您的形状,其中可能没问题,但您需要记住将其设置回全宽和高度。然后有矩阵......

使用矩阵定义坐标系。对于2D,最好的方法通常是使用Ortho,它使用边界参数(左,上,下,右),然后可以设置为你想要的任何东西。例如,您可以使用视图坐标(left = 0right = viewWidthtop = 0bottom = viewHeight),或者您可以将系统标准化为零,并选择哪个边框的值应为{ {1}}:对于水平规范化,您将拥有(1.0left = -1right = 1top = viewHeight/viewWidth)和垂直(bottom = -viewHeight/viewWidth,{{1} },left = -viewWidth/viewHeightright = viewWidth/viewHeight)。

答案 1 :(得分:0)

要使气球看起来像圆圈,请添加一个浮点(我们称之为X_SCALE)作为绘制参数:

public void draw(float X_SCALE) {
   ...
   FillBaloon(posX, posY, radius, X_SCALE);
   ...
}

然后将您的绘制时间x坐标乘以FillBaloon(...)中的比例因子:

data[j++] = x1 + X_SCALE * r1 * (float)Math.cos(angle);

并在渲染器绘制(X_SCALE)调用中设置比例因子:

X_SCALE = (float)MyGLSurfaceView.getHeight()/(float)MyGLSurfaceView.getWidth();
myBaloon.draw(X_SCALE);

更好的方法是在onSurfaceCreated(...)中设置一次X_SCALE,并且每次在onSurfaceChanged(...)中调整表面大小。

最后一件事:你可以通过在显式初始化中使用“f”后缀来避免将双精度转换为浮点数:

float twicePI = 6.28318530717959f;