当前位置: 首页 > 知识库问答 >
问题:

地形网格法线的计算

虞安康
2023-03-14

我试图优化我的地形,减少三角形计数,同时保持尽可能多的细节。减少工作很好,我削减了五分之一顶点的数量没有太多的视觉损失。在这个新的非对称网格上法线的计算有一个问题。

每个顶点都有法线,下面是计算法线的片段:

private void calcNormal(Vector<Triangle_dt> triangles, Point_dt point) {

    Vec3 normal = new Vec3(0, 0, 0);
    for (Triangle_dt triangle : triangles) {
        Vec3 a = getPos(triangle.p1());
        Vec3 b = getPos(triangle.p2());
        Vec3 c = getPos(triangle.p3());

        Vec3 AB = b.subtract(a);
        Vec3 AC = c.subtract(a);

        normal = normal.add(AB.cross(AC));
    }

    setNormal(point, normal.getUnitVector());
}

其中三角形是与顶点(点)相连的三角形。我把所有的三角形法线加在一起(不进行归一化以使最终的向量以三角形面积加权),然后最后对最终结果进行归一化。

我相信计算是正确的,但结果中有一些讨厌的伪影(它被定向光点亮):

如你所见,顶点稀疏的地方有不需要的线。这是由于一小群离下一组点很近,但离下一组点很远而引起的(见下图)。有什么办法防止这种情况发生吗?下面是点渲染的相同视图:

共有1个答案

皇甫文乐
2023-03-14

多亏了ybungalobill,我做了以下工作来使它工作:

  1. 使用以下代码从原始heighmap(对称网格)创建法线地图:

从高度图计算法线

// Calculating normals from height map
public void calcNormals() {
    Vec3 up = new Vec3(0, 1, 0);
    float sizeFactor = 1.0f / (8.0f * cellSize);
    normals = new Vec3[rows * cols];

    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            Vec3 normal = up;

            if (col > 0 && row > 0 && col < cols - 1 && row < rows - 1) {
                float nw = getValue(row - 1, col - 1);
                float n = getValue(row - 1, col);
                float ne = getValue(row - 1, col + 1);
                float e = getValue(row, col + 1);
                float se = getValue(row + 1, col + 1);
                float s = getValue(row + 1, col);
                float sw = getValue(row + 1, col - 1);
                float w = getValue(row, col - 1);

                float dydx = ((ne + 2 * e + se) - (nw + 2 * w + sw)) * sizeFactor;
                float dydz = ((sw + 2 * s + se) - (nw + 2 * n + ne)) * sizeFactor;

                normal = new Vec3(-dydx, 1.0f, -dydz).getUnitVector();
            }

            normals[row * cols + col] = normal;
        }
    }
}
public static BufferedImage getNormalMap(Terrain terrain) {
    Vec3[] normals = terrain.getNormals();
    float[] pixels = new float[normals.length * 3];

    for (int i = 0; i < normals.length; i++) {
        Vec3 normal = normals[i];
        float x = (1.0f + normal.x) * 0.5f;
        float y = (1.0f + normal.y) * 0.5f;
        float z = (1.0f + normal.z) * 0.5f;
        pixels[i * 3] = x * MAX;
        pixels[i * 3 + 1] = y * MAX;
        pixels[i * 3 + 2] = z * MAX;
    }

    BufferedImage img = new BufferedImage(cols, rows, BufferedImage.TYPE_INT_RGB);
    WritableRaster imgRaster = img.getRaster();
    imgRaster.setPixels(0, 0, cols, rows, pixels);
    return img;
}
void main() {
    vec3 newNormal = texture(normalMap, vec2(worldPos0.x / maxX, worldPos0.z / maxZ)).xyz;
    newNormal = (2.0 * newNormal) - 1.0;
    outputColor = calcColor(normalize(newNormal));
}

结果如下:

与点呈现相同的视图:

换句话说:很少的顶点,但视觉上很高的细节地形

 类似资料:
  • 我要做的是找出在一个六角网格上,两点之间有多少个六边形。我试着在网上搜索一个公式,但我无法找到一个匹配类型的十六进制网格我正在使用。

  • 我有一个超过40年的过去Storm的大数据集(约20000),其中有一个3小时间隔的中心点列表。我试图覆盖一个网格网格到一个大的区域,我想从其中计数的次数每次Storm已经通过任何给定的网格单元,但是我目前的实现只跟踪在这三个小时的时间间隔的位置,导致一些情况当轨道也应该被计算时,它会跳过网格空间。 我尝试使用geopandas来解决这个问题,为每个Storm轨迹创建一个线系列,然后对网格网格执行

  • 我有一个六边形网格,就像图中的一样,我试图找到最简单的方法(也许是一个公式)来计算这个网格内两个六边形之间的距离。当然,我的网格的大小比这更大,但是当我们计算规则网格(有水平和垂直轴)中两个节点之间的距离时,我试图找到一个类似于欧几里得距离公式的公式。 我读了一些方法,但他们都说Y轴应该是60度,然后他们提供了一些公式(六角网格中瓷砖之间的曼哈顿距离)。是否有一种方法来计算距离使用“坐标系”相同,

  • 这更多的是一个方法问题,而不仅仅是技术问题。 我有一个生成的球体,分解成六边形作为一个网格。每一个六边形瓷砖都是一种不同的地形,例如,山,丘陵,海洋,飞机等。我想在3D中把每一种地形类型画成几个网格的集合,代表一种相应的地形类型。 现在最大的问题是如何在运行时将地形网格调整到每个六边形面,这取决于地形类型,在运行时地形类型也会发生变化,例如,地形变形。同时,考虑到六边形并不是完全正则或相等的。 缩

  • 地形计算 地形计算又称地形曲率计算,格数据表面的曲率,包括平均曲率、剖面曲率和平面曲率。曲率是表面的二阶导数,或者可称之为坡度的坡度。输出结果为地形栅格每个像元的表面曲率,该值通过将该像元与八个相邻像元拟合而得。结果输出为栅格数据集,可输出曲率类型为:平均曲率、剖面曲率和平面曲率,平均曲率为必须输出的结果,剖面曲率和平面曲率为可选择输出。其中,剖面曲率是指沿最大斜率方向的曲率,平面曲率是指垂直于最

  • gridline(int $option = \Vtiful\Kernel\Excel::GRIDLINES_SHOW_ALL): self 网格线类型 const GRIDLINES_HIDE_ALL = 0; // 隐藏 屏幕网格线 和 打印网格线 const GRIDLINES_SHOW_SCREEN = 1; // 显示屏幕网格线 const GRIDLINES_SHOW_PRIN