Skip to content

Commit e2b7309

Browse files
committed
Merge PR #1542 by @emanuele3d - more rendering work
2 parents 0d96c33 + a4af343 commit e2b7309

File tree

5 files changed

+78
-74
lines changed

5 files changed

+78
-74
lines changed

engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public interface RenderableWorld {
3434
boolean updateChunksInProximity(Region3i renderableRegion);
3535
boolean updateChunksInProximity(ViewDistance viewDistance);
3636

37-
int updateAndQueueVisibleChunks(boolean isFirstRenderingStageForCurrentFrame);
37+
void generateVBOs();
38+
int queueVisibleChunks(boolean isFirstRenderingStageForCurrentFrame);
3839

3940
void dispose();
4041

engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public class RenderableWorldImpl implements RenderableWorld {
5757
private static final Logger logger = LoggerFactory.getLogger(RenderableWorldImpl.class);
5858

5959
private final int maxChunksForShadows = TeraMath.clamp(CoreRegistry.get(Config.class).getRendering().getMaxChunksUsedForShadowMapping(), 64, 1024);
60-
private final int verticalChunkMeshSegements = CoreRegistry.get(Config.class).getSystem().getVerticalChunkMeshSegments();
61-
private final int chunkYsizeToSegmentsRatio = ChunkConstants.SIZE_Y / verticalChunkMeshSegements;
60+
private final int verticalChunkMeshSegments = CoreRegistry.get(Config.class).getSystem().getVerticalChunkMeshSegments();
61+
private final int chunkYsizeToSegmentsRatio = ChunkConstants.SIZE_Y / verticalChunkMeshSegments;
6262

6363
private final WorldProvider worldProvider;
6464
private ChunkProvider chunkProvider;
@@ -131,7 +131,7 @@ public boolean pregenerateChunks() {
131131
chunkProvider.beginUpdate();
132132

133133
RenderableChunk chunk;
134-
ChunkMesh[] newMesh = new ChunkMesh[verticalChunkMeshSegements];
134+
ChunkMesh[] newMesh = new ChunkMesh[verticalChunkMeshSegments];
135135
ChunkView localView;
136136
for (Vector3i chunkCoordinates : calculateRenderableRegion(renderingConfig.getViewDistance())) {
137137
chunk = chunkProvider.getChunk(chunkCoordinates);
@@ -144,7 +144,7 @@ public boolean pregenerateChunks() {
144144
}
145145
chunk.setDirty(false);
146146

147-
for (int segment = 0; segment < verticalChunkMeshSegements; segment++) {
147+
for (int segment = 0; segment < verticalChunkMeshSegments; segment++) {
148148
newMesh[segment] = chunkTessellator.generateMesh(localView, chunkYsizeToSegmentsRatio, segment * chunkYsizeToSegmentsRatio);
149149
newMesh[segment].generateVBOs();
150150
}
@@ -252,41 +252,43 @@ private Vector3i calcCameraCoordinatesInChunkUnits() {
252252
(int) (cameraCoordinates.z / ChunkConstants.SIZE_Z));
253253
}
254254

255-
/**
256-
* Updates the currently visible chunks (in sight of the player).
257-
*/
258255
@Override
259-
public int updateAndQueueVisibleChunks(boolean isFirstRenderingStageForCurrentFrame) {
260-
statDirtyChunks = 0;
261-
statVisibleChunks = 0;
262-
statIgnoredPhases = 0;
263-
264-
if (isFirstRenderingStageForCurrentFrame) {
265-
PerformanceMonitor.startActivity("Building Mesh VBOs");
266-
chunkMeshUpdateManager.setCameraPosition(playerCamera.getPosition());
267-
for (RenderableChunk chunk : chunkMeshUpdateManager.availableChunksForUpdate()) {
268-
if (chunksInProximityOfCamera.contains(chunk) && chunk.hasPendingMesh()) {
269-
for (ChunkMesh pendingMesh : chunk.getPendingMesh()) {
270-
pendingMesh.generateVBOs();
256+
public void generateVBOs() {
257+
PerformanceMonitor.startActivity("Building Mesh VBOs");
258+
chunkMeshUpdateManager.setCameraPosition(playerCamera.getPosition());
259+
for (RenderableChunk chunk : chunkMeshUpdateManager.availableChunksForUpdate()) {
260+
if (chunksInProximityOfCamera.contains(chunk) && chunk.hasPendingMesh()) {
261+
for (ChunkMesh pendingMesh : chunk.getPendingMesh()) {
262+
pendingMesh.generateVBOs();
263+
}
264+
if (chunk.hasMesh()) {
265+
for (ChunkMesh mesh: chunk.getMesh()) {
266+
mesh.dispose();
271267
}
272-
if (chunk.hasMesh()) {
273-
for (ChunkMesh mesh: chunk.getMesh()) {
274-
mesh.dispose();
275-
}
268+
}
269+
chunk.setMesh(chunk.getPendingMesh());
270+
chunk.setPendingMesh(null);
271+
} else {
272+
if (chunk.hasPendingMesh()) {
273+
for (ChunkMesh pendingMesh : chunk.getPendingMesh()) {
274+
pendingMesh.dispose();
276275
}
277-
chunk.setMesh(chunk.getPendingMesh());
278276
chunk.setPendingMesh(null);
279-
} else {
280-
if (chunk.hasPendingMesh()) {
281-
for (ChunkMesh pendingMesh : chunk.getPendingMesh()) {
282-
pendingMesh.dispose();
283-
}
284-
chunk.setPendingMesh(null);
285-
}
286277
}
287278
}
288-
PerformanceMonitor.endActivity();
289279
}
280+
PerformanceMonitor.endActivity();
281+
}
282+
283+
/**
284+
* Updates the currently visible chunks (in sight of the player).
285+
*/
286+
@Override
287+
public int queueVisibleChunks(boolean isFirstRenderingStageForCurrentFrame) {
288+
PerformanceMonitor.startActivity("Queueing Visible Chunks");
289+
statDirtyChunks = 0;
290+
statVisibleChunks = 0;
291+
statIgnoredPhases = 0;
290292

291293
int processedChunks = 0;
292294
int chunkCounter = 0;
@@ -341,12 +343,18 @@ public int updateAndQueueVisibleChunks(boolean isFirstRenderingStageForCurrentFr
341343
}
342344

343345
// Process all chunks in the area, not only the visible ones
344-
if (isFirstRenderingStageForCurrentFrame && processChunkUpdate(chunk)) {
345-
processedChunks++;
346+
if (isFirstRenderingStageForCurrentFrame) {
347+
if ((chunk.isDirty() || !chunk.hasMesh())) {
348+
statDirtyChunks++;
349+
chunkMeshUpdateManager.queueChunkUpdate(chunk);
350+
processedChunks++;
351+
}
346352
}
347353
}
348354
chunkCounter++;
349355
}
356+
357+
PerformanceMonitor.endActivity();
350358
return processedChunks;
351359
}
352360

@@ -362,15 +370,6 @@ private int triangleCount(ChunkMesh[] mesh, ChunkMesh.RenderPhase renderPhase) {
362370
return count;
363371
}
364372

365-
private boolean processChunkUpdate(RenderableChunk chunk) {
366-
if ((chunk.isDirty() || !chunk.hasMesh())) {
367-
statDirtyChunks++;
368-
chunkMeshUpdateManager.queueChunkUpdate(chunk);
369-
return true;
370-
}
371-
return false;
372-
}
373-
374373
@Override
375374
public void dispose() {
376375
chunkMeshUpdateManager.shutdown();

engine/src/main/java/org/terasology/rendering/world/WorldRendererLwjgl.java

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ public final class WorldRendererLwjgl implements WorldRenderer {
106106

107107
private final Time time = CoreRegistry.get(Time.class);
108108
private float tick;
109+
private float secondsSinceLastFrame;
109110

110111
private int statChunkMeshEmpty;
111112
private int statChunkNotReady;
@@ -124,9 +125,7 @@ public enum ChunkRenderMode {
124125
private RenderingConfig renderingConfig = config.getRendering();
125126
private RenderingDebugConfig renderingDebugConfig = renderingConfig.getDebug();
126127

127-
// TODO: work on the update/preRenderUpdate methods
128128
// TODO: rendering process as constructor input and setRenderingProcess method
129-
// TODO: move config-provided variables in preRenderUpdate() method?
130129
// TODO: examine the potential to avoid allocation of variables such as Materials
131130

132131
public WorldRendererLwjgl(BackdropProvider backdropProvider, BackdropRenderer backdropRenderer,
@@ -179,24 +178,12 @@ public boolean pregenerateChunks() {
179178
@Override
180179
public void update(float deltaInSeconds) {
181180

182-
updateTick(deltaInSeconds);
183-
184-
playerCamera.update(deltaInSeconds);
185-
positionShadowMapCamera();
186-
shadowMapCamera.update(deltaInSeconds);
187-
188-
renderableWorld.update();
181+
secondsSinceLastFrame += deltaInSeconds;
182+
tick += deltaInSeconds * 1000; // Updates the tick variable that animation is based on.
189183

190184
smoothedPlayerSunlightValue = TeraMath.lerp(smoothedPlayerSunlightValue, getSunlightValue(), deltaInSeconds);
191185
}
192186

193-
/**
194-
* Updates the tick variable that animation is based on. tick is in milliseconds.
195-
*/
196-
private void updateTick(float deltaInSeconds) {
197-
tick += deltaInSeconds * 1000;
198-
}
199-
200187
public void positionShadowMapCamera() {
201188
// Shadows are rendered around the player so...
202189
Vector3f lightPosition = new Vector3f(playerCamera.getPosition().x, 0.0f, playerCamera.getPosition().z);
@@ -236,24 +223,40 @@ private void resetStats() {
236223
}
237224

238225
private void preRenderUpdate(DefaultRenderingProcess.StereoRenderState stereoRenderState) {
226+
239227
switch (stereoRenderState) {
240228
case MONO:
241229
currentRenderingStage = WorldRenderingStage.DEFAULT;
242230
isFirstRenderingStageForCurrentFrame = true;
243231
break;
244232
case OCULUS_LEFT_EYE:
245233
currentRenderingStage = WorldRenderingStage.OCULUS_LEFT_EYE;
246-
playerCamera.updateFrustum();
247234
isFirstRenderingStageForCurrentFrame = true;
248235
break;
249236
case OCULUS_RIGHT_EYE:
250237
currentRenderingStage = WorldRenderingStage.OCULUS_RIGHT_EYE;
251-
playerCamera.updateFrustum();
252238
isFirstRenderingStageForCurrentFrame = false;
253239
break;
254240
}
255241

256-
renderableWorld.updateAndQueueVisibleChunks(isFirstRenderingStageForCurrentFrame);
242+
// this is done to execute this code block only once per frame
243+
// instead of once per eye in a stereo setup.
244+
if (isFirstRenderingStageForCurrentFrame) {
245+
playerCamera.update(secondsSinceLastFrame);
246+
positionShadowMapCamera();
247+
shadowMapCamera.update(secondsSinceLastFrame);
248+
249+
renderableWorld.update();
250+
renderableWorld.generateVBOs();
251+
secondsSinceLastFrame = 0;
252+
}
253+
254+
if (stereoRenderState != DefaultRenderingProcess.StereoRenderState.MONO) {
255+
playerCamera.updateFrustum();
256+
}
257+
258+
// this line needs to be here as deep down it relies on the camera's frustrum.
259+
renderableWorld.queueVisibleChunks(isFirstRenderingStageForCurrentFrame);
257260
}
258261

259262
/**
@@ -312,6 +315,8 @@ private void renderShadowMap() {
312315
renderer.renderShadows();
313316
}
314317

318+
playerCamera.lookThrough(); // not strictly needed: just defensive programming here.
319+
315320
glEnable(GL_CULL_FACE);
316321
DefaultRenderingProcess.getInstance().endRenderSceneShadowMap();
317322

@@ -787,10 +792,6 @@ public ChunkProvider getChunkProvider() {
787792
return renderableWorld.getChunkProvider();
788793
}
789794

790-
public Time getTime() {
791-
return time;
792-
}
793-
794795
@Override
795796
public float getTick() {
796797
return tick;

engine/src/main/java/org/terasology/world/chunks/ChunkConstants.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ public final class ChunkConstants {
3131
public static final int SIZE_X = 32;
3232
public static final int SIZE_Y = 64;
3333
public static final int SIZE_Z = 32;
34+
3435
public static final int INNER_CHUNK_POS_FILTER_X = TeraMath.ceilPowerOfTwo(SIZE_X) - 1;
3536
public static final int INNER_CHUNK_POS_FILTER_Y = TeraMath.ceilPowerOfTwo(SIZE_Y) - 1;
3637
public static final int INNER_CHUNK_POS_FILTER_Z = TeraMath.ceilPowerOfTwo(SIZE_Z) - 1;
38+
3739
public static final int POWER_X = TeraMath.sizeOfPower(SIZE_X);
3840
public static final int POWER_Y = TeraMath.sizeOfPower(SIZE_Y);
3941
public static final int POWER_Z = TeraMath.sizeOfPower(SIZE_Z);
40-
public static final int VERTICAL_SEGMENTS = CoreRegistry.get(Config.class).getSystem().getVerticalChunkMeshSegments();
42+
4143
public static final byte MAX_LIGHT = 0x0f;
4244
public static final byte MAX_SUNLIGHT = 0x0f;
4345
public static final byte MAX_SUNLIGHT_REGEN = 63;

engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.slf4j.Logger;
2222
import org.slf4j.LoggerFactory;
23+
import org.terasology.config.Config;
2324
import org.terasology.math.AABB;
2425
import org.terasology.math.Region3i;
2526
import org.terasology.math.Vector3i;
@@ -64,6 +65,9 @@ public class ChunkImpl implements Chunk {
6465
private static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("0.##");
6566
private static final DecimalFormat SIZE_FORMAT = new DecimalFormat("#,###");
6667

68+
private final int verticalChunkMeshSegments = CoreRegistry.get(Config.class).getSystem().getVerticalChunkMeshSegments();
69+
private final int chunkHalfHeight = ChunkConstants.SIZE_Y / verticalChunkMeshSegments / 2;
70+
6771
private final Vector3i chunkPos = new Vector3i();
6872

6973
private BlockManager blockManager;
@@ -73,7 +77,6 @@ public class ChunkImpl implements Chunk {
7377
private TeraArray sunlightRegenData;
7478
private TeraArray lightData;
7579

76-
7780
private TeraArray blockData;
7881
private volatile TeraArray blockDataSnapshot;
7982
private TeraArray extraData;
@@ -510,13 +513,11 @@ public ChunkMesh[] getPendingMesh() {
510513
@Override
511514
public AABB getSubMeshAABB(int subMesh) {
512515
if (subMeshAABB == null) {
513-
subMeshAABB = new AABB[ChunkConstants.VERTICAL_SEGMENTS];
514-
515-
int heightHalf = ChunkConstants.SIZE_Y / ChunkConstants.VERTICAL_SEGMENTS / 2;
516+
subMeshAABB = new AABB[verticalChunkMeshSegments];
516517

517518
for (int i = 0; i < subMeshAABB.length; i++) {
518-
Vector3f dimensions = new Vector3f(8, heightHalf, 8);
519-
Vector3f position = new Vector3f(getChunkWorldOffsetX() - 0.5f, (i * heightHalf * 2) - 0.5f, getChunkWorldOffsetZ() - 0.5f);
519+
Vector3f dimensions = new Vector3f(8, chunkHalfHeight, 8);
520+
Vector3f position = new Vector3f(getChunkWorldOffsetX() - 0.5f, (i * chunkHalfHeight * 2) - 0.5f, getChunkWorldOffsetZ() - 0.5f);
520521
position.add(dimensions);
521522
subMeshAABB[i] = AABB.createCenterExtent(position, dimensions);
522523
}

0 commit comments

Comments
 (0)