快速总结:
我有一个简单的基于四叉树的地形渲染系统,它可以构建地形补丁,然后在顶点着色器中对高度贴图进行采样,以确定每个顶点的高度。
对于对象放置和co,在CPU上进行完全相同的计算。
超级简单,但现在添加了一些系统来按程序放置对象后,我发现它们似乎只是放错了一小部分地方。为了调试这一点,我在地形上渲染了几个十字架作为单个模型。这个
十字架
(红、绿、蓝线)表示从CPU读取的高度。地形网格使用着色器来平移顶点。
(我还在每个高度值上添加了一个简单的奇数/偶数间隙,以排除简单的偏移问题。
所以那些丑陋的悬崖是意料之中的事,淹没的十字架是问题所在
)
我明确使用
GL_NEAREST
能够显示“原始”高度值:
正如你所看到的,十字架有时被淹没在地形下,而不是代表它的确切高度。
高度图只是CPU和GPU上的一个简单的浮点数组。
数据的存储方式
一个简单的
vector<float>
它被上传到
GL_RGB32F
GL_FLOAT
缓冲器浮动没有标准化,我的地形通常包含-100到500之间的值。
如何在着色器中访问数据
我尝试了一些方法来排除错误,最初:
vec2 terrain_heightmap_uv(vec2 position, Heightmap heightmap)
{
return (position + heightmap.world_offset) / heightmap.size;
}
float terrain_read_height(vec2 position, Heightmap heightmap)
{
return textureLod(heightmap.heightmap, terrain_heightmap_uv(position, heightmap), 0).r;
}
顶点着色器的基础知识(完整的着色器代码很长,所以我提取了实际读取高度的部分):
void main()
{
vec4 world_position = a_model * vec4(a_position, 1.0);
vec4 final_position = world_position;
// snap vertex to grid
final_position.x = floor(world_position.x / a_quad_grid) * a_quad_grid;
final_position.z = floor(world_position.z / a_quad_grid) * a_quad_grid;
final_position.y = terrain_read_height(final_position.xz, heightmap);
gl_Position = projection * view * final_position;
}
为了确保位置的确定方式略有不同,我使用与C++读取高度方式相同的硬编码值对其进行了测试:
return texelFetch(heightmap.heightmap, ivec2((position / 8) + vec2(1024, 1024)), 0).r;
这给出了完全相同的结果。。。
如何在应用程序中访问数据
在C++中,高度如下所示:
inline float get_local_height_safe(uint32_t x, uint32_t y)
{
// this macro simply clips x and y to the heightmap bounds
// it does not interfer with the result
BB_TERRAIN_HEIGHTMAP_BOUND_XY_TO_SAFE;
uint32_t i = (y * _size1d) + x;
return buffer->data[i];
}
inline float get_height_raw(glm::vec2 position)
{
position = position + world_offset;
uint32_t x = static_cast<int>(position.x);
uint32_t y = static_cast<int>(position.y);
return get_local_height_safe(x, y);
}
float BB::Terrain::get_height(const glm::vec3 position)
{
return heightmap->get_height_raw({position.x / heightmap_unit_scale, position.z / heightmap_unit_scale});
}
我尝试过什么:
-
比较缓冲区
我已经从向量中丢弃了最初的几百个值。并将其与使用Nvidia Nsight上传到GPU的浮点缓冲区进行比较,它们是相等的,四舍五入/精度误差。
-
取样方法
我试过了
texture
,
textureLod
和
texelFetch
为了排除一些问题,他们都给了我相同的结果。
-
舍入
当我四舍五入所有的高度值时,这是一件非常奇怪的事情。它们完全对齐,这只是浮点精度问题。
-
位置捕捉
我已经尝试过将位置舍入、铺地板和天花板,以确保该位置始终映射到相同的纹理元素。我还尝试添加ε偏移量来排除位置精度误差(可能很愚蠢,因为地形稳定…)
-
高度图尺寸
我试过各种不同尺寸的高度图。
-
高度图图案
我创建了一个包含图案的高度图,以确保位置不只是偏移。