Problem between tiles
with wire frame would be like this, I prefer use wireframe off because is easy to spot holes where background is white on the black mesh.
The settings I use:
private AppSettingsConfig() { settings = new AppSettings(true); settings.setResolution( Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height ); settings.putInteger("MonitorIndex", 1); settings.setTitle("jMonkeyEngine Game"); settings.setDisplay(1); settings.setFrameRate(-1); settings.setVSync(false); settings.setFrequency(100); settings.setFullscreen(true); settings.setSamples(16); settings.setDepthBits(32); }
After comparing the values of rows and colums of the mesh and use mult instead of add , wich brings precision overtime each iteration. (The other program that creates the 16 bits images add sums in each iteration wich were giving wrong data, using multiplication fixed it)
I had to change the scalar implementation to have the same cpu spets from SIMD pipeline, so it would compute the same numbers, and on the last col or row I use the value of next time instead of doing mutiplications.
static final float PLANET_RADIUS = 6371000f;
static final float STEP = (WorldConfig.TILE_LENGTH / (TILE_PIXELS - 1));
static final VectorSpecies FLOAT_VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
static final VectorSpecies INT_SPECIES = IntVector.SPECIES_PREFERRED;
static final VectorSpecies SHORT_SPECIES = ShortVector.SPECIES_PREFERRED;
static final int TILE_PIXELS_BOUND_SHORT = SHORT_SPECIES.loopBound(WorldConfig.TILE_PIXELS);
static final int F_LENGTH = FLOAT_VECTOR_SPECIES.length();
static final int I_LENGTH = INT_SPECIES.length();
static final int S_LENGTH = SHORT_SPECIES.length();
static final int SHORT_VECTOR_LOOP_BOUND = TILE_PIXELS_BOUND_SHORT - S_LENGTH;
static final int INT_TO_FLOAT_GROUP_RATIO = INT_SPECIES.length() / F_LENGTH;
static final int SHORT_TO_INT_GROUP_RATIO = S_LENGTH / INT_SPECIES.length();
static final int TAIL_START_J = TILE_PIXELS_BOUND_SHORT;
static final int TAIL_LENGTH = TILE_PIXELS - TAIL_START_J;
static final FloatVector INDEX = FloatVector.fromArray(FLOAT_VECTOR_SPECIES, createIndex(), 0).mul(STEP);
static final float HEIGHT_SCALE = 3200.0f / (256f * 256f);
static final FloatVector ONE = FloatVector.broadcast(FLOAT_VECTOR_SPECIES, 1f);
static final float NORMALIZED_HEIGHT_SCALE = HEIGHT_SCALE / PLANET_RADIUS;
static final FloatVector NORMALIZED_HEIGHT_SCALE_VECTOR = FloatVector.broadcast(FLOAT_VECTOR_SPECIES, NORMALIZED_HEIGHT_SCALE);
static final float RADIUS_NORMALIZED_OFFSET = -200f / PLANET_RADIUS + 1f;
static final FloatVector RADIUS_NORMALIZED_OFFSET_VECTOR = FloatVector.broadcast(FLOAT_VECTOR_SPECIES, RADIUS_NORMALIZED_OFFSET);
private static final float
meshData = new float[TILE_PIXELS * TILE_PIXELS * 3];
static final short
shortArray = new short[TAIL_LENGTH];
static final float
tmp = new float[F_LENGTH * 3];
private static final ValueLayout.OfShort OF_SHORT = ValueLayout.JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN);
private static float
createIndex() {
float
a = new float[F_LENGTH];
for (int i = 0; i < F_LENGTH; i++)
a[i] = i;
return a;
}
static float columnCord(short tileCol, int meshCol) {
if (meshCol == TILE_PIXELS - 1) {
return (tileCol + 1) * WorldConfig.TILE_LENGTH - GeoUtils.OFFSET;
}
return tileCol * WorldConfig.TILE_LENGTH - GeoUtils.OFFSET + STEP * meshCol;
}
static float rowCord(short tileRow, int meshRow) {
if (meshRow == TILE_PIXELS - 1) {
return (tileRow + 1) * WorldConfig.TILE_LENGTH - GeoUtils.OFFSET;
}
return tileRow * WorldConfig.TILE_LENGTH - GeoUtils.OFFSET + STEP * meshRow;
}
public static void writePositions(Tile tile) {
TileID tileId = tile.getTileId();
GeoEnum face = tileId.face();
MeshBuffer buffer = tile.getBuffer();
MemorySegment heightMap = HeightMapReader.getInstance().getMapData(tileId);
CubePlane plane = switch (face) {
case TOP, BOTTOM → CubePlane.HORIZONTAL;
case FRONT, BACK → CubePlane.FRONTAL;
case LEFT, RIGHT → CubePlane.PERFIL;
};
writePlane(tileId, tile.start(), heightMap, plane);
buffer.setPositionData(meshData);
}
static void writePlane(TileID tileId, Position3D start, MemorySegment heightMap, CubePlane layout) {
short tileRow = tileId.row();
short tileCol = tileId.col();
float f = layout.fixedBase(start);
FloatVector fixedVec = FloatVector.broadcast(FLOAT_VECTOR_SPECIES, f);
int offset = 0;
for (int i = 0; i < TILE_PIXELS; i++) {
float r = rowCord(tileRow, i);
FloatVector rowVec = FloatVector.broadcast(FLOAT_VECTOR_SPECIES, r);
for (int j = 0; j <= SHORT_VECTOR_LOOP_BOUND; j += S_LENGTH) {
ShortVector heightVec = ShortVector.fromMemorySegment(SHORT_SPECIES, heightMap, ((long) i * TILE_PIXELS + j) * Short.BYTES, ByteOrder.LITTLE_ENDIAN);
for (int k = 0; k < SHORT_TO_INT_GROUP_RATIO; k++) {
IntVector unsigned = (IntVector) heightVec.convertShape(VectorOperators.S2I, INT_SPECIES, k).lanewise(VectorOperators.AND, 0xFFFF);
for (int h = 0; h < INT_TO_FLOAT_GROUP_RATIO; h++) {
int colStart = j + k * I_LENGTH + h * F_LENGTH;
FloatVector colVec = INDEX.add( columnCord(tileCol, colStart));
FloatVector fv = (FloatVector) unsigned.convertShape(VectorOperators.I2F, FLOAT_VECTOR_SPECIES, h);
FloatVector heightVecNormalized = fv.fma(NORMALIZED_HEIGHT_SCALE_VECTOR, RADIUS_NORMALIZED_OFFSET_VECTOR);
FloatVector xVec = layout.wx(fixedVec, rowVec, colVec);
FloatVector yVec = layout.wy(fixedVec, rowVec, colVec);
FloatVector zVec = layout.wz(fixedVec, rowVec, colVec);
FloatVector len = xVec.fma(xVec, yVec.fma(yVec, zVec.mul(zVec)));
FloatVector invLen = ONE.div(len.sqrt()).mul(heightVecNormalized);
FloatVector nx = xVec.mul(invLen);
FloatVector ny = yVec.mul(invLen);
FloatVector nz = zVec.mul(invLen);
nx.intoArray(tmp, 0);
ny.intoArray(tmp, F_LENGTH);
nz.intoArray(tmp, F_LENGTH * 2);
for (int lane = 0; lane < F_LENGTH; lane++) {
meshData[offset++] = tmp[lane];
meshData[offset++] = tmp[lane + F_LENGTH];
meshData[offset++] = tmp[lane + F_LENGTH * 2];
}
}
}
}
long tailOffsetBytes = ((long) i * TILE_PIXELS + TAIL_START_J) * Short.BYTES;
MemorySegment.copy(heightMap, ValueLayout.JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), tailOffsetBytes, shortArray, 0, TAIL_LENGTH);
for (int s = TAIL_START_J; s < TILE_PIXELS; s++) {
float c = columnCord(tileCol, s);
float wx = layout.sx(f, r, c);
float wy = layout.sy(f, r, c);
float wz = layout.sz(f, r, c);
int u = Short.toUnsignedInt(shortArray[s - TAIL_START_J]);
float len = (float) Math.sqrt(Math.fma(wx, wx, Math.fma(wy, wy, wz * wz)));
float height = Math.fma(u, NORMALIZED_HEIGHT_SCALE, RADIUS_NORMALIZED_OFFSET);
float inv = 1f / len * height;
meshData[offset++] = wx * inv;
meshData[offset++] = wy * inv;
meshData[offset++] = wz * inv;
}
}
}
Thanks to all.
Discussion in the ATmosphere