简体   繁体   English

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

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

So, my problem is basically adding texture to my triangle or square through an image in my project. 因此,我的问题基本上是通过项目中的图像向三角形或正方形添加纹理。 Although this seems like a basic question that I should be able to look up and execute, I am having a hard time processing all the necessary code needed to apply texture from the tutorials I have went through. 尽管这似乎是我应该能够查找和执行的基本问题,但是我在处理我所经历的教程中应用纹理所需的所有必要代码方面都遇到了困难。 I have copy and pasted code from a tutorial that did not compile because the creator of the tutorial left out code that was assumed to be already added. 我已经从未编译的教程中复制并粘贴了代码,因为该教程的创建者遗漏了假定已添加的代码。 I worked out all the syntax errors to the best of my ability, making sure to properly add in the correct code that the tutorial left out. 我尽力解决了所有语法错误,并确保正确添加了本教程遗漏的正确代码。 In the end, my app crashes from a logic error that I believe is in the texture code that I added. 最后,我的应用程序因逻辑错误而崩溃,我认为这是我添加的纹理代码中的错误。 I could be missing a few lines of code, or I could have misused a few lines of code. 我可能会丢失几行代码,或者我可能滥用了几行代码。 Really, what I'm asking for is a bare minimal complete code(not snippets) that includes a simple addition of texture to a simple open gl shape(like a square), so that I may copy and paste this code into a new project and save it as a future reference. 确实,我要的是一个最少的完整代码(不是片段),其中包括在简单的开放gl形状(如正方形)中简单添加纹理,以便我可以将此代码复制并粘贴到新项目中并保存为将来参考。 This would also help me identify my problem by comparing my code and the correct code. 通过比较我的代码和正确的代码,这也将帮助我确定问题所在。

But, I will post my code anyway in case it is easier for you to fix. 但是,无论如何我都会发布我的代码,以防您更容易修复。

SurfaceView Code: 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;
    } 
}

Renderer Code: 渲染器代码:

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

Triangle Code: 三角码:

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: The LogCat points to this line of code from the loadTexture method saying NullPointerException: PS:LogCat从loadTexture方法指向此代码行,并说NullPointerException:

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

I believe it has to do with the context but I'm not sure. 我认为这与上下文有关,但我不确定。

Primarily, you should add error checking to your code if it does not work as expected. 首先,如果代码无法按预期工作,则应在代码中添加错误检查。 Use glGetError() to check for general errors, glGetShaderiv() and glGetProgramiv() to check for success/error and logs after you compile and link shader programs. 在编译和链接着色器程序之后,使用glGetError()检查常规错误,使用glGetShaderiv()glGetProgramiv()检查成功/错误并记录日志。

Skimming through your code, here are a few things that jump out: 浏览代码,以下是一些要跳过的事情:

Your vertex shader would not compile. 您的顶点着色器无法编译。 Executable statements must be within functions, so v_TexCoordinate = a_TexCoordinate; 可执行语句必须在函数中,因此v_TexCoordinate = a_TexCoordinate; should be within the main() function: 应该在main()函数中:

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

The fragment shader has worse problems. 片段着色器存在更严重的问题。 Again, diffuse is assigned outside the main function. 同样, diffuse是在主要功能之外分配的。 It is also undeclared, and the value is used within an expression before it was assigned a value. 也未声明,并且在为其分配值之前在表达式中使用了该值。

In onSurfaceCreated() , when you assign this.context=context , I believe that both of these refer to the member variable, so that assignment does nothing, and context will still be null. onSurfaceCreated() ,当您分配this.context=context ,我相信这两个都引用了成员变量,因此分配不执行任何操作,并且context仍然为null。 If you need the context in the renderer, you will have to bass it from the view into the renderer before starting it. 如果需要渲染器中的上下文,则必须在启动之前将其从视图中放大到渲染器中。

In onDrawFrame() , you should clear the depth buffer as well as the color buffer. onDrawFrame() ,您应该清除深度缓冲区以及颜色缓冲区。 GLSurfaceView chooses a configuration with a depth buffer unless you request otherwise: 除非您另有要求,否则GLSurfaceView选择具有深度缓冲区的配置:

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

triangleTextureCoordinateData contains 3 components per vertex, while it should have only 2. triangleTextureCoordinateData每个顶点包含3个组件,而它应该只有2个。

You're calling glGetUniformLocation() instead of glGetAttribLocation() for v_TexCoordinate . 你打电话glGetUniformLocation()代替glGetAttribLocation()v_TexCoordinate That should actually be a_TexCoordinate anyway, since that's your attribute variable, while v_TexCoordinate is a varying variable. 无论如何,实际上这应该是a_TexCoordinate ,因为这是您的属性变量,而v_TexCoordinatevarying变量。

I'm going to post this since I already finished typing. 由于我已经完成输入,因此我将发布它。 But in hindsight, this is really not a good question for SO. 但是事后看来,这对于SO来说确实不是一个好问题。 In the future, please ask questions about specific problems, and don't just post code with countless issues. 将来,请提出有关特定问题的问题,不要仅仅发布包含无数问题的代码。

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

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