简体   繁体   English

OpenGL ES 2.0中的多维数据集不绘制给定的纹理

[英]Cube in OpenGL ES 2.0 does not draw the given textures

Normally I would not bother you with my questions, but this time I'm rather desperate. 通常,我不会打扰您,但这次我比较绝望。

First of all, I'm fairly new to OpenGL so please don't shoot me if I've made some rookie mistakes. 首先,我是OpenGL的新手,所以如果我犯了一些菜鸟错误,请不要射击我。 I've seen some examples already, but some of the example code is not understandable for me. 我已经看过一些示例,但是某些示例代码对我来说是无法理解的。

Secondly, I know this question is already been asked before on stack, but the answers that were given are no solutions for my case. 其次,我知道这个问题已经在堆栈上问过了,但是给出的答案并不是我的情况的解决方案。 They say one should resize the images so it becomes a power of 2, so I did, but no effect. 他们说应该调整图像的大小,使其变为2的幂,所以我做到了,但是没有效果。 They also say it could be the transparancy-element of a png, so I changed gl_FragColor in the fragmentShader (more than once), but no effect. 他们还说这可能是png的透明元素,所以我更改了fragmentShader中的gl_FragColor(不止一次),但没有效果。

Here below you can find the code I'm using to draw the cube and rotate it. 在下面,您可以找到我用来绘制立方体并旋转它的代码。 So everything works, beside the fact that it should show the textures as well but it doesn't . 因此,一切工作正常, 除了它还应显示纹理但不显示纹理 The one that could solve this problem for me is a god! 可以为我解决这个问题的人是上帝!

This is the activity that creates a surfaceview and sets the custom renderer 这是创建Surfaceview并设置自定义渲染器的活动

package --------------------;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class MyGLSurfaceView extends Activity {
    private GLSurfaceView mGLSurfaceView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGLSurfaceView = new GLSurfaceView(this);

        final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        final ConfigurationInfo configurationInfo =  activityManager.getDeviceConfigurationInfo();
        final boolean supportsEs2 = configurationInfo.reqGlEsVersion >=  0x20000;

        if (supportsEs2) {
            mGLSurfaceView.setEGLContextClientVersion(2);
            mGLSurfaceView.setRenderer(new MyOpenGLESRenderer(this));
        } else {
            return;
        }

        setContentView(mGLSurfaceView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGLSurfaceView.onPause();
    }
}

This is the renderer 这是渲染器

package ----------------------;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.DisplayMetrics;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MyOpenGLESRenderer implements GLSurfaceView.Renderer {
    private final Context context;

    private Cube cube;

    private float[] viewMatrix = new float[16];
    private float[] projectionMatrix = new float[16];

    private int programHandle;
    private int textureDataHandle1;
    private int textureDataHandle2;
    private int textureDataHandle3;
    private int textureDataHandle4;
    private int textureDataHandle5;
    private int textureDataHandle6;

    private int[] textureHandles = {
            textureDataHandle1,
            textureDataHandle2,
            textureDataHandle3,
            textureDataHandle4,
            textureDataHandle5,
            textureDataHandle6
    };

    int deviceWidth;
    int deviceHeight;

    public MyOpenGLESRenderer(final Context context) {
        this.context = context;

        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        deviceWidth = displayMetrics.widthPixels;
        deviceHeight = displayMetrics.heightPixels;
    }

    @Override
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
        GLES20.glClearColor(0.3f, 1.0f, 0.3f, 0.0f);
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        GLES20.glEnable(GLES20.GL_CULL_FACE);
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

        final float eyeX = 0.0f;
        final float eyeY = 0.0f;
        final float eyeZ = -0.5f;

        final float lookX = 0.0f;
        final float lookY = 0.0f;
        final float lookZ = -5.0f;

        final float upX = 0.0f;
        final float upY = 1.0f;
        final float upZ = 0.0f;

        Matrix.setLookAtM(viewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);

        final String vertexShader =
            "uniform mat4 u_MVPMatrix;      \n"        // A constant representing the combined model/view/projection matrix.

                    + "attribute vec4 a_Position;     \n"        // Per-vertex position information we will pass in.
                    + "attribute vec4 a_Color;        \n"        // Per-vertex color information we will pass in.
                    + "attribute vec2 a_TexCoordinate;\n"
                    + "varying vec2 v_TexCoordinate;  \n"
                    + "varying vec4 v_Color;          \n"        // This will be passed into the fragment shader.

                    + "void main()                    \n"        // The entry point for our vertex shader.
                    + "{                              \n"
                    + "   v_Color = a_Color;          \n"        // Pass the color through to the fragment shader.
                    + "v_TexCoordinate = a_TexCoordinate;\n"                                                                     // It will be interpolated across the triangle.
                    + "   gl_Position = u_MVPMatrix   \n"    // gl_Position is a special variable used to store the final position.
                    + "               * a_Position;   \n"     // Multiply the vertex by the matrix to get the final point in
                    + "}                              \n";    // normalized screen coordinates.

        final String fragmentShader =
            "precision mediump float;       \n"        // Set the default precision to medium. We don't need as high of a
                    // precision in the fragment shader.
                    + "varying vec4 v_Color;          \n"        // This is the color from the vertex shader interpolated across the
                    + "uniform sampler2D u_Texture;   \n"
                    + "varying vec2 v_TexCoordinate;   \n"// triangle per fragment.
                    + "void main()                    \n"        // The entry point for our fragment shader.
                    + "{                              \n"
                    + " gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate));     \n"        // Pass the color directly through the pipeline.
                    + "}                              \n";

        final int vertexShaderHandle = loadShader(vertexShader, GLES20.GL_VERTEX_SHADER);
        final int fragmentShaderHandle = loadShader(fragmentShader, GLES20.GL_FRAGMENT_SHADER);

        programHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
            new String[]{"a_Position", "a_Color", "a_TexCoordinate"});

    }

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

        final float ratio = (float) width / height;
        final float left = -ratio;
        final float right = ratio;
        final float bottom = -1.0f;
        final float top = 1.0f;
        final float near = 1.0f;
        final float far = 10.0f;

        Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far);
    }

    @Override
    public void onDrawFrame(GL10 glUnused) {
        cube = new Cube(deviceWidth, deviceHeight);
        cube.onDraw(programHandle, textureHandles, viewMatrix, projectionMatrix);
    }

    private int loadShader(final String shader, final int glShader) {
        int shaderHandle = GLES20.glCreateShader(glShader);

        if (shaderHandle != 0) {
            GLES20.glShaderSource(shaderHandle, shader);
            GLES20.glCompileShader(shaderHandle);

            final int[] compileStatus = new int[1];
            GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

            if (compileStatus[0] == 0) {
                GLES20.glDeleteShader(shaderHandle);
                shaderHandle = 0;
            }
        }
        if (shaderHandle == 0) {
            throw new RuntimeException("Error creating shader.");
        }
        return shaderHandle;
    }

    private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) {
        programHandle = GLES20.glCreateProgram();

        if (programHandle != 0) {
            GLES20.glAttachShader(programHandle, vertexShaderHandle);
            GLES20.glAttachShader(programHandle, fragmentShaderHandle);

            if (attributes != null) {
                final int size = attributes.length;
                for (int i = 0; i < size; i++) {
                    GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
                }
            }

            GLES20.glLinkProgram(programHandle);
            textureDataHandle1 = loadTexture(R.drawable.diceface1);
            textureDataHandle2 = loadTexture(R.drawable.diceface4);
            textureDataHandle3 = loadTexture(R.drawable.diceface6);
            textureDataHandle4 = loadTexture(R.drawable.diceface3);
            textureDataHandle5 = loadTexture(R.drawable.diceface5);
            textureDataHandle6 = loadTexture(R.drawable.diceface2);

            final int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);

            if (linkStatus[0] == 0) {
                GLES20.glDeleteProgram(programHandle);
                programHandle = 0;
            }
        }
        if (programHandle == 0) {
            throw new RuntimeException("Error creating program.");
        }
        return programHandle;
    }

    private int loadTexture(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

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

            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

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

            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

            bitmap.recycle();
        }

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

        return textureHandle[0];
     }
}

And this is the object that needs to be rendered: 这是需要渲染的对象:

package ---------------;

import android.opengl.GLES20;
import android.opengl.Matrix;
import android.os.SystemClock;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class Cube {

    private float X = 0, Y = 0;

    private final FloatBuffer cubeVertices;
    private final FloatBuffer cubeColors;
    private final FloatBuffer cubeTextureCoordinates;

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

    private float[] MVPMatrix = new float[16];

    private int MVPMatrixHandle;
    private int MVMatrixHandle;
    private int textureUniformHandle;
    private int positionHandle;
    private int colorHandle;
    private int textureCoordinateHandle;

    private final int positionDataSize = 3;
    private final int colorDataSize = 4;
    private final int textureCoordinateDataSize = 2;

    private final int bytesPerFloat = 4;

    private boolean upX = true;
    private boolean upY = true;
    private float counterX = 0.0f;
    private float counterY = 0.0f;

    private int deviceWidth;
    private int deviceHeight;

    private final float[] verticesData = {
            -0.6f, 0.6f, 0.6f,
            -0.6f, -0.6f, 0.6f,
            0.6f, 0.6f, 0.6f,
            -0.6f, -0.6f, 0.6f,
            0.6f, -0.6f, 0.6f,
            0.6f, 0.6f, 0.6f,

            0.6f, 0.6f, 0.6f,
            0.6f, -0.6f, 0.6f,
            0.6f, 0.6f, -0.6f,
            0.6f, -0.6f, 0.6f,
            0.6f, -0.6f, -0.6f,
            0.6f, 0.6f, -0.6f,

            0.6f, 0.6f, -0.6f,
            0.6f, -0.6f, -0.6f,
            -0.6f, 0.6f, -0.6f,
            0.6f, -0.6f, -0.6f,
            -0.6f, -0.6f, -0.6f,
            -0.6f, 0.6f, -0.6f,

            -0.6f, 0.6f, -0.6f,
            -0.6f, -0.6f, -0.6f,
            -0.6f, 0.6f, 0.6f,
            -0.6f, -0.6f, -0.6f,
            -0.6f, -0.6f, 0.6f,
            -0.6f, 0.6f, 0.6f,

            -0.6f, 0.6f, -0.6f,
            -0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, -0.6f,
            -0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, -0.6f,

            0.6f, -0.6f, -0.6f,
            0.6f, -0.6f, 0.6f,
            -0.6f, -0.6f, -0.6f,
            0.6f, -0.6f, 0.6f,
            -0.6f, -0.6f, 0.6f,
            -0.6f, -0.6f, -0.6f,
    };

    private final float[] cubeColorData = {
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f
    };

    private final float[] cubeTextureCoordinateData = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f
    };

    public Cube(int deviceWidth, int deviceHeight) {
        this.deviceWidth = deviceWidth;
        this.deviceHeight = deviceHeight;

        cubeVertices = ByteBuffer.allocateDirect(verticesData.length *     bytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
        cubeVertices.put(verticesData).position(0);

        cubeColors = ByteBuffer.allocateDirect(cubeColorData.length * bytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
        cubeColors.put(cubeColorData).position(0);

        cubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * bytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
        cubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);
    }

    public void onDraw(int programHandle, int[] textureDataHandles, float[] viewMatrix, float[] projectionMatrix) {
        this.viewMatrix = viewMatrix;
        this.projectionMatrix = projectionMatrix;

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

        long time = SystemClock.uptimeMillis() % 10000L;
        float angleInDegrees = (360.0f / 10000.0f) * ((int) time);

        GLES20.glUseProgram(programHandle);

        MVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
        MVMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVMatrix");
        textureUniformHandle = GLES20.glGetUniformLocation(programHandle, "u_Texture");
        positionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
        colorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
        textureCoordinateHandle = GLES20.glGetAttribLocation(programHandle, "a_TexCoordinate");

        Matrix.setIdentityM(modelMatrix, 0);

        //Matrix.translateM(modelMatrix, 0, 3.0f, 5.5f, -7.0f);

        //zie kladblok!!!!!!!!!!
        Matrix.translateM(modelMatrix, 0, X, Y, -7.0f);

        Matrix.rotateM(modelMatrix, 0, angleInDegrees, 1.0f, 0.0f, 0.0f);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[0]);
        GLES20.glUniform1i(textureUniformHandle, 0);
        drawCube(0);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[1]);
        GLES20.glUniform1i(textureUniformHandle, 1);
        drawCube(1);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[2]);
        GLES20.glUniform1i(textureUniformHandle, 2);
        drawCube(2);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[3]);
        GLES20.glUniform1i(textureUniformHandle, 3);
        drawCube(3);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[4]);
        GLES20.glUniform1i(textureUniformHandle, 4);
        drawCube(4);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[5]);
        GLES20.glUniform1i(textureUniformHandle, 5);
        drawCube(5);
    }

    private void drawCube(final int i) {
        cubeVertices.position(18 * i);
        GLES20.glVertexAttribPointer(positionHandle, positionDataSize, GLES20.GL_FLOAT, false,
            0, cubeVertices);
        GLES20.glEnableVertexAttribArray(positionHandle);

        cubeColors.position(24 * i);
        GLES20.glVertexAttribPointer(colorHandle, colorDataSize, GLES20.GL_FLOAT, false,
            0, cubeColors);
        GLES20.glEnableVertexAttribArray(colorHandle);

        cubeTextureCoordinates.position(12 * i);
        GLES20.glVertexAttribPointer(textureCoordinateHandle, textureCoordinateDataSize, GLES20.GL_FLOAT, false,
            0, cubeTextureCoordinates);
        GLES20.glEnableVertexAttribArray(textureCoordinateHandle);

        Matrix.multiplyMM(MVPMatrix, 0, viewMatrix, 0, modelMatrix, 0);
        GLES20.glUniformMatrix4fv(MVMatrixHandle, 1, false, MVPMatrix, 0);
        Matrix.multiplyMM(MVPMatrix, 0, projectionMatrix, 0, MVPMatrix, 0);
        GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, MVPMatrix, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
    }
}

I don't think I need to provide more files (like the manifest), but if you do need it please ask. 我认为我不需要提供更多文件(如清单),但是如果需要,请询问。

Remark : Working with a logger would be difficult because somehow I can't run the Trancer program from android. 备注 :使用记录器将很困难,因为我无法从android运行Trancer程序。

It also looks like you have some suspect variable setup for your texture handles. 看起来您的纹理手柄有一些可疑的变量设置。 You declare individual handles as integers, and then also declare an array of the 6 values. 您将各个句柄声明为整数,然后还声明6个值的数组。 The 6 values here are "int" basic types, not objects, so the array will take a copy of the values rather than a reference. 这里的6个值是“ int”基本类型,而不是对象,因此数组将获取值的副本而不是引用。 In one place later in the code you set via the non-array version, and bind via the array version, which won't work as you are really looking at two totally different variables. 在稍后的代码中,您可以通过非数组版本进行设置,然后通过数组版本进行绑定,这将无法正常工作,因为您实际上正在查看两个完全不同的变量。 I'd suggest deleting the version outside of the array, and just use the array as the only storage of the 6 texture handles. 我建议删除数组外部的版本,仅将数组用作6个纹理句柄的唯一存储。

More generally something looks "off" in your texture setup. 通常,纹理设置中有些东西看起来“不可用”。 You only have a single texture sampler set up in your shader, and you are trying to bind 6 different textures to it. 您的着色器中仅设置了一个纹理采样器,并且您试图将6种不同的纹理绑定到该采样器。 How does the shader know which texture to apply to which triangle? 着色器如何知道将哪个纹理应用于哪个三角形? It can't. 不可以 If you fix the issue above around how you manage the handles your current shader will simply show the last bound texture on all 6 faces. 如果您在管理手柄的方式上解决了上述问题,则当前的着色器将仅显示所有6个面上的最后绑定纹理。

If you want to show something like a die with 6 different images on each face of the cube then you will typically need to pack the texture data for all 6 faces into a single texture image, and then give each face's vertices a different texture coordinate so it maps the correct sub-region of the image. 如果要显示类似骰子的物体,在立方体的每个面上都具有6个不同的图像,则通常需要将所有6个面的纹理数据打包到单个纹理图像中,然后为每个面的顶点赋予不同的纹理坐标,以便它映射了图像的正确子区域。

HTH, Pete 皮特HTH

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

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