diff --git a/src/client/java/su/divan2000/veila/client/render/fog/FogChunkStreamer.java b/src/client/java/su/divan2000/veila/client/render/fog/FogChunkStreamer.java index 585770b..8272357 100644 --- a/src/client/java/su/divan2000/veila/client/render/fog/FogChunkStreamer.java +++ b/src/client/java/su/divan2000/veila/client/render/fog/FogChunkStreamer.java @@ -23,6 +23,7 @@ public final class FogChunkStreamer { // Битовые маски вместо массивов статусов private static final AtomicLongArray pendingMask = new AtomicLongArray(TOTAL_WORDS); private static final AtomicLongArray readyMask = new AtomicLongArray(TOTAL_WORDS); + private static final Object sharedStateLock = new Object(); // Pre-allocated массивы данных private static final byte[][] preparedData = new byte[TOTAL_CHUNKS][CHUNK_DATA_SIZE]; @@ -130,66 +131,68 @@ public final class FogChunkStreamer { int newOriginChunkX, int newOriginChunkZ, int ringChunkOffsetX, int ringChunkOffsetZ ) { - currentOriginChunkX = newOriginChunkX; - currentOriginChunkZ = newOriginChunkZ; - currentRingChunkOffsetX = ringChunkOffsetX; - currentRingChunkOffsetZ = ringChunkOffsetZ; + synchronized (sharedStateLock) { + currentOriginChunkX = newOriginChunkX; + currentOriginChunkZ = newOriginChunkZ; + currentRingChunkOffsetX = ringChunkOffsetX; + currentRingChunkOffsetZ = ringChunkOffsetZ; - if (firstUpdate) { - markAllPending(); - firstUpdate = false; - return; + if (firstUpdate) { + markAllPending(); + firstUpdate = false; + return; + } + + int dx = newOriginChunkX - oldOriginChunkX; + int dz = newOriginChunkZ - oldOriginChunkZ; + + if (dx == 0 && dz == 0) { + return; + } + + if (Math.abs(dx) >= FogWorldVolume.CHUNKS_X || + Math.abs(dz) >= FogWorldVolume.CHUNKS_Z) { + markAllPending(); + return; + } + + regionCount = 0; + + if (dx > 0) { + int worldX = newOriginChunkX + FogWorldVolume.CHUNKS_X - dx; + int worldZ = newOriginChunkZ; + collectRegions(worldX, worldZ, dx, FogWorldVolume.CHUNKS_Z); + markPendingRange(worldX, worldZ, dx, FogWorldVolume.CHUNKS_Z); + } + + if (dx < 0) { + int worldX = newOriginChunkX; + int worldZ = newOriginChunkZ; + collectRegions(worldX, worldZ, -dx, FogWorldVolume.CHUNKS_Z); + markPendingRange(worldX, worldZ, -dx, FogWorldVolume.CHUNKS_Z); + } + + if (dz > 0) { + int worldX = newOriginChunkX; + int worldZ = newOriginChunkZ + FogWorldVolume.CHUNKS_Z - dz; + collectRegions(worldX, worldZ, FogWorldVolume.CHUNKS_X, dz); + markPendingRange(worldX, worldZ, FogWorldVolume.CHUNKS_X, dz); + } + + if (dz < 0) { + int worldX = newOriginChunkX; + int worldZ = newOriginChunkZ; + collectRegions(worldX, worldZ, FogWorldVolume.CHUNKS_X, -dz); + markPendingRange(worldX, worldZ, FogWorldVolume.CHUNKS_X, -dz); + } + + if (regionCount > 0) { + FogWorldVolume.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount); + FogDensityTextures.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount); + } + + uploadReadyData(); } - - int dx = newOriginChunkX - oldOriginChunkX; - int dz = newOriginChunkZ - oldOriginChunkZ; - - if (dx == 0 && dz == 0) { - return; - } - - if (Math.abs(dx) >= FogWorldVolume.CHUNKS_X || - Math.abs(dz) >= FogWorldVolume.CHUNKS_Z) { - markAllPending(); - return; - } - - regionCount = 0; - - if (dx > 0) { - int worldX = newOriginChunkX + FogWorldVolume.CHUNKS_X - dx; - int worldZ = newOriginChunkZ; - collectRegions(worldX, worldZ, dx, FogWorldVolume.CHUNKS_Z); - markPendingRange(worldX, worldZ, dx, FogWorldVolume.CHUNKS_Z); - } - - if (dx < 0) { - int worldX = newOriginChunkX; - int worldZ = newOriginChunkZ; - collectRegions(worldX, worldZ, -dx, FogWorldVolume.CHUNKS_Z); - markPendingRange(worldX, worldZ, -dx, FogWorldVolume.CHUNKS_Z); - } - - if (dz > 0) { - int worldX = newOriginChunkX; - int worldZ = newOriginChunkZ + FogWorldVolume.CHUNKS_Z - dz; - collectRegions(worldX, worldZ, FogWorldVolume.CHUNKS_X, dz); - markPendingRange(worldX, worldZ, FogWorldVolume.CHUNKS_X, dz); - } - - if (dz < 0) { - int worldX = newOriginChunkX; - int worldZ = newOriginChunkZ; - collectRegions(worldX, worldZ, FogWorldVolume.CHUNKS_X, -dz); - markPendingRange(worldX, worldZ, FogWorldVolume.CHUNKS_X, -dz); - } - - if (regionCount > 0) { - FogWorldVolume.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount); - FogDensityTextures.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount); - } - - uploadReadyData(); } private static void markPendingRange(int worldX, int worldZ, int countX, int countZ) { @@ -305,75 +308,79 @@ public final class FogChunkStreamer { } public static void processPending() { - int originX = currentOriginChunkX; - int originZ = currentOriginChunkZ; - int ringOffsetX = currentRingChunkOffsetX; - int ringOffsetZ = currentRingChunkOffsetZ; + synchronized (sharedStateLock) { + int originX = currentOriginChunkX; + int originZ = currentOriginChunkZ; + int ringOffsetX = currentRingChunkOffsetX; + int ringOffsetZ = currentRingChunkOffsetZ; - int processedCount = 0; - int index = 0; + int processedCount = 0; + int index = 0; - int limit = MAX_CHUNKS_PER_TICK + (burstFrames > 0 ? MAX_CHUNKS_PER_TICK : 0); + int limit = MAX_CHUNKS_PER_TICK + (burstFrames > 0 ? MAX_CHUNKS_PER_TICK : 0); - while (processedCount < limit) { - index = nextSetBit(pendingMask, index); - if (index < 0) break; + while (processedCount < limit) { + index = nextSetBit(pendingMask, index); + if (index < 0) break; - int physicalX = index % FogWorldVolume.CHUNKS_X; - int physicalZ = index / FogWorldVolume.CHUNKS_X; + int physicalX = index % FogWorldVolume.CHUNKS_X; + int physicalZ = index / FogWorldVolume.CHUNKS_X; - int worldChunkX = originX + floorMod(physicalX - ringOffsetX, FogWorldVolume.CHUNKS_X); - int worldChunkZ = originZ + floorMod(physicalZ - ringOffsetZ, FogWorldVolume.CHUNKS_Z); + int worldChunkX = originX + floorMod(physicalX - ringOffsetX, FogWorldVolume.CHUNKS_X); + int worldChunkZ = originZ + floorMod(physicalZ - ringOffsetZ, FogWorldVolume.CHUNKS_Z); - if (FogChunkProvider.fillChunkIntoArray(worldChunkX, worldChunkZ, preparedData[index])) { - preparedWorldChunkX[index] = worldChunkX; - preparedWorldChunkZ[index] = worldChunkZ; - setBit(readyMask, index); - clearBit(pendingMask, index); - processedCount++; + if (FogChunkProvider.fillChunkIntoArray(worldChunkX, worldChunkZ, preparedData[index])) { + preparedWorldChunkX[index] = worldChunkX; + preparedWorldChunkZ[index] = worldChunkZ; + setBit(readyMask, index); + clearBit(pendingMask, index); + processedCount++; + } + index++; } - index++; + if (burstFrames > 0) burstFrames--; } - if (burstFrames > 0) burstFrames--; } public static void uploadReadyData() { - int originX = currentOriginChunkX; - int originZ = currentOriginChunkZ; - int ringOffsetX = currentRingChunkOffsetX; - int ringOffsetZ = currentRingChunkOffsetZ; + synchronized (sharedStateLock) { + int originX = currentOriginChunkX; + int originZ = currentOriginChunkZ; + int ringOffsetX = currentRingChunkOffsetX; + int ringOffsetZ = currentRingChunkOffsetZ; - int processed = 0; - int index = 0; + int processed = 0; + int index = 0; - int limit = MAX_READY_CHUNK_UPLOADS_PER_TICK + (burstFrames > 0 ? MAX_READY_CHUNK_UPLOADS_PER_TICK : 0); + int limit = MAX_READY_CHUNK_UPLOADS_PER_TICK + (burstFrames > 0 ? MAX_READY_CHUNK_UPLOADS_PER_TICK : 0); - FogWorldVolume.beginUpload(); - while (processed < limit) { - index = nextSetBit(readyMask, index); - if (index < 0) break; + FogWorldVolume.beginUpload(); + while (processed < limit) { + index = nextSetBit(readyMask, index); + if (index < 0) break; - int physicalX = index % FogWorldVolume.CHUNKS_X; - int physicalZ = index / FogWorldVolume.CHUNKS_X; + int physicalX = index % FogWorldVolume.CHUNKS_X; + int physicalZ = index / FogWorldVolume.CHUNKS_X; - int currentWorldX = originX + floorMod(physicalX - ringOffsetX, FogWorldVolume.CHUNKS_X); - int currentWorldZ = originZ + floorMod(physicalZ - ringOffsetZ, FogWorldVolume.CHUNKS_Z); + int currentWorldX = originX + floorMod(physicalX - ringOffsetX, FogWorldVolume.CHUNKS_X); + int currentWorldZ = originZ + floorMod(physicalZ - ringOffsetZ, FogWorldVolume.CHUNKS_Z); - if (preparedWorldChunkX[index] == currentWorldX && - preparedWorldChunkZ[index] == currentWorldZ) { + if (preparedWorldChunkX[index] == currentWorldX && + preparedWorldChunkZ[index] == currentWorldZ) { - FogWorldVolume.uploadChunkFromArrayNoBind(physicalX, physicalZ, preparedData[index]); - clearBit(readyMask, index); - processed++; - } else { - // Координаты изменились — помечаем как pending заново - clearBit(readyMask, index); - setBit(pendingMask, index); + FogWorldVolume.uploadChunkFromArrayNoBind(physicalX, physicalZ, preparedData[index]); + clearBit(readyMask, index); + processed++; + } else { + // Координаты изменились — помечаем как pending заново + clearBit(readyMask, index); + setBit(pendingMask, index); + } + index++; } - index++; + FogWorldVolume.endUpload(); + if (burstFrames > 0) burstFrames--; } - FogWorldVolume.endUpload(); - if (burstFrames > 0) burstFrames--; } public static void setBurst(int frames) { diff --git a/src/client/java/su/divan2000/veila/client/render/fog/FogLightStreamer.java b/src/client/java/su/divan2000/veila/client/render/fog/FogLightStreamer.java index 076bc95..bacb0fb 100644 --- a/src/client/java/su/divan2000/veila/client/render/fog/FogLightStreamer.java +++ b/src/client/java/su/divan2000/veila/client/render/fog/FogLightStreamer.java @@ -18,6 +18,7 @@ public final class FogLightStreamer { private static final AtomicLongArray readySkyMask = new AtomicLongArray(TOTAL_WORDS); private static final AtomicLongArray initialBlockMask = new AtomicLongArray(TOTAL_WORDS); private static final AtomicLongArray initialSkyMask = new AtomicLongArray(TOTAL_WORDS); + private static final Object sharedStateLock = new Object(); // Flat массивы для мировых координат private static final int[] preparedBlockWorldX = new int[TOTAL_SECTIONS]; @@ -159,50 +160,52 @@ public final class FogLightStreamer { int newOriginChunkX, int newOriginChunkZ, int ringChunkOffsetX, int ringChunkOffsetZ ) { - currentOriginChunkX = newOriginChunkX; - currentOriginChunkZ = newOriginChunkZ; - currentRingChunkOffsetX = ringChunkOffsetX; - currentRingChunkOffsetZ = ringChunkOffsetZ; + synchronized (sharedStateLock) { + currentOriginChunkX = newOriginChunkX; + currentOriginChunkZ = newOriginChunkZ; + currentRingChunkOffsetX = ringChunkOffsetX; + currentRingChunkOffsetZ = ringChunkOffsetZ; - if (firstUpdate) { - markAllPending(); - firstUpdate = false; - return; - } + if (firstUpdate) { + markAllPending(); + firstUpdate = false; + return; + } - int dx = newOriginChunkX - oldOriginChunkX; - int dz = newOriginChunkZ - oldOriginChunkZ; + int dx = newOriginChunkX - oldOriginChunkX; + int dz = newOriginChunkZ - oldOriginChunkZ; - if (dx == 0 && dz == 0) return; + if (dx == 0 && dz == 0) return; - if (Math.abs(dx) >= FogLightVolume.CHUNKS_X || Math.abs(dz) >= FogLightVolume.CHUNKS_Z) { - markAllPending(); - return; - } + if (Math.abs(dx) >= FogLightVolume.CHUNKS_X || Math.abs(dz) >= FogLightVolume.CHUNKS_Z) { + markAllPending(); + return; + } - regionCount = 0; + regionCount = 0; - if (dx > 0) { - int worldX = newOriginChunkX + FogLightVolume.CHUNKS_X - dx; - collectRegions(worldX, newOriginChunkZ, dx, FogLightVolume.CHUNKS_Z); - addInitialLoadForRange(worldX, newOriginChunkZ, dx, FogLightVolume.CHUNKS_Z); - } - if (dx < 0) { - collectRegions(newOriginChunkX, newOriginChunkZ, -dx, FogLightVolume.CHUNKS_Z); - addInitialLoadForRange(newOriginChunkX, newOriginChunkZ, -dx, FogLightVolume.CHUNKS_Z); - } - if (dz > 0) { - int worldZ = newOriginChunkZ + FogLightVolume.CHUNKS_Z - dz; - collectRegions(newOriginChunkX, worldZ, FogLightVolume.CHUNKS_X, dz); - addInitialLoadForRange(newOriginChunkX, worldZ, FogLightVolume.CHUNKS_X, dz); - } - if (dz < 0) { - collectRegions(newOriginChunkX, newOriginChunkZ, FogLightVolume.CHUNKS_X, -dz); - addInitialLoadForRange(newOriginChunkX, newOriginChunkZ, FogLightVolume.CHUNKS_X, -dz); - } + if (dx > 0) { + int worldX = newOriginChunkX + FogLightVolume.CHUNKS_X - dx; + collectRegions(worldX, newOriginChunkZ, dx, FogLightVolume.CHUNKS_Z); + addInitialLoadForRange(worldX, newOriginChunkZ, dx, FogLightVolume.CHUNKS_Z); + } + if (dx < 0) { + collectRegions(newOriginChunkX, newOriginChunkZ, -dx, FogLightVolume.CHUNKS_Z); + addInitialLoadForRange(newOriginChunkX, newOriginChunkZ, -dx, FogLightVolume.CHUNKS_Z); + } + if (dz > 0) { + int worldZ = newOriginChunkZ + FogLightVolume.CHUNKS_Z - dz; + collectRegions(newOriginChunkX, worldZ, FogLightVolume.CHUNKS_X, dz); + addInitialLoadForRange(newOriginChunkX, worldZ, FogLightVolume.CHUNKS_X, dz); + } + if (dz < 0) { + collectRegions(newOriginChunkX, newOriginChunkZ, FogLightVolume.CHUNKS_X, -dz); + addInitialLoadForRange(newOriginChunkX, newOriginChunkZ, FogLightVolume.CHUNKS_X, -dz); + } - if (regionCount > 0) { - FogLightVolume.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount); + if (regionCount > 0) { + FogLightVolume.clearRegions(regionPhysX, regionPhysZ, regionWidth, regionDepth, regionCount); + } } } @@ -290,90 +293,94 @@ public final class FogLightStreamer { * обрабатываем и initial, и pending параллельно, чтобы избежать пиков. */ public static void prepareAllSections() { - int processedBlock = 0; - int processedSky = 0; + synchronized (sharedStateLock) { + int processedBlock = 0; + int processedSky = 0; - // Чередование: немного initial block, немного pending block, - // немного initial sky, немного pending sky - int index = 0; - int initialLimit = MAX_INITIAL_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_INITIAL_SECTIONS_PER_TICK : 0); - while (processedBlock < initialLimit) { - index = nextSetBit(initialBlockMask, index); - if (index < 0) break; - if (prepareBlockLight(index)) { - clearBit(initialBlockMask, index); - processedBlock++; + // Чередование: немного initial block, немного pending block, + // немного initial sky, немного pending sky + int index = 0; + int initialLimit = MAX_INITIAL_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_INITIAL_SECTIONS_PER_TICK : 0); + while (processedBlock < initialLimit) { + index = nextSetBit(initialBlockMask, index); + if (index < 0) break; + if (prepareBlockLight(index)) { + clearBit(initialBlockMask, index); + processedBlock++; + } + index++; } - index++; - } - index = 0; - int pendingLimit = MAX_INITIAL_SECTIONS_PER_TICK + MAX_PENDING_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_PENDING_SECTIONS_PER_TICK : 0); - while (processedBlock < pendingLimit) { - index = nextSetBit(pendingBlockMask, index); - if (index < 0) break; - if (prepareBlockLight(index)) { - clearBit(pendingBlockMask, index); - processedBlock++; + index = 0; + int pendingLimit = MAX_INITIAL_SECTIONS_PER_TICK + MAX_PENDING_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_PENDING_SECTIONS_PER_TICK : 0); + while (processedBlock < pendingLimit) { + index = nextSetBit(pendingBlockMask, index); + if (index < 0) break; + if (prepareBlockLight(index)) { + clearBit(pendingBlockMask, index); + processedBlock++; + } + index++; } - index++; - } - index = 0; - int initialSkyLimit = MAX_INITIAL_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_INITIAL_SECTIONS_PER_TICK : 0); - while (processedSky < initialSkyLimit) { - index = nextSetBit(initialSkyMask, index); - if (index < 0) break; - if (prepareSkyLight(index)) { - clearBit(initialSkyMask, index); - processedSky++; + index = 0; + int initialSkyLimit = MAX_INITIAL_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_INITIAL_SECTIONS_PER_TICK : 0); + while (processedSky < initialSkyLimit) { + index = nextSetBit(initialSkyMask, index); + if (index < 0) break; + if (prepareSkyLight(index)) { + clearBit(initialSkyMask, index); + processedSky++; + } + index++; } - index++; - } - index = 0; - int pendingSkyLimit = MAX_INITIAL_SECTIONS_PER_TICK + MAX_PENDING_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_PENDING_SECTIONS_PER_TICK : 0); - while (processedSky < pendingSkyLimit) { - index = nextSetBit(pendingSkyMask, index); - if (index < 0) break; - if (prepareSkyLight(index)) { - clearBit(pendingSkyMask, index); - processedSky++; + index = 0; + int pendingSkyLimit = MAX_INITIAL_SECTIONS_PER_TICK + MAX_PENDING_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_PENDING_SECTIONS_PER_TICK : 0); + while (processedSky < pendingSkyLimit) { + index = nextSetBit(pendingSkyMask, index); + if (index < 0) break; + if (prepareSkyLight(index)) { + clearBit(pendingSkyMask, index); + processedSky++; + } + index++; } - index++; + if (burstFrames > 0) burstFrames--; } - if (burstFrames > 0) burstFrames--; } public static void uploadReadySections() { - int processedBlock = 0; - int processedSky = 0; - int index = 0; - FogLightVolume.beginUpload(FogLightVolume.getBlockLightTexture()); - int blockLimit = MAX_READY_BLOCK_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_READY_BLOCK_SECTIONS_PER_TICK : 0); - while (processedBlock < blockLimit) { - index = nextSetBit(readyBlockMask, index); - if (index < 0) break; - if (uploadBlockLight(index)) { - processedBlock++; + synchronized (sharedStateLock) { + int processedBlock = 0; + int processedSky = 0; + int index = 0; + FogLightVolume.beginUpload(FogLightVolume.getBlockLightTexture()); + int blockLimit = MAX_READY_BLOCK_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_READY_BLOCK_SECTIONS_PER_TICK : 0); + while (processedBlock < blockLimit) { + index = nextSetBit(readyBlockMask, index); + if (index < 0) break; + if (uploadBlockLight(index)) { + processedBlock++; + } + index++; } - index++; - } - FogLightVolume.endUpload(); + FogLightVolume.endUpload(); - index = 0; - FogLightVolume.beginUpload(FogLightVolume.getSkyLightTexture()); - int skyLimit = MAX_READY_SKY_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_READY_SKY_SECTIONS_PER_TICK : 0); - while (processedSky < skyLimit) { - index = nextSetBit(readySkyMask, index); - if (index < 0) break; - if (uploadSkyLight(index)) { - processedSky++; + index = 0; + FogLightVolume.beginUpload(FogLightVolume.getSkyLightTexture()); + int skyLimit = MAX_READY_SKY_SECTIONS_PER_TICK + (burstFrames > 0 ? MAX_READY_SKY_SECTIONS_PER_TICK : 0); + while (processedSky < skyLimit) { + index = nextSetBit(readySkyMask, index); + if (index < 0) break; + if (uploadSkyLight(index)) { + processedSky++; + } + index++; } - index++; + FogLightVolume.endUpload(); + if (burstFrames > 0) burstFrames--; } - FogLightVolume.endUpload(); - if (burstFrames > 0) burstFrames--; } public static void setBurst(int frames) { diff --git a/src/client/java/su/divan2000/veila/client/render/fog/FogWorldVolume.java b/src/client/java/su/divan2000/veila/client/render/fog/FogWorldVolume.java index 75c8cbd..25b051e 100644 --- a/src/client/java/su/divan2000/veila/client/render/fog/FogWorldVolume.java +++ b/src/client/java/su/divan2000/veila/client/render/fog/FogWorldVolume.java @@ -42,8 +42,9 @@ public final class FogWorldVolume { // PBO для быстрой очистки регионов private static int clearPBO = -1; - // PBO для загрузки чанков - private static int uploadPBO = -1; + // Ring of PBOs for chunk uploads to avoid overwriting a buffer while the GPU is still using it + private static final int[] uploadPBOs = new int[3]; + private static int uploadPBOIndex = 0; private static final int MAX_CLEAR_SIZE = SIZE_X * SIZE_Y * SIZE_Z; private FogWorldVolume() { @@ -213,10 +214,11 @@ public final class FogWorldVolume { int textureChunkZ, byte[] data ) { - // Use PBO to upload without stalling the driver - if (uploadPBO != -1) { - GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, uploadPBO); - // Orphan and allocate + // Use a ring of PBOs so one upload never overwrites another still pending on the GPU + if (uploadPBOs[0] != 0) { + int pbo = uploadPBOs[uploadPBOIndex % uploadPBOs.length]; + uploadPBOIndex++; + GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, pbo); GL15.glBufferData(GL31.GL_PIXEL_UNPACK_BUFFER, CHUNK_SIZE * SIZE_Y * CHUNK_SIZE, GL15.GL_STREAM_DRAW); ByteBuffer mapped = GL15.glMapBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, GL15.GL_WRITE_ONLY); if (mapped != null) { @@ -263,10 +265,11 @@ public final class FogWorldVolume { } private static void initUploadPBO() { - if (uploadPBO != -1) return; - uploadPBO = GL15.glGenBuffers(); - GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, uploadPBO); - GL15.glBufferData(GL31.GL_PIXEL_UNPACK_BUFFER, CHUNK_SIZE * SIZE_Y * CHUNK_SIZE, GL15.GL_STREAM_DRAW); + for (int i = 0; i < uploadPBOs.length; i++) { + uploadPBOs[i] = GL15.glGenBuffers(); + GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, uploadPBOs[i]); + GL15.glBufferData(GL31.GL_PIXEL_UNPACK_BUFFER, CHUNK_SIZE * SIZE_Y * CHUNK_SIZE, GL15.GL_STREAM_DRAW); + } GL15.glBindBuffer(GL31.GL_PIXEL_UNPACK_BUFFER, 0); } diff --git a/src/client/resources/assets/veila/shaders/fog_raymarching.frag b/src/client/resources/assets/veila/shaders/fog_raymarching.frag index 771fc4c..0091bb5 100644 --- a/src/client/resources/assets/veila/shaders/fog_raymarching.frag +++ b/src/client/resources/assets/veila/shaders/fog_raymarching.frag @@ -43,7 +43,7 @@ const float SCATTERING_COEFF = 1.0; const float AMBIENT_INTENSITY = 0.10; const float MIN_TRANSMITTANCE = 0.01; -const float AMBIENT_FOG = 0.01; +const float AMBIENT_FOG = 0.0025; //------------------------------------------------------------ @@ -99,7 +99,7 @@ float density(vec3 worldPos) { vec3 uv = worldToUV(worldPos); if (uv.x < 0.0) return 0.0; - return max(texture(BlockLightVolume, uv).r, 1.0-texture(SkyLightVolume, uv).r)*0.1; + return max(texture(FogVolume, uv).r, AMBIENT_FOG*texture(SkyLightVolume, uv).r); } vec2 light(vec3 worldPos)