Java 使用三次bezier样条曲线渲染平滑地形?
我正在尝试用贝塞尔补丁制作一幅山地景观 我这样做是为了确保C1的连续性,但它就是不起作用 作为函数的输入,虽然它是在计算之前生成的,但它是一个由nxn网格高度组成的高度图。Java 使用三次bezier样条曲线渲染平滑地形?,java,algorithm,graphics,bezier,spline,Java,Algorithm,Graphics,Bezier,Spline,我正在尝试用贝塞尔补丁制作一幅山地景观 我这样做是为了确保C1的连续性,但它就是不起作用 作为函数的输入,虽然它是在计算之前生成的,但它是一个由nxn网格高度组成的高度图。 然后在我的方法中,我想为每个网格生成16个立方体贝塞尔面片控制桥 但是,我不能这样做,因为这会导致奇怪的结果,我的代码: new PatchIterator(width).forEachRemaining(p -> { int w = p.first, d = p.second;
然后在我的方法中,我想为每个网格生成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);
}
}
}
}
新的PatchIterator(宽度)。ForEachLeving(p->{
int w=p.first,d=p.second;
补丁=新补丁();
布尔值lastWidthPatchExists=(w-1>=0&&patchs[w-1][d]!=null);
布尔值lastDepthPatchExists=(d-1>=0&&patches[w][d-1]!=null);
如果(!lastWidthPatchExists&!lastDepthPatchExists){
createFirstPatch(高度映射[w][d]);
}
else if(lastWidthPatchExists&!lastDepthPatchExists){
createWidthConstrainedPatch(高度映射[w][d],面片[w-1][d]);
}
如果(!lastWidthPatchExists&&lastDepthPatchExists)存在,则为else{
createDepthConstrainedPatch(高度映射[w][d],面片[w][d-1]);
}
否则{
createWithAndDepthConstrainedPatch(高度映射[w][d]、面片[w-1][d]、面片[w][d-1]);
}
亚高大斑块(水螅目,w,d);
贴片[w][d]=贴片;
});
私有类补丁{
最终浮点[][]patchData=新浮点[4][4];
/**
*创建第一个面片,该面片不受任何其他约束。
*
*@param height修补程序所需的高度
*/
void createFirstPatch(最终浮动高度){
循环((x,z)->{
patchData[x][z]=高度;
});
}
/**
*创建受上一个面片宽度约束的面片,这保证了Bezier曲面的C1连续性。
*
*@param height修补程序所需的高度
*@param lastWidthPatch宽度方向上的最后一个面片
*/
void createWidthConstrainedPatch(最终浮动高度,最终面片lastWidthPatch){
循环((x,z)->{
浮动y;
如果(x==0){
//第一个点应与上一个贴片的最后一个点相同(C0连续性)
y=lastWidthPatch.patchData[3][z];
}
else如果(x==1){
//三个点(前一个补片最后两个和当前补片前两个)应在一条线上(C1连续性)
float-previousDifference=lastWidthPatch.patchData[3][z]-lastWidthPatch.patchData[2][z];
y=lastWidthPatch.patchData[3][z]+上一个差值;
}
否则{
//这些点不受任何约束
y=高度;
}
patchData[x][z]=y;
});
}
/**
*创建受上一个面片深度约束的面片,这保证了Bezier曲面的C1连续性。
*
*@param height修补程序所需的高度
*@param lastDepthPatch深度方向上的最后一个补丁
*/
void createDepthConstrainedPatch(最终浮动高度,最终面片lastDepthPatch){
浮动[]Y值=新浮动[4];
数组。填充(y值,0f);
循环((x,z)->{
浮动y;
如果(z==0){
//第一个点应与上一个贴片的最后一个点相同(C0连续性)
y=lastDepthPatch.patchData[x][3];
}
else如果(z==1){
//三个点(前一个补片最后两个和当前补片前两个)应在一条线上(C1连续性)
float-previousDifference=lastDepthPatch.patchData[x][3]-lastDepthPatch.patchData[x][2];
y=lastDepthPatch.patchData[x][3]+上一个差值;
}
否则{
//这些点不受任何约束
y=高度;
}
patchData[x][z]=y;
});
}
/**
*创建受上一个面片深度约束的面片,这保证了Bezier曲面的C1连续性。
*
*@param height修补程序所需的高度
*@param lastWidthPatch宽度方向上的最后一个面片
*@param lastDepthPatch深度方向上的最后一个补丁
*/
void createWithAndDepthConstrainedPatch(最终浮动高度、最终面片lastWidthPatch、最终面片lastDepthPatch){
循环((x,z)->{
浮动y;
如果(x==0){
//第一个点应与上一个宽度面片的最后一个点相同(C0连续性)
y=lastWidthPatch.patchData[3][z];
}
else如果(z==0){
//第一个点应与上一个深度面片的最后一个点相同(C0连续性)
y=lastDepthPatch.patchData[x][3];
}
else如果(x==1){
//我认为x,z==1应该是一个单独的例子
//三个点(前一个宽度补片最后两个和当前宽度补片前两个)应在一条线上(C1连续性)
float-previousDifference=lastWidthPatch.patchData[3][z]-lastWidthPatch.patchData[2][z];
y=lastWidthPatch.patchData[3][z]+上一个差值;
}
else如果(z==1){
//三个点(前一个深度片最后两个和当前深度片前两个)应在一条线上(C1连续性)
float-previousDifference=lastDepthPatch.patchData[x][3]-lastDepthPatch.patchData[x][2];
y=lastDepthPatch.patchData[x][3]+上一个差值;
}
否则{
//这些点不受任何约束