如何找到四个顶点之间点的Y位置? HLSL

时间:2014-08-31 22:25:14

标签: c++ directx hlsl terrain geometry-shader

假设有一个由两个三角形组成的瓷砖组成的游戏的网格地形 - 由四个顶点组成。我们如何找到四个顶点之间点的Y(向上)位置?

Terrain

我试过这个:

float diffZ1    = lerp(heights[0], heights[2], zOffset);
float diffZ2    = lerp(heights[1], heights[3], zOffset);
float yPosition = lerp(diffZ1, diffZ2, xOffset);

其中z / yOffset是距离瓷砖第一个顶点的z / y偏移量,单位为百分比/ 100.这适用于平面,但在凹凸不平的地形上不太好。

我希望这与三角形的地形有关,上面的三角形可以在平面上工作。我不确定,但有人知道出了什么问题吗?

这可以更好地解释这里发生了什么:

enter image description here

在上面的代码"高度[]"是周围顶点v0-3的Y坐标的数组。 三角形1由顶点0,2和1组成。 三角形2由顶点1,2和3组成。

当x,y坐标位于v0-3之间时,我希望找到p1的坐标Y.

所以我尝试通过这个函数确定点之间的哪个三角形:

bool PointInTriangle(float3 pt, float3 pa, float3 pb, float3 pc)
{
  // Compute vectors        
  float2 v0 = pc.xz - pa.xz;
  float2 v1 = pb.xz - pa.xz;
  float2 v2 = pt.xz - pa.xz;

  // Compute dot products
  float dot00 = dot(v0, v0);
  float dot01 = dot(v0, v1);
  float dot02 = dot(v0, v2);
  float dot11 = dot(v1, v1);
  float dot12 = dot(v1, v2);

  // Compute barycentric coordinates
  float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
  float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

  // Check if point is in triangle
  return (u >= 0.0f) && (v >= 0.0f) && (u + v <= 1.0f);
}

这并不能给我预期的结果

然后我试图在每个三角形内找到点p1的y坐标:

// Position of point p1
float3 pos = input[0].PosI;

// Calculate point and normal for triangles
float3 p1 = tile[0];
float3 n1 = (tile[2] - p1) * (tile[1] - p1); // <-- Error, cross needed
       // = cross(tile[2] - p1, tile[1] - p1);
float3 p2 = tile[3];
float3 n2 = (tile[2] - p2) * (tile[1] - p2);  // <-- Error
       // = cross(tile[2] - p2, tile[1] - p2); 
float newY = 0.0f;

// Determine triangle & get y coordinate inside correct triangle
if(PointInTriangle(pos, tile[0], tile[1], tile[2]))
{
    newY = p1.y - ((pos.x - p1.x) * n1.x + (pos.z - p1.z) * n1.z) / n1.y;
}
else if(PointInTriangle(input[0].PosI, tile[3], tile[2], tile[1]))
{
    newY = p2.y - ((pos.x - p2.x) * n2.x + (pos.z - p2.z) * n2.z) / n2.y;
}

使用以下内容查找正确的三角形:

if((1.0f - xOffset) <= zOffset)
    inTri1 = true;

纠正上面的代码以使用正确的交叉函数似乎已经解决了这个问题。

enter image description here

1 个答案:

答案 0 :(得分:4)

因为您的4个顶点可能不在平面上,所以您应该分别考虑每个三角形。首先找到该点所在的三角形,然后使用下面的StackOverflow讨论来求解Z值(注意轴的不同命名)。我个人非常喜欢DanielKO的答案,但是接受的答案也应该有效:

Linear interpolation of three 3D points in 3D space


编辑:对于问题的第二部分(找到该点所在的三角形): 因为将瓷砖投影到xz平面上(当您定义坐标时)是完美的正方形,找到点所在的三角形是一个非常简单的操作。在这里,我将使用左右术语来指代x轴(从x的较低值到较高值)和从底部到顶部来指代z轴(从z的较低值到较高值)。

每个图块只能以两种方式之一进行拆分。 (A)通过从左下角到右上角的对角线,或(B)通过从右下角到左上角的对角线。

  • 对于任何分为A的拼贴: 检查x&#39; &GT; z&#39;,其中x&#39;是从瓷砖的边缘到该点的距离,并且z&#39;是从瓷砖的底部边缘到该点的距离。如果x&#39; &GT; ž&#39;那你的观点是在右下三角形;否则它在左上角的三角形中。

  • 对于任何拆分为B的图块:检查x&#34; &GT; z&#39;,其中x&#34;是从瓷砖的右侧边缘到该点的距离,并且z&#39;是从瓷砖的底部边缘到该点的距离。如果x&#34; &GT; ž&#39;那么你的观点就在左下角的三角形里;否则它就在右上角的三角形中。

(小调:上面我假设你的瓷砖没有在xz平面上旋转;即它们与轴对齐。如果这不正确,只需旋转它们使它们与轴对齐在进行上述检查之前。)