我正在努力制作一个有更好的补丁的山地景观。
我有它确保C1连续性,但它没有成功。
我对该函数的输入虽然是在计算之前生成的,但它是由n x n网格的高度组成的高度图。
然后在我的方法中,我想为每个网格生成16个用于立方贝塞尔补丁的控制字。
但是我无法这样做,因为这导致了奇怪的结果,我的代码:
new PatchIterator(width).forEachRemaining(p -> {
int w = p.first, d = p.second;
Patch patch = new Patch();
boolean lastWidthPatchExists = (w - 1 >= 0 && patches[w - 1][d] != null);
boolean lastDepthPatchExists = (d - 1 >= 0 && patches[w][d - 1] != null);
if (!lastWidthPatchExists && !lastDepthPatchExists) {
patch.createFirstPatch(heightMapping[w][d]);
}
else if (lastWidthPatchExists && !lastDepthPatchExists) {
patch.createWidthConstrainedPatch(heightMapping[w][d], patches[w - 1][d]);
}
else if (!lastWidthPatchExists && lastDepthPatchExists) {
patch.createDepthConstrainedPatch(heightMapping[w][d], patches[w][d - 1]);
}
else {
patch.createWithAndDepthConstrainedPatch(heightMapping[w][d], patches[w - 1][d], patches[w][d - 1]);
}
patch.submitAll(terrainData, w, d);
patches[w][d] = patch;
});
private class Patch {
final float[][] patchData = new float[4][4];
/**
* Creates the first patch, which is not constrained to anything else.
*
* @param height The desired height for the patch
*/
void createFirstPatch(final float height) {
loop((x, z) -> {
patchData[x][z] = height;
});
}
/**
* Creates a patch that is constrained by the previous patch in width, this guarantees C1-continuity of the Bezier Surface.
*
* @param height The desired height for the patch
* @param lastWidthPatch The last patch in the width direction
*/
void createWidthConstrainedPatch(final float height, final Patch lastWidthPatch) {
loop((x, z) -> {
float y;
if (x == 0) {
//First point should be the same as the last point of the previous patch (C0-continuity)
y = lastWidthPatch.patchData[3][z];
}
else if (x == 1) {
//The three points (previous patch last two and current patch first two) should be on a line (C1-continuity)
float previousDifference = lastWidthPatch.patchData[3][z] - lastWidthPatch.patchData[2][z];
y = lastWidthPatch.patchData[3][z] + previousDifference;
}
else {
//No constraints apply to these points
y = height;
}
patchData[x][z] = y;
});
}
/**
* Creates a patch that is constrained by the previous patch in depth, this guarantees C1-continuity of the Bezier Surface.
*
* @param height The desired height for the patch
* @param lastDepthPatch The last patch in the depth direction
*/
void createDepthConstrainedPatch(final float height, final Patch lastDepthPatch) {
float[] yValues = new float[4];
Arrays.fill(yValues, 0f);
loop((x, z) -> {
float y;
if (z == 0) {
//First point should be the same as the last point of the previous patch (C0-continuity)
y = lastDepthPatch.patchData[x][3];
}
else if (z == 1) {
//The three points (previous patch last two and current patch first two) should be on a line (C1-continuity)
float previousDifference = lastDepthPatch.patchData[x][3] - lastDepthPatch.patchData[x][2];
y = lastDepthPatch.patchData[x][3] + previousDifference;
}
else {
//No constraints apply to these points
y = height;
}
patchData[x][z] = y;
});
}
/**
* Creates a patch that is constrained by the previous patch in depth, this guarantees C1-continuity of the Bezier Surface.
*
* @param height The desired height for the patch
* @param lastWidthPatch The last patch in the width direction
* @param lastDepthPatch The last patch in the depth direction
*/
void createWithAndDepthConstrainedPatch(final float height, final Patch lastWidthPatch, final Patch lastDepthPatch) {
loop((x, z) -> {
float y;
if (x == 0) {
//First point should be the same as the last point of the previous width patch (C0-continuity)
y = lastWidthPatch.patchData[3][z];
}
else if (z == 0) {
//First point should be the same as the last point of the previous depth patch (C0-continuity)
y = lastDepthPatch.patchData[x][3];
}
else if (x == 1) {
//TODO I think that x, z == 1 should be a seperate case
//The three points (previous width patch last two and current width patch first two) should be on a line (C1-continuity)
float previousDifference = lastWidthPatch.patchData[3][z] - lastWidthPatch.patchData[2][z];
y = lastWidthPatch.patchData[3][z] + previousDifference;
}
else if (z == 1) {
//The three points (previous depth patch last two and current depth patch first two) should be on a line (C1-continuity)
float previousDifference = lastDepthPatch.patchData[x][3] - lastDepthPatch.patchData[x][2];
y = lastDepthPatch.patchData[x][3] + previousDifference;
}
else {
//No constraints apply to these points
y = height;
}
patchData[x][z] = y;
});
}
void submitAll(final FloatBuffer data, final int width, final int depth) {
loop((x, z) -> {
int datax = x + (width * 3);
int dataz = z + (depth * 3);
data.put(datax).put(patchData[x][z]).put(dataz);
});
}
void loop(final BiConsumer<Integer, Integer> consumer) {
for (int x = 0; x < 4; x++) {
for (int z = 0; z < 4; z++) {
consumer.accept(x, z);
}
}
}
}
这些是最相关的,任何人都可以通过提示来帮助我吗? 另外,有没有专门设计用于处理此问题的算法?