当前的截锥体剔除效果导致 openTk 中的对象闪烁
Current frustum culling effects results in flickering objects in openTk
我在进行视锥体剔除的方式上遇到了一些问题。当前的方法确实解决了剔除问题,但效果确实很奇怪。当我离我的主要父对象太近时,我正在使用场景图来渲染所有内容,对象开始非常快速地闪烁。当我离开时,它就消失了。我尝试了很多东西,但再也没有想法了。你们有什么想法吗?非常感谢任何帮助。
我首先在我的模型周围创建一个由八个点组成的边界框。据我所知,经过大量测试,这些都是正确的。
这是我计算截锥平面点的方法。
相机位置是世界 space 中的位置,方向是它正在看的方向。此外,每次旋转相机时都会计算 cameraUp 和 cameraRight。
Vector3 pos = Camera.staticPosition;
Vector3 view = Camera.staticOrientation;
Vector3 upVector3 = Camera.cameraUp;
Vector3 rightVector3 = Camera.cameraRight;
float toRadians = (float)Math.PI / 180.0f;
float nearDis = .1f;
float farDistance = 1000f;
float fov = Game.FOV;
float aspectRatio = 1.3f;
//Get with and height of near and far plane
float tanDiv = 2 * (float) Math.Tan(fov*toRadians / 2);
float heightNear = tanDiv * nearDis;
float widthNear = heightNear * aspectRatio;
float heightFar = tanDiv * farDistance;
float widthFar = heightFar * aspectRatio;
// get the centre points of the planes so they can be used to calculate the edge points
Vector3 centreNear = pos + view * nearDis;
Vector3 centreFar = pos + view * farDistance;
// get the halfht values of the width and hegiht to make sure you can get the points
float hNearHalf = heightNear / 2;
float wNearHalf = widthNear / 2;
float hFarHalf = heightFar / 2;
float wFarHalf = widthFar / 2;
Vector3 nearTopLeft = centreNear + (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
Vector3 nearTopRight = centreNear + (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);
Vector3 nearBottomLeft = centreNear - (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
Vector3 nearBottomRight = centreNear - (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);
Vector3 farTopLeft = centreFar + (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
Vector3 farTopRight = centreFar + (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);
Vector3 farBotomLeft = centreFar - (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
Vector3 farBottomRight = centreFar - (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);
我将截锥体点存储在一个数组中。首先是近平面点,然后是远平面、顶平面、底平面、左平面,最后是右平面。然后我遍历所有六个平面和 boundinbox 的 8 个点,如果该点位于平面的右侧,则增加字典中该键的值。
Vector3[] frustumPoints = new Vector3[18]
{
nearTopLeft, nearTopRight, nearBottomLeft, farTopLeft, farTopRight, farBotomLeft, nearTopLeft, farTopLeft,
nearTopRight, nearBottomLeft, farBotomLeft, nearBottomRight, nearTopLeft, nearBottomLeft, farTopLeft,
nearTopRight, nearBottomRight, farTopRight
};
Dictionary<Vector3, int> count = new Dictionary<Vector3, int>(8);
for (int value = 0; value < 8; value++)
{
count.Add(cubePositions[value], 0);
}
for (int x = 0; x < 18; x += 3)
{
Vector3 normal = NormalPlane(frustumPoints[x], frustumPoints[x + 1], frustumPoints[x + 2]);
for (int y = 0; y < 8; y++)
{
Vector3 pointPlane = frustumPoints[x] - cubePositions[y];
float dot = Vector3.Dot(pointPlane, normal);
if (dot <= 0 && x % 6 == 0)
{
count[cubePositions[y]]++;
}
else if (dot >= 0 && x % 3 == 0)
{
count[cubePositions[y]]++;
}
}
}
这是我获取平面法线的方法
Vector3 NormalPlane(Vector3 pointOne, Vector3 pointTwo, Vector3 pointThree)
{
Vector3 normal;
Vector3 edgeOne = pointTwo - pointOne; // calculate vector from point one to point two
Vector3 edgeTwo = pointThree - pointOne; // calculate vector from point one to point three
normal = Vector3.Normalize(Vector3.Cross(edgeOne, edgeTwo)); // calculate the cross product of the two given vectors. Then normalize it so you have normal of plane
return normal; // return the normal
}
如果对于立方体上的这些点之一,计数为 6,则这些点在所有平面内,因此平截头体和我绘制对象。如果 none 个点等于 6,则不会绘制对象。
问题是我不知道我在哪里犯了错误所以你们有什么想法吗?
提前致谢,
杰罗默
If for one of these points on the cube the count is six, the points is within all planes and thus the frustum and I draw the object. If none of the points is equal to 6 the objects don't get drawn.
你的逻辑好像是
- "if there is no vertex of the cube lying inside the frustum, the cube is not visible."
不过。这只是错误。即使立方体的所有 8 个顶点都位于平截头体之外,立方体仍然可以与平截头体相交,如二维草图所示:
*----------*
| |
+-----------------+--+ |
\ | / |
\ |/ |
\ / |
\ /| |
\ / *----------*
\ /
\ /
+----+
因此你剔除了可能可见的东西。
平截头体剔除的通常逻辑是只有当所有顶点都被同一平面拒绝时才剔除该框。 (这会导致一些奇怪的情况,盒子完全在外面并且没有被剔除,但这些情况不太可能发生,通常也没什么大不了的。)
我在进行视锥体剔除的方式上遇到了一些问题。当前的方法确实解决了剔除问题,但效果确实很奇怪。当我离我的主要父对象太近时,我正在使用场景图来渲染所有内容,对象开始非常快速地闪烁。当我离开时,它就消失了。我尝试了很多东西,但再也没有想法了。你们有什么想法吗?非常感谢任何帮助。
我首先在我的模型周围创建一个由八个点组成的边界框。据我所知,经过大量测试,这些都是正确的。
这是我计算截锥平面点的方法。 相机位置是世界 space 中的位置,方向是它正在看的方向。此外,每次旋转相机时都会计算 cameraUp 和 cameraRight。
Vector3 pos = Camera.staticPosition;
Vector3 view = Camera.staticOrientation;
Vector3 upVector3 = Camera.cameraUp;
Vector3 rightVector3 = Camera.cameraRight;
float toRadians = (float)Math.PI / 180.0f;
float nearDis = .1f;
float farDistance = 1000f;
float fov = Game.FOV;
float aspectRatio = 1.3f;
//Get with and height of near and far plane
float tanDiv = 2 * (float) Math.Tan(fov*toRadians / 2);
float heightNear = tanDiv * nearDis;
float widthNear = heightNear * aspectRatio;
float heightFar = tanDiv * farDistance;
float widthFar = heightFar * aspectRatio;
// get the centre points of the planes so they can be used to calculate the edge points
Vector3 centreNear = pos + view * nearDis;
Vector3 centreFar = pos + view * farDistance;
// get the halfht values of the width and hegiht to make sure you can get the points
float hNearHalf = heightNear / 2;
float wNearHalf = widthNear / 2;
float hFarHalf = heightFar / 2;
float wFarHalf = widthFar / 2;
Vector3 nearTopLeft = centreNear + (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
Vector3 nearTopRight = centreNear + (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);
Vector3 nearBottomLeft = centreNear - (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
Vector3 nearBottomRight = centreNear - (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);
Vector3 farTopLeft = centreFar + (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
Vector3 farTopRight = centreFar + (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);
Vector3 farBotomLeft = centreFar - (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
Vector3 farBottomRight = centreFar - (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);
我将截锥体点存储在一个数组中。首先是近平面点,然后是远平面、顶平面、底平面、左平面,最后是右平面。然后我遍历所有六个平面和 boundinbox 的 8 个点,如果该点位于平面的右侧,则增加字典中该键的值。
Vector3[] frustumPoints = new Vector3[18]
{
nearTopLeft, nearTopRight, nearBottomLeft, farTopLeft, farTopRight, farBotomLeft, nearTopLeft, farTopLeft,
nearTopRight, nearBottomLeft, farBotomLeft, nearBottomRight, nearTopLeft, nearBottomLeft, farTopLeft,
nearTopRight, nearBottomRight, farTopRight
};
Dictionary<Vector3, int> count = new Dictionary<Vector3, int>(8);
for (int value = 0; value < 8; value++)
{
count.Add(cubePositions[value], 0);
}
for (int x = 0; x < 18; x += 3)
{
Vector3 normal = NormalPlane(frustumPoints[x], frustumPoints[x + 1], frustumPoints[x + 2]);
for (int y = 0; y < 8; y++)
{
Vector3 pointPlane = frustumPoints[x] - cubePositions[y];
float dot = Vector3.Dot(pointPlane, normal);
if (dot <= 0 && x % 6 == 0)
{
count[cubePositions[y]]++;
}
else if (dot >= 0 && x % 3 == 0)
{
count[cubePositions[y]]++;
}
}
}
这是我获取平面法线的方法
Vector3 NormalPlane(Vector3 pointOne, Vector3 pointTwo, Vector3 pointThree)
{
Vector3 normal;
Vector3 edgeOne = pointTwo - pointOne; // calculate vector from point one to point two
Vector3 edgeTwo = pointThree - pointOne; // calculate vector from point one to point three
normal = Vector3.Normalize(Vector3.Cross(edgeOne, edgeTwo)); // calculate the cross product of the two given vectors. Then normalize it so you have normal of plane
return normal; // return the normal
}
如果对于立方体上的这些点之一,计数为 6,则这些点在所有平面内,因此平截头体和我绘制对象。如果 none 个点等于 6,则不会绘制对象。
问题是我不知道我在哪里犯了错误所以你们有什么想法吗?
提前致谢,
杰罗默
If for one of these points on the cube the count is six, the points is within all planes and thus the frustum and I draw the object. If none of the points is equal to 6 the objects don't get drawn.
你的逻辑好像是
- "if there is no vertex of the cube lying inside the frustum, the cube is not visible."
不过。这只是错误。即使立方体的所有 8 个顶点都位于平截头体之外,立方体仍然可以与平截头体相交,如二维草图所示:
*----------*
| |
+-----------------+--+ |
\ | / |
\ |/ |
\ / |
\ /| |
\ / *----------*
\ /
\ /
+----+
因此你剔除了可能可见的东西。
平截头体剔除的通常逻辑是只有当所有顶点都被同一平面拒绝时才剔除该框。 (这会导致一些奇怪的情况,盒子完全在外面并且没有被剔除,但这些情况不太可能发生,通常也没什么大不了的。)