【发布时间】:2017-07-20 16:52:40
【问题描述】:
我已经使用四叉树在我的图形引擎中实现了一个基本地形,现在我在修复 t 形接头和裂缝时遇到了问题。首先,我使用的是 OpenGL 3.2,所以我无法使用 tesslation。也许我会在不久的将来实现这个功能。基本上我有一个地形对象,它存储一个四叉树对象并有一个称为渲染的方法:
/**
* Render tile
* @param program - shader program
*/
public void render(Camera camera, Shader program)
{
if(camera.hasMoved())
this.quadtree.updateQuadTree(camera);
this.quadtree.render(program);
}
然后我的四叉树对象有四个称为 TerrainTreeNode 的子对象和这个方法:
/**
* Update quadtree
* @param camera - camera
*/
public void updateQuadTree(Camera camera)
{
for(Node node : getChildren())
((TerrainTreeNode) node).updateQuadtree(camera);
}
那么我的 TerrainTreeNode 对象有这些方法:
/**
* Update quad tree
* @param camera - camera
*/
public void updateQuadtree(Camera camera)
{
updateChildNodes(camera.position);
for(Node node : getChildren())
{
((TerrainTreeNode) node).updateQuadtree(camera);
}
}
/**
* Update child nodes
* @param cameraPosition - camera position
*/
private void updateChildNodes(Vector3f cameraPosition)
{
Vector3f tempCamera = new Vector3f(cameraPosition);
Vector3f tempPosition = new Vector3f(this.position);
Vector3f.sub(tempCamera, tempPosition, tempCamera);
float distance = tempCamera.length();
switch(this.lod)
{
case 0:
if(distance < 1750)
{
addChildNodes(this.lod+1);
}
else if(distance >= 1750)
{
removeChildNodes();
}
break;
case 1:
if(distance < 874)
{
addChildNodes(this.lod+1);
}
else if(distance >= 874)
{
removeChildNodes();
}
break;
case 2:
if(distance < 386)
{
addChildNodes(this.lod+1);
}
else if(distance >= 386)
{
removeChildNodes();
}
break;
case 3:
if (distance < 192)
{
addChildNodes(this.lod+1);
}
else if(distance >= 192)
{
removeChildNodes();
}
break;
case 4:
if(distance < 100)
{
addChildNodes(this.lod+1);
}
else if(distance >= 100)
{
removeChildNodes();
}
break;
case 5:
if(distance < 50)
{
addChildNodes(this.lod+1);
}
else if(distance >= 50)
{
removeChildNodes();
}
break;
case 6:
if(distance < 0)
{
addChildNodes(this.lod+1);
}
else if(distance >= 0)
{
removeChildNodes();
}
break;
case 7:
if (distance < 0)
{
addChildNodes(this.lod+1);
}
else if(distance >= 0)
{
removeChildNodes();
}
break;
}
}
/**
* Add child nodes
* @param lod - level of detail
*/
public void addChildNodes(int newLod)
{
if(isLeaf)
{
isLeaf = false;
if(this.mesh != null)
this.mesh.dispose();
}
if(getChildren().size() == 0)
{
float newWidth = this.width/2f;
float newWidth2 = newWidth/2f;
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
float first, second;
if(i == 0)
first = -(newWidth/2f);
else
first = newWidth/2f;
if(j == 0)
second = -(newWidth/2f);
else
second = newWidth/2f;
Vector3f newPosition = new Vector3f(this.position.x+first,
0f, this.position.z+second);
addChild(new TerrainTreeNode(newPosition,
newLod,
new Vector2f(i, j),
newWidth));
}
}
}
}
/**
* Remove child nodes
*/
private void removeChildNodes()
{
if(!isLeaf)
{
isLeaf = true;
this.mesh = generateMesh();
}
//Remove childrends
if(getChildren().size() != 0)
{
for(Node child : getChildren())
child.dispose();
getChildren().clear();
}
}
正如你所看到的,如果树节点与相机的距离很长,那么它会删除子节点并创建自己的 vao,在相反的情况下,它会创建子节点并从内存中删除 vao。我的 vao 使用三角扇,它看起来像这样:
1、2、4、6、8 和 10 个顶点始终处于活动状态,我要打开和关闭的其他顶点取决于邻居的详细程度以避免这种情况:
算法应该禁用红色顶点。我怎样才能做到这一点?如何找到所有无用的顶点? 该算法基于gamesutra的这篇文章。
感谢您的帮助!
编辑 我发现(来自此链接:http://www.dice.se/wp-content/uploads/2014/12/Chapter5-Andersson-Terrain_Rendering_in_Frostbite.pdf -> 请参阅第 53-55 页)我不必打开和关闭顶点,而是必须将节点的所有排列存储在不同的 vao 中。这很清楚。但仍然不知道如何检测裂缝:/。
【问题讨论】: