简体   繁体   English

在给定的世界坐标处修改网格上的纹理

[英]Modifying a texture on a mesh at given world coordinate

Im making an editor in which I want to build a terrain map. 我正在制作一个编辑器,我想在其中构建地形图。 I want to use the mouse to increase/decrease terrain altitude to create mountains and lakes. 我想用鼠标来增加/减少地形高度来创造山脉和湖泊。

Technically I have a heightmap I want to modify at a certain texcoord that I pick out with my mouse. 从技术上讲,我有一个高度图,我想在我用鼠标选择的某个texcoord上进行修改。 To do this I first go from screen coordinates to world position - I have done that. 要做到这一点,我首先从屏幕坐标到世界位置 - 我已经做到了。 The next step, going from world position to picking the right texture coordinate puzzles me though. 下一步,从世界位置到选择正确的纹理坐标让我感到困惑。 How do I do that? 我怎么做?

If you are using a simple hightmap, that you use as a displacement map in lets say the y direction. 如果您使用的是简单的hightmap,那么您将其用作位移贴图,即y方向。 The base mesh lays in the xz plain (y=0). 基础网格位于xz平面(y = 0)。

You can discard the y coordinate from world coordinate that you have calculated and you get the point on the base mesh. 您可以从已计算的世界坐标中丢弃y坐标,并获得基础网格上的点。 From there you can map it to texture space the way, you map your texture. 从那里你可以将它映射到纹理空间,你可以映射你的纹理。

I would not implement it that way. 我不会那样实现它。 I would render the scene to a framebuffer and instead of rendering a texture the the mesh, colorcode the texture coordinate onto the mesh. 我会将场景渲染到帧缓冲区,而不是渲染纹理网格,将纹理坐标颜色编码到网格上。 If i click somewhere in screen space, i can simple read the pixel value from the framebuffer and get the texture coordinate directly. 如果我点击屏幕空间中的某个地方,我可以简单地从帧缓冲区读取像素值并直接获取纹理坐标。 The rendering to the framebuffer should be very inexpensive anyway. 无论如何,对帧缓冲区的渲染应该非常便宜。

Assuming your terrain is a simple rectangle you first calculate the vector between the mouse world position and the origin of your terrain. 假设您的地形是一个简单的矩形,您首先要计算鼠标世界位置和地形原点之间的向量。 (The vertex of your terrain quad where the top left corner of your height map is mapped to). (地形四边形的顶点,高度贴图的左上角将映射到该顶点)。 Eg mouse (50,25) - origin(-100,-100) = (150,125) . 例如mouse (50,25) - origin(-100,-100) = (150,125)
Now divide the x and y coordinates by the world space width and height of your terrain quad. 现在将x和y坐标除以地形四边形的世界空间宽度和高度。
150 / 200 = 0.75 and 125 / 200 = 0.625 . 150 / 200 = 0.75125 / 200 = 0.625 This gives you the texture coordinates, if you need them as pixel coordinates instead simply multiply with the size of your texture. 这为您提供纹理坐标,如果您需要它们作为像素坐标而不是简单地乘以纹理的大小。

I assume the following: 我假设如下:

  1. The world coordinates you computed are those of the mouse pointer within the view frustrum. 您计算的世界坐标是视图frustrum中鼠标指针的坐标。 I name them mouseCoord 我把它们命名为mouseCoord
  2. We also have the camera coordinates, camCoord 我们还有摄像机坐标,camCoord
  3. The world consists of triangles 世界由三角形组成
  4. Each triangle point has texture coordiantes, those are interpolated by barycentric coordinates 每个三角形点都有纹理坐标,这些坐标由重心坐标插值

If so, the solution goes like this: 如果是这样,解决方案是这样的:

  1. use camCoord as origin. 使用camCoord作为原点。 Compute the direction of a ray as mouseCoord - camCoord. 计算光线的方向为mouseCoord - camCoord。
  2. Compute the point of intersection with a triangle. 计算与三角形的交点。 Naive variant is to check for every triangle if it is intersected, more sophisticated would be to rule out several triangles first by some other algorithm, like parting the world in cubes, trace the ray along the cubes and only look at the triangles that have overlappings with the cube. 天真的变体是检查每个三角形是否相交,更复杂的是先用其他算法排除几个三角形,比如在立方体中划分世界,沿立方体追踪光线,只看有重叠的三角形与立方体。 Intersection with a triangle can be computed like on this website: http://www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/ 可以像在这个网站上一样计算三角形的交点: http//www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/
  3. Compute the intersection points barycentric coordinates with respect to that triangle, like that: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates 计算相对于该三角形的交点重心坐标,如: https//www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates
  4. Use the barycentric coordinates as weights for the texture coordinates of the corresponding triangle points. 使用重心坐标作为相应三角形点的纹理坐标的权重。 The result are the texture coordinates of the intersection point, aka what you want. 结果是交叉点的纹理坐标,也就是你想要的。

If I misunderstood what you wanted, please edit your question with additional information. 如果我误解了您的想法,请使用其他信息编辑您的问题。

Another variant specific for a height map: 另一种特定于高度图的变体:

Assumed that the assumptions are changed like that: 假设假设改变如下:

  1. The world has ground tiles over x and y 世界上有x和y的地砖
  2. The ground tiles have height values in their corners 地砖在其角落处具有高度值
  3. For a point within the tile, the height value is interpolated somehow, like by bilinear interpolation. 对于图块内的点,高度值以某种方式进行插值,例如通过双线性插值。
  4. The texture is interpolated in the same way, again with given texture coordinates for the corners 纹理以相同的方式进行插值,同样使用角的给定纹理坐标

A feasible algorithm for that (approximative): 一种可行的算法(近似):

  1. Again, compute origin and direction. 再次,计算原点和方向。
  2. Wlog, we assume that the direction has a higher change in x-direction. Wlog,我们假设方向在x方向上有更高的变化。 If not, exchange x and y in the algorithm. 如果不是,则在算法中交换x和y。
  3. Trace the ray in a given step length for x, that is, in each step, the x-coordinate changes by that step length. 以x的给定步长跟踪光线,也就是说,在每个步骤中,x坐标按该步长变化。 (take the direction, multiply it with step size divided by it's x value, add that new direction to the current position starting at the origin) (取方向,将其乘以步长除以它的x值,将新方向添加到从原点开始的当前位置)
  4. For your current coordinate, check whether it's z value is below the current height (aka has just collided with the ground) 对于当前坐标,检查它的z值是否低于当前高度(也就是刚刚与地面碰撞)
  5. If so, either finish or decrease step size and do a finer search in that vicinity, going backwards until you are above the height again, then maybe go forwards in even finer steps again et cetera. 如果是这样,要么完成或减小步长并在附近进行更精细的搜索,然后向后移动,直到再次高于高度,然后再往前走更精细的步骤等等。 The result are the current x and y coordinates 结果是当前的x和y坐标
  6. Compute the relative position of your x and y coordinates within the current tile. 计算当前切片中x和y坐标的相对位置。 Use that for weights for the corner texture coordinates. 将其用于角落纹理坐标的权重。

This algorithm can theoretically jump over very thin tops. 理论上,该算法可以跳过非常薄的顶部。 Choose a small enough step size to counter that. 选择足够小的步长来对付它。 I cannot give an exact algorithm without knowing what type of interpolation the height map uses. 在不知道高度图使用什么类型的插值的情况下,我无法给出精确的算法。 Might be not the worst idea to create triangles anyway, out of bilinear interpolated coordinates maybe? 无论如何,创建三角形可能不是最糟糕的想法,可能是双线性插值坐标? In any case, the algorithm is good to find the tile in which it collides. 在任何情况下,该算法都很好地找到它碰撞的区块。

Another variant would be to trace the ray over the points at which it's xy-coordinates cross the tile grid and then look if the z coordinate went below the height map. 另一种变体是在xy坐标穿过瓷砖网格的点上跟踪光线,然后查看z坐标是否低于高度图。 Then we know that it collides in this tile. 然后我们就知道它在这个瓷砖中碰撞了。 This could produce a false negative if the height can be bigger inside the tile than at it's edges, as certain forms of interpolation can produce, especially those that consider the neighbour tiles. 如果高度可以在区块内部比在其边缘处更大,则可能产生假阴性,因为某些形式的插值可以产生,尤其是那些考虑相邻区块的插值。 Works just fine with bilinear interpolation, though. 但是,使用双线性插值可以正常工作。

In bilinear interpolation, the exact intersection can be found like that: Take the two (x,y) coordinates at which the grid is crossed by the ray. 在双线性插值中,可以找到精确的交点:采用光线穿过网格的两个(x,y)坐标。 Compute the height of those to retrieve two (x,y,z) coordinates. 计算检索两个(x,y,z)坐标的高度。 Create a line out of them. 用它们创建一条线。 Compute the intersection of that line with the ray. 计算该线与光线的交点。 The intersection of those is that of the intersection with the tile's height map. 那些交叉点是与瓦片高度图的交点。

Simplest way is to render the mesh as a pre-pass with the uvs as the colour. 最简单的方法是将网格渲染为uvs作为颜色的预传。 No screen to world needed. 没有屏幕需要世界。 The uv is the value at the mouse position. uv是鼠标位置的值。 Just be careful though with mips/filtering etv 使用mips /过滤etv时要小心

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM