【问题标题】:How to render SkyBox correctly?如何正确渲染 SkyBox?
【发布时间】:2016-05-27 03:34:10
【问题描述】:

我使用此问题的解决方案使用 6 个图像绘制了 3D SKybox 视图。问题可在此处找到。 LibGDX 0.9.9 - Apply cubemap in environment。该程序有效,但它似乎使用了大量的处理能力,我的 cpu 风扇开始运行。我渲染 3D 天空盒的方式是否有问题,或者有更好的方法吗?我实施天空盒的方式是否正确。这是我的代码。

创建环境的类如下

protected final Pixmap[] data = new Pixmap[6];  
protected ShaderProgram shader;

protected int u_worldTrans;
protected Mesh quad;
private Matrix4 worldTrans;
private Quaternion q;

protected String vertexShader = " attribute vec3 a_position; \n"+
        " attribute vec3 a_normal; \n"+
        " attribute vec2 a_texCoord0; \n"+          
        " uniform mat4 u_worldTrans; \n"+                   
        " varying vec2 v_texCoord0; \n"+
        " varying vec3 v_cubeMapUV; \n"+            
        " void main() { \n"+
        "     v_texCoord0 = a_texCoord0;     \n"+
        "     vec4 g_position = u_worldTrans * vec4(a_position, 1.0); \n"+
        "     v_cubeMapUV = normalize(g_position.xyz); \n"+
        "     gl_Position = vec4(a_position, 1.0); \n"+
        " } \n";

protected String fragmentShader = "#ifdef GL_ES \n"+
        " precision mediump float; \n"+
        " #endif \n"+           
        " uniform samplerCube u_environmentCubemap; \n"+            
        " varying vec2 v_texCoord0; \n"+
        " varying vec3 v_cubeMapUV; \n"+            
        " void main() {      \n"+
        "   gl_FragColor = vec4(textureCube(u_environmentCubemap, v_cubeMapUV).rgb, 1.0);   \n"+
        " } \n";

public String getDefaultVertexShader(){
    return vertexShader;
}

public String getDefaultFragmentShader(){
    return fragmentShader;
}

public EnvironmentCubemap (Pixmap positiveX, Pixmap negativeX, Pixmap positiveY, Pixmap negativeY, Pixmap positiveZ, Pixmap negativeZ) {
    data[0]=positiveX;
    data[1]=negativeX;

    data[2]=positiveY;
    data[3]=negativeY;

    data[4]=positiveZ;
    data[5]=negativeZ;

    init();   
}

public EnvironmentCubemap (FileHandle positiveX, FileHandle negativeX, FileHandle positiveY, FileHandle negativeY, FileHandle positiveZ, FileHandle negativeZ) {
    this(new Pixmap(positiveX), new Pixmap(negativeX), new Pixmap(positiveY), new Pixmap(negativeY), new Pixmap(positiveZ), new Pixmap(negativeZ));
}

//IF ALL SIX SIDES ARE REPRESENTED IN ONE IMAGE
public EnvironmentCubemap (Pixmap cubemap) {        
    int w = cubemap.getWidth();
    int h = cubemap.getHeight();
    for(int i=0; i<6; i++) data[i] = new Pixmap(w/4, h/3, Format.RGB888);
    for(int x=0; x<w; x++)
        for(int y=0; y<h; y++){
            //-X
            if(x>=0 && x<=w/4 && y>=h/3 && y<=h*2/3) data[1].drawPixel(x, y-h/3, cubemap.getPixel(x, y));
            //+Y
            if(x>=w/4 && x<=w/2 && y>=0 && y<=h/3) data[2].drawPixel(x-w/4, y, cubemap.getPixel(x, y));
            //+Z
            if(x>=w/4 && x<=w/2 && y>=h/3 && y<=h*2/3) data[4].drawPixel(x-w/4, y-h/3, cubemap.getPixel(x, y));
            //-Y
            if(x>=w/4 && x<=w/2 && y>=h*2/3 && y<=h) data[3].drawPixel(x-w/4, y-h*2/3, cubemap.getPixel(x, y));
            //+X
            if(x>=w/2 && x<=w*3/4 && y>=h/3 && y<=h*2/3) data[0].drawPixel(x-w/2, y-h/3, cubemap.getPixel(x, y));
            //-Z
            if(x>=w*3/4 && x<=w && y>=h/3 && y<=h*2/3) data[5].drawPixel(x-w*3/4, y-h/3, cubemap.getPixel(x, y));
        }
    cubemap.dispose();
    cubemap=null;
    init();     
}

private void init(){        
     shader = new ShaderProgram(vertexShader, fragmentShader);
        if (!shader.isCompiled())
            throw new GdxRuntimeException(shader.getLog());

     u_worldTrans = shader.getUniformLocation("u_worldTrans");

     quad = createQuad();      
     worldTrans = new Matrix4();         
     q = new Quaternion();

     initCubemap();
} 

private void initCubemap(){
    //bind cubemap
    Gdx.gl.glBindTexture(GL.GL_TEXTURE_CUBE_MAP, 0);
    Gdx.gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL30.GL_RGB, data[0].getWidth(), data[0].getHeight(), 0, GL30.GL_RGB, GL30.GL_UNSIGNED_BYTE, data[0].getPixels());
    Gdx.gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL30.GL_RGB, data[1].getWidth(), data[1].getHeight(), 0, GL30.GL_RGB, GL30.GL_UNSIGNED_BYTE, data[1].getPixels());

    Gdx.gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL30.GL_RGB, data[2].getWidth(), data[2].getHeight(), 0, GL30.GL_RGB, GL30.GL_UNSIGNED_BYTE, data[2].getPixels());
    Gdx.gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL30.GL_RGB, data[3].getWidth(), data[3].getHeight(), 0, GL30.GL_RGB, GL30.GL_UNSIGNED_BYTE, data[3].getPixels());

    Gdx.gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL30.GL_RGB, data[4].getWidth(), data[4].getHeight(), 0, GL30.GL_RGB, GL30.GL_UNSIGNED_BYTE, data[4].getPixels());
    Gdx.gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL30.GL_RGB, data[5].getWidth(), data[5].getHeight(), 0, GL30.GL_RGB, GL30.GL_UNSIGNED_BYTE, data[5].getPixels());

    Gdx.gl.glGenerateMipmap(GL.GL_TEXTURE_CUBE_MAP);
    Gdx.gl.glTexParameteri(GL.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_MIN_FILTER, GL30.GL_LINEAR);

    Gdx.gl.glTexParameteri ( GL.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_MIN_FILTER,GL30.GL_LINEAR_MIPMAP_LINEAR );     
    Gdx.gl.glTexParameteri ( GL.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_MAG_FILTER,GL30.GL_LINEAR );
    Gdx.gl.glTexParameteri ( GL.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_WRAP_S, GL30.GL_CLAMP_TO_EDGE );
    Gdx.gl.glTexParameteri ( GL.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_WRAP_T, GL30.GL_CLAMP_TO_EDGE );   

    Gdx.gl.glGenerateMipmap(GL30.GL_TEXTURE_CUBE_MAP);
}



public void render(Camera camera){

    //SPECIAL THANKS TO Jos van Egmond 
    camera.view.getRotation( q, true );
    q.conjugate();

    ///////////////////////////////////    
    worldTrans.idt();
    worldTrans.rotate(q);

    shader.begin();     
    shader.setUniformMatrix(u_worldTrans, worldTrans.translate(0, 0, -1));

    quad.render(shader, GL30.GL_TRIANGLES);
    shader.end();
}

public Mesh createQuad(){
    Mesh mesh = new Mesh(true, 4, 6, VertexAttribute.Position(), VertexAttribute.  ColorUnpacked(), VertexAttribute.TexCoords(0));
        mesh.setVertices(new float[] 
        {-1f, -1f, 0, 1, 1, 1, 1, 0, 1,
        1f, -1f, 0, 1, 1, 1, 1, 1, 1,
        1f, 1f, 0, 1, 1, 1, 1, 1, 0,
        -1f, 1f, 0, 1, 1, 1, 1, 0, 0});
        mesh.setIndices(new short[] {0, 1, 2, 2, 3, 0});
        return mesh;
}

@Override
public void dispose() {
    shader.dispose();
    quad.dispose();
    for(int i=0; i<6; i++) 
        data[i].dispose();
}

在我的主要 java 类中,我有

   env = new EnvironmentCubemap(Gdx.files.internal("assets/skybox/back.jpg"), Gdx.files.internal("assets/skybox/front.jpg"),
                    Gdx.files.internal("assets/skybox/top.jpg"), Gdx.files.internal("assets/skybox/bottom.jpg"),
                    Gdx.files.internal("assets/skybox/left.jpg"), Gdx.files.internal("assets/skybox/right.jpg"));

在我的渲染方法中

modelBatch.begin(cam);
        modelBatch.flush();
        modelBatch.render(instance);
        env.render(modelBatch.getCamera());
        modelBatch.end();

        // Stage
        stage.act();
        stage.draw();

【问题讨论】:

    标签: java libgdx


    【解决方案1】:

    不要将立方体贴图用于天空盒之类的东西,这只会过于复杂并且不会为您带来任何好处。只需在您的建模应用程序中创建一个框(或使用ModelBuilder,如果您愿意,可以创建 6 个矩形,您不应该这样做)并在其上映射纹理。就像您使用的任何其他模型一样。不要忘记您想从内部查看它,因此根据您的建模应用程序,您可能需要翻转法线或顶点缠绕。确保它足够大(如果需要,您可以使用不同的相机)。如果您经常移动相机,那么您可能希望盒子跟随相机,这样您就无法到达天空的尽头。最后,请确保在不指定环境的情况下进行渲染,这样就不会受到任何光照等的影响。

    当然,无论您是否使用立方体贴图,使用盒子表示天空确实有其局限性。因此,我个人建议使用天空球或天穹。本教程可能也会有所帮助:https://xoppa.github.io/blog/loading-a-scene-with-libgdx/。

    【讨论】:

    • 感谢您的帮助。我尝试按照在这个问题中所做的事情创建一个足够大的立方体,但是 stackoverflow.com/questions/27452192/… 。当我试图用 gdx 替换 tr[0] 时。 files.internal 它失败了。你有任何教程吗?我是一个新手,真的很挣扎。
    • 如果您是新手,请不要使用模型构建器。只需像对其他模型一样使用建模应用程序即可。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 2019-02-21
    • 2018-07-17
    • 2017-01-18
    • 2013-06-30
    • 1970-01-01
    • 2011-03-19
    相关资源
    最近更新 更多