繁体   English   中英

如何正确地将纹理添加到我的openGL形状中?

[英]How Do I Add Texture to my openGL Shapes Properly?

因此,我的问题基本上是通过项目中的图像向三角形或正方形添加纹理。 尽管这似乎是我应该能够查找和执行的基本问题,但是我在处理我所经历的教程中应用纹理所需的所有必要代码方面都遇到了困难。 我已经从未编译的教程中复制并粘贴了代码,因为该教程的创建者遗漏了假定已添加的代码。 我尽力解决了所有语法错误,并确保正确添加了本教程遗漏的正确代码。 最后,我的应用程序因逻辑错误而崩溃,我认为这是我添加的纹理代码中的错误。 我可能会丢失几行代码,或者我可能滥用了几行代码。 确实,我要的是一个最少的完整代码(不是片段),其中包括在简单的开放gl形状(如正方形)中简单添加纹理,以便我可以将此代码复制并粘贴到新项目中并保存为将来参考。 通过比较我的代码和正确的代码,这也将帮助我确定问题所在。

但是,无论如何我都会发布我的代码,以防您更容易修复。

SurfaceView代码:

int mProgram;

 private final String vertexShaderCode =
            "attribute vec4 vPosition;" +"uniform mat4 uMVPMatrix;"+
            "attribute vec2 a_TexCoordinate;"+"varying vec2 v_TexCoordinate;"+
            "v_TexCoordinate = a_TexCoordinate;"+
            "void main() {" +
            "  gl_Position =uMVPMatrix*vPosition;" +
            "}";

        private final String fragmentShaderCode =
            "precision mediump float;" +
            "uniform vec4 vColor;" +"uniform sampler2D u_Texture;"+
            "varying vec2 v_TexCoordinate;"+"diffuse = diffuse + 0.3;"+
            "void main() {" +
            "gl_FragColor = (v_Color * diffuse * texture2D(u_Texture, v_TexCoordinate));" +
            "}";

class MyGLSurfaceView extends GLSurfaceView {

    private MyGLRenderer myRend;

    public MyGLSurfaceView(Context context){
        super(context);

        myRend=new MyGLRenderer();
        setEGLContextClientVersion(2);
        setRenderer(myRend);
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }

    float mPreviousX;
    float mPreviousY;
    private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        // MotionEvent reports input details from the touch screen
        // and other input controls. In this case, you are only
        // interested in events where the touch position changed.

        float x = e.getX();
        float y = e.getY();

        switch (e.getAction()) {
            case MotionEvent.ACTION_MOVE:

                float dx = x - mPreviousX;
                float dy = y - mPreviousY;

                // reverse direction of rotation above the mid-line
                if (y > getHeight() / 2) {
                  dx = dx * 1 ;
                }

                // reverse direction of rotation to left of the mid-line
                if (x < getWidth() / 2) {
                  dy = dy * 1 ;
                }

                myRend.mAngle += (dx + dy) * TOUCH_SCALE_FACTOR;
                requestRender();
        }

        mPreviousX = x;
        mPreviousY = y;
        return true;
    } 
}

渲染器代码:

Triangle mTriangle;
cube mCube;
float [] mViewMatrix=new float[16];
float [] mMVPMatrix=new float[16];
float [] mProjectionMatrix=new float[16];
private float[] mRotationMatrix=new float[16];
int mTextureDataHandle;


public class MyGLRenderer implements GLSurfaceView.Renderer {

    public volatile float mAngle;
    Context context;

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        this.context=context;

        // Load the texture
        int mTextureDataHandle =loadTexture(context, R.drawable.ic_launcher);


        mTriangle = new Triangle();

        mCube=new cube();

    }

    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        int mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
        int mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");

        // Set the active texture unit to texture unit 0.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

        // Bind the texture to this unit.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);

        // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
        GLES20.glUniform1i(mTextureUniformHandle, 0);

        float[] scratch = new float[16];
        //long time = SystemClock.uptimeMillis() % 4000L;
        //float mAngle = 0.090f * ((int) time);

        Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);

        Matrix.setLookAtM(mViewMatrix, 0, 5, 0, -5, -1f, 0f, 0f, 0f, 1.0f, 0.0f);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
        Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
      //mCube.draw(scratch);


        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
        mTriangle.draw(mMVPMatrix);

    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        float ratio = (float) width / height;
        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 2, 10);
    }
}

public int loadTexture(final Context context, final int resourceId)
{
    final int[] textureHandle = new int[1];

    GLES20.glGenTextures(1, textureHandle, 0);

    if (textureHandle[0] != 0)
    {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;   // No pre-scaling

        // Read in the resource
        final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

        // Bind to the texture in OpenGL
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

        // Set filtering
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

        // Load the bitmap into the bound texture.
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        // Recycle the bitmap, since its data has been loaded into OpenGL.
        bitmap.recycle();
    }

    if (textureHandle[0] == 0)
    {
        throw new RuntimeException("Error loading texture.");
    }

    return textureHandle[0];
}

三角码:

public class Triangle {


    /** This will be used to pass in the texture. */
    private int mTextureUniformHandle;

    /** This will be used to pass in model texture coordinate information. */
    private int mTextureCoordinateHandle;

    /** Size of the texture coordinate data in elements. */
    private final int mTextureCoordinateDataSize = 2;

    /** This is a handle to our texture data. */
    private int mTextureDataHandle;

    private FloatBuffer vertexBuffer, colorBuff, textureBuff;
    static final int COORDS_PER_VERTEX = 3;
    float triangleCoords[] = {   // in counterclockwise order:
            0.0f,  0.622008459f, 0.0f, // top
            -0.5f, -0.311004243f, 0.0f, // bottom left
             0.5f, -0.311004243f, 0.0f  // bottom right
    };


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


    public Triangle() {

        final float[] triangleTextureCoordinateData ={
                0.0f,  -0.622008459f, 0.0f, // top
                -0.5f, 0.311004243f, 0.0f, // bottom left
                 0.5f, 0.311004243f, 0.0f  // bottom right
        };

        ByteBuffer bb = ByteBuffer.allocateDirect(
                triangleCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(triangleCoords);
        vertexBuffer.position(0);

        ByteBuffer tb = ByteBuffer.allocateDirect(
                triangleTextureCoordinateData.length * 4);
        tb.order(ByteOrder.nativeOrder());
        textureBuff = tb.asFloatBuffer();
        textureBuff.put(triangleTextureCoordinateData);
        textureBuff.position(0);


        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

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


        public int loadShader(int type, String shaderCode){

            // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
            // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
            int shader = GLES20.glCreateShader(type);

            // add the source code to the shader and compile it
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);

            return shader;
        }

        static final int vertexStride = COORDS_PER_VERTEX * 4;
        static final int vertexCount = 3;

        public void draw(float [] mvpMatrix) {
            GLES20.glUseProgram(mProgram);
            int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            GLES20.glEnableVertexAttribArray(mPositionHandle);
            GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                                         GLES20.GL_FLOAT, false,
                                         vertexStride, vertexBuffer);
            int mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
            GLES20.glUniform4fv(mColorHandle, 1, color, 0);
           int mTriangleTextureCoordinates=GLES20.glGetUniformLocation(mProgram, "v_TexCoordinate");
            GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 
                                        0, mTriangleTextureCoordinates);
            int mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
            GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
            GLES20.glDisableVertexAttribArray(mPositionHandle);
        }


}

PS:LogCat从loadTexture方法指向此代码行,并说NullPointerException:

  final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

我认为这与上下文有关,但我不确定。

首先,如果代码无法按预期工作,则应在代码中添加错误检查。 在编译和链接着色器程序之后,使用glGetError()检查常规错误,使用glGetShaderiv()glGetProgramiv()检查成功/错误并记录日志。

浏览代码,以下是一些要跳过的事情:

您的顶点着色器无法编译。 可执行语句必须在函数中,因此v_TexCoordinate = a_TexCoordinate; 应该在main()函数中:

void main() {
    v_TexCoordinate = a_TexCoordinate;
    gl_Position = uMVPMatrix*vPosition;
}

片段着色器存在更严重的问题。 同样, diffuse是在主要功能之外分配的。 也未声明,并且在为其分配值之前在表达式中使用了该值。

onSurfaceCreated() ,当您分配this.context=context ,我相信这两个都引用了成员变量,因此分配不执行任何操作,并且context仍然为null。 如果需要渲染器中的上下文,则必须在启动之前将其从视图中放大到渲染器中。

onDrawFrame() ,您应该清除深度缓冲区以及颜色缓冲区。 除非您另有要求,否则GLSurfaceView选择具有深度缓冲区的配置:

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

triangleTextureCoordinateData每个顶点包含3个组件,而它应该只有2个。

你打电话glGetUniformLocation()代替glGetAttribLocation()v_TexCoordinate 无论如何,实际上这应该是a_TexCoordinate ,因为这是您的属性变量,而v_TexCoordinatevarying变量。

由于我已经完成输入,因此我将发布它。 但是事后看来,这对于SO来说确实不是一个好问题。 将来,请提出有关特定问题的问题,不要仅仅发布包含无数问题的代码。

暂无
暂无

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

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