簡體   English   中英

OpenGL地形紋理底紋

[英]Opengl terrain texture shading

我目前正在用Java開發OpenGL(JOGL)項目。 目標是創建具有紋理和陰影的地形。

我正在使用這些值作為高度圖來創建隨機單純形噪聲。 高度映射到一維紋理以基於高度模擬着色。 然后使用一種材質(環境/漫反射/鏡面反射/光澤度)來模擬陰影。

然而; 在為地形添加陰影后,“條紋”出現在地形的每個“列”(Y方向)上。

然后應用以下材料:

TERRAIN(
        new float[]{0.5f, 0.5f, 0.5f, 1.0f},
        new float[]{0.7f, 0.7f, 0.7f, 1.0f},
        new float[]{0.2f, 0.2f, 0.2f, 1.0f},
        new float[]{100f})

材質枚舉構造函數:

Material(float[] ambient, float[] diffuse, float[] specular, float[] shininess) {
    this.ambient = ambient;
    this.diffuse = diffuse;
    this.specular = specular;
    this.shininess = shininess;
}

我使用以下方法應用材料:

public void use(GL2 gl) {
    // set the material properties
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT, ambient, 0);
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_DIFFUSE, diffuse, 0);
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, specular, 0);
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SHININESS, shininess, 0);
}

創建2個0-1值一致的“噪聲數組”后,將創建一個2D向量數組,包含X * Y個向量,其中每個向量代表平面/地形中的一個點。

這是在這些點之間繪制三角形的方法,您可以看到我每列(Y方向)繪制平面:

public void draw(GL2 gl, GLU glu, GLUT glut, Drawer drawer) {
    Material.TERRAIN.use(gl);
    texture.bind(gl);
    if (showGrid)
        gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_LINE );
    ArrayList<Vector[]> normals = new ArrayList<>();
    for(int i=1;i<vectors.length;i++) {
        gl.glBegin(gl.GL_TRIANGLE_STRIP);
        for (int j = 0; j < vectors[i].length; j++) {
            Vector normalTopRight, normalBottomLeft;

            //Calculate normals top right
            Vector v1, v2, triangleCenterTR;
            if (j < vectors[i].length - 1)
            {
                v1 = vectors[i-1][j].subtract(vectors[i][j]);
                v2 = vectors[i][j+1].subtract(vectors[i][j]);
                normalTopRight = v2.cross(v1).normalized();
                // Get center (a+b+c)*(1/3)
                triangleCenterTR = (vectors[i][j].add(vectors[i - 1][j]).add(vectors[i][j + 1])).scale(1.0 / 3);
            } else {
                v1 = vectors[i-1][j].subtract(vectors[i][j]);
                v2 = vectors[i][j-1].subtract(vectors[i][j]);
                normalTopRight = v1.cross(v2).normalized();
                // Get center (a+b+c)*(1/3)
                triangleCenterTR = (vectors[i][j].add(vectors[i-1][j]).add(vectors[i][j-1])).scale(1.0/3);
            }
            normals.add(new Vector[] {triangleCenterTR, triangleCenterTR.add(normalTopRight)});

            if (j != 0)
            {
                v1 = vectors[i][j].subtract(vectors[i-1][j]);
                v2 = vectors[i-1][j-1].subtract(vectors[i-1][j]);
                normalBottomLeft = v2.cross(v1).normalized();
                // Get center (a+b+c)*(1/3)
                Vector triangleCenterBL = (vectors[i - 1][j].add(vectors[i][j]).add(vectors[i - 1][j - 1])).scale(1.0 / 3);
                normals.add(new Vector[]{triangleCenterBL, triangleCenterBL.add(normalBottomLeft)});
            } else {
                normalBottomLeft = null; // If j==0, there is no bottom left triangle above
            }

            /**
             * We have everything to start drawing
             */
            // Set some color
            if (j == 0) {
                // Initialization vector
                gl.glTexCoord1d(mapTextureToHeight(vectors[i][j].z));
                drawer.glVertexV(vectors[i][j]);
            } else {
                drawer.glNormalV(normalBottomLeft);
            }

            // Shift left
            gl.glTexCoord1d(mapTextureToHeight(vectors[i - 1][j].z));
            drawer.glVertexV(vectors[i - 1][j]);

            // Right down diagonally
            if (j < vectors[i].length - 1) { // Skip if we are reached the end
                gl.glTexCoord1d(mapTextureToHeight(vectors[i][j + 1].z));
                drawer.glNormalV(normalTopRight);
                drawer.glVertexV(vectors[i][j + 1]);
            }
        }
        gl.glEnd();
    }
    if (showGrid)
        gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_FILL );
    if (drawNormals) {
        for (Vector[] arrow : normals) {
            if (yellowNormals)
                Material.YELLOW.use(gl);
            else
                gl.glTexCoord1d(mapTextureToHeight(arrow[0].z));
            drawer.drawArrow(arrow[0], arrow[1], 0.05);
        }
    }

    texture.unbind(gl);
}

出現條紋的最明顯原因是我每列繪制了三角形,導致OpenGL無法平滑多邊形(GL_SMOOTH)上的陰影。 有沒有什么辦法解決這一問題?

出現在地形上的條紋圖像

使用更高的分辨率(更多多邊形)

[Edit1]摘自Spektre的評論

我剛剛完成了平均法線的計算,現在確實地勢平坦,但是光照看起來有些暗淡(沒有深度)

例

這是繪制地形的新代碼:

public void draw() {
    if (showGrid)
        gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_LINE);
    texture.bind(gl);
    Material.TERRAIN.use(gl);
    for(int i=1;i<vectors.length;i++) {
        gl.glBegin(gl.GL_TRIANGLE_STRIP);
        for (int j = 0; j < vectors[i].length; j++) {
            // Initialization vector
            gl.glTexCoord1d(mapTextureToHeight(vectors[i][j].z));
            drawer.glNormalV(normals.get(vectors[i][j]));
            drawer.glVertexV(vectors[i][j]);

            // Shift left
            gl.glTexCoord1d(mapTextureToHeight(vectors[i - 1][j].z));
            drawer.glNormalV(normals.get(vectors[i - 1][j]));
            drawer.glVertexV(vectors[i - 1][j]);
        }
        gl.glEnd();
    }
    if (showGrid)
        gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_FILL );
    if (drawNormals)
        drawFaceNormals();
    texture.unbind(gl);
}

我將其清理干凈,我確定法線使用drawnormals函數指向正確的方式,並確保OpenGL使用FRONT來將地形的頂部視為FRONT(gl.GL_FRONT->僅在地形上方繪制,而不在下方繪制)。

這是完整的類: PasteBin

感謝@Spektre幫助我。

正確計算頂點上所有周圍平面的平均法線並將此法線用於glNormal ,陰影是正確的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM