【问题标题】:Opengl - Extreme texture quality lossOpengl - 极端的纹理质量损失
【发布时间】:2019-12-23 22:02:58
【问题描述】:

我正在尝试对球体进行纹理处理。我的顶点着色器:

attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec3 a_texCoord0;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform sampler2D u_texture;
varying vec3 fragPos;
varying vec3 normal;
varying vec3 color;

void main()
{
    gl_Position = projection * view * model * vec4(a_position, 1.0);
    fragPos = vec3(model * vec4(a_position, 1.0));
    normal = a_normal;
    if(a_texCoord0.x > 50){
        color = vec3(1f, 0.0f, 0.0f);
    } else {
        color = texture(u_texture, a_texCoord0);
    }
}

我的片段着色器:

#ifdef GL_ES
    precision mediump float;
#endif
varying vec3 normal;
varying vec3 color;
varying vec3 fragPos;

uniform vec3 lightPos;
uniform vec3 lightColor;

void main()
{
    // Ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    // Diffuse
    vec3 norm = normalize(normal);
    vec3 lightDir = normalize(lightPos - fragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    //vec3 result = (ambient + diffuse) * color;
    vec3 result = color;
    gl_FragColor = vec4(result, 1.0);
}

我从二十面体构建球体,但使用 6 个相同的纹理对其进行纹理化,并通过立方体贴图原理连接它。这是我如何将球面坐标转换为 UV 的代码:

public void fillTexInformation(Vertex vertex){
        float[] sphericalCoord = GeometryHelper.toSphericalCoordinates(vertex.getPosition());
        vertex.setTexCoord(projection(sphericalCoord[1], sphericalCoord[2]));
    }

    /**
     * Project point on shpere to texture coordinate
     * @param theta
     * @param phi
     * @return
     */
    //https://stackoverflow.com/questions/29678510/convert-21-equirectangular-panorama-to-cube-map
    private Vector2 projection(float theta, float phi) {
        if (theta < 0.615) {
            return projectRight(theta, phi);
        } else if (theta > 2.527) {
            return projectLeft(theta, phi);
        } else if (phi <= Math.PI / 4 || phi > 7 * Math.PI / 4) {
            return projectBack(theta, phi);
        } else if (phi > Math.PI / 4 && phi <= 3 * Math.PI / 4) {
            return projectBottom(theta, phi);
        } else if (phi >3 * Math.PI / 4 && phi <= 5 * Math.PI / 4) {
            return projectFront(theta, phi);
        } else if (phi > 5 * Math.PI / 4 && phi <= 7 * Math.PI / 4) {
            return projectTop(theta, phi);
        } else {
            throw new RuntimeException("Algorithm error");
        }
    }

    private Vector2 projectBack(float theta, float phi) {
        float y = (float) Math.tan(phi);
        float z = (float) ((1 / Math.tan(theta)) / Math.cos(phi));
        if (z < -1) {
            return projectLeft(theta, phi);
        }
        if (z > 1) {
            return projectRight(theta, phi);
        }

        return new Vector2(normilizeTexCoord(y), normilizeTexCoord(z));
    }

    private Vector2 projectBottom(float theta, float phi) {
        float x = (float) Math.tan(phi - Math.PI / 2);
        float z = (float) ((1 / Math.tan(theta)) / Math.cos(phi - Math.PI / 2));
        if (z < -1) {
            return projectLeft(theta, phi);
        }
        if (z > 1) {
            return projectRight(theta, phi);
        }

//        return new Vector2(normilizeTexCoord(x), normilizeTexCoord(z));
        return new Vector2(100, 100);
    }

    private Vector2 projectFront(float theta, float phi) {
        float y = (float) Math.tan(phi);
        float z = (float) (-(1 / Math.tan(theta)) / Math.cos(phi));
        if (z < -1) {
            return projectLeft(theta, phi);
        }
        if (z > 1) {
            return projectRight(theta, phi);
        }

//        return new Vector2(normilizeTexCoord(y), normilizeTexCoord(z));
        return new Vector2(100, 100);
    }

    private Vector2 projectTop(float theta, float phi) {
        float x = (float) Math.tan(phi - 3 * Math.PI / 2);
        float z = (float) ((1 / Math.tan(theta)) / Math.cos(phi - 3 * Math.PI / 2));
        if (z < -1) {
            return projectLeft(theta, phi);
        }
        if (z > 1) {
            return projectRight(theta, phi);
        }

//        return new Vector2(normilizeTexCoord(x), normilizeTexCoord(z));
        return new Vector2(100, 100);
    }

    private Vector2 projectRight(float theta, float phi) {
        float x = (float) (Math.tan(theta) * Math.cos(phi));
        float y = (float) (Math.tan(theta) * Math.sin(phi));
//        return new Vector2(normilizeTexCoord(x), normilizeTexCoord(y));
        return new Vector2(100, 100);
    }

    private Vector2 projectLeft(float theta, float phi) {
        float x = (float) (-Math.tan(theta) * Math.cos(phi));
        float y = (float) (-Math.tan(theta) * Math.sin(phi));
//        return new Vector2(normilizeTexCoord(x), normilizeTexCoord(-y));
        return new Vector2(100, 100);
    }

    private float normilizeTexCoord(float coord){
        return (coord + 1) / 2;
    }

结果我得到了可怕的纹理质量损失。这是original texturewhat I get on sphere(这里只是立方体贴图的一部分,其他边是红色的)。 我猜测它可能与构建方法(来自二十面体)和纹理(使用立方体贴图)的差异有关。但它可以解释纹理边缘不均匀但没有那么可怕的质量损失。有人可以向我解释一下这里发生了什么吗?

【问题讨论】:

    标签: java opengl libgdx


    【解决方案1】:

    这是因为您在顶点着色器中对纹理进行采样,这意味着您只能在每个三角形的角处获得三种颜色。其他像素被插值。

    为了获得更好的质量,应该将纹理采样移到片段着色器中,并且应该插入 uv 坐标而不是颜色:

    顶点着色器:

    attribute vec3 a_position;
    attribute vec3 a_normal;
    attribute vec3 a_texCoord0;
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    
    varying vec3 fragPos;
    varying vec3 normal;
    varying vec2 texcoord0;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(a_position, 1.0);
        fragPos = vec3(model * vec4(a_position, 1.0));
        normal = a_normal;
        texcoord0 = a_texCoord0;
    }
    

    片段着色器:

    varying vec3 normal;
    varying vec2 texcoord0;
    varying vec3 fragPos;
    
    uniform sampler2D u_texture;
    uniform vec3 lightPos;
    uniform vec3 lightColor;
    
    void main()
    {
        vec3 color = texture(u_texture, texcoord0).rgb;
    
        // Ambient
        float ambientStrength = 0.1;
        vec3 ambient = ambientStrength * lightColor;
    
        // Diffuse
        vec3 norm = normalize(normal);
        vec3 lightDir = normalize(lightPos - fragPos);
        float diff = max(dot(norm, lightDir), 0.0);
        vec3 diffuse = diff * lightColor;
    
        //vec3 result = (ambient + diffuse) * color;
        vec3 result = color;
        gl_FragColor = vec4(result, 1.0);
    }
    

    【讨论】:

    • 我是否正确理解片段着色器中的不同变量被插值?因此,在我的情况下,变量“颜色”被插值,这是纹理不成功的原因,但在您的代码中“texcoord0”被插值。对吗?
    • @КобаЕвгений:正确。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-14
    相关资源
    最近更新 更多