Skip to content

Commit 06d8333

Browse files
committed
refactored ground plane creation and rendering
1 parent 95d5518 commit 06d8333

File tree

14 files changed

+140
-67
lines changed

14 files changed

+140
-67
lines changed

android/assets/textures/ground1.jpg

408 KB
Loading

core/src/org/jrenner/fps/Assets.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,13 @@ public void loadAll() {
6969
manager.load("models/gate.g3db", HeadlessModel.class, modelParam);
7070
manager.load("models/strange-ramp1.g3db", HeadlessModel.class, modelParam);
7171
manager.load("models/strange-ramp2.g3db", HeadlessModel.class, modelParam);
72-
manager.load("models/ground.g3db", HeadlessModel.class, modelParam);
7372
} else {
7473
ModelLoader.ModelParameters modelParam = new ModelLoader.ModelParameters();
7574
modelParam.textureParameter = modTexParam;
7675

7776
manager.load("models/gate.g3db", Model.class, modelParam);
7877
manager.load("models/strange-ramp1.g3db", Model.class, modelParam);
7978
manager.load("models/strange-ramp2.g3db", Model.class, modelParam);
80-
manager.load("models/ground.g3db", Model.class, modelParam);
8179
manager.load("models/skybox.g3db", Model.class, modelParam);
8280
}
8381

@@ -124,7 +122,7 @@ private void loadTextures() {
124122
textureParam.minFilter = TextureFilter.MipMapLinearLinear;
125123
textureParam.wrapU = Texture.TextureWrap.Repeat;
126124
textureParam.wrapV = Texture.TextureWrap.Repeat;
127-
manager.load("models/ground1.jpg", Texture.class, textureParam);
125+
manager.load("textures/ground1.jpg", Texture.class, textureParam);
128126
manager.load("textures/marble.jpg", Texture.class, textureParam);
129127
manager.load("textures/shadow.png", Texture.class, textureParam);
130128

core/src/org/jrenner/fps/Box.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.badlogic.gdx.graphics.g3d.model.Node;
1010
import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
1111
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
12+
import com.badlogic.gdx.math.MathUtils;
1213
import com.badlogic.gdx.math.Matrix4;
1314
import com.badlogic.gdx.math.Quaternion;
1415
import com.badlogic.gdx.math.Vector3;
@@ -27,7 +28,7 @@ public class Box {
2728

2829

2930
/** create some boxes to fill the level with some test geometry */
30-
public static void createBoxes(int count, int minW, int maxW, int minH, int maxH) {
31+
public static void createBoxes(int count) {
3132
ModelBuilder main = new ModelBuilder();
3233
ModelBuilder mb = new ModelBuilder();
3334
Material material = new Material();
@@ -50,10 +51,11 @@ public static void createBoxes(int count, int minW, int maxW, int minH, int maxH
5051
Model boxModel = mb.end();
5152
Node node = main.node("box-" + i, boxModel);
5253
node.translation.set(tmp);
54+
q.idt();
55+
node.rotation.set(q);
5356
}
5457
//node.translation.set(MathUtils.random(x), 0f, MathUtils.random(y));
5558
//q.set(Vector3.X, -90);
56-
q.idt();
5759
mtx.set(q);
5860
mtx.setTranslation(tmp);
5961
btCollisionObject obj = Physics.inst.createBoxObject(tmp.set(w/2, h/2, d/2));

core/src/org/jrenner/fps/GameWorld.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package org.jrenner.fps;
22

33
public class GameWorld {
4-
public static final int WORLD_WIDTH = 200;
5-
public static final int WORLD_DEPTH = 200;
4+
public static final int WORLD_WIDTH = 100;
5+
public static final int WORLD_DEPTH = 100;
66
public static final int CENTER_X = WORLD_WIDTH / 2;
77
public static final int CENTER_Y = WORLD_DEPTH / 2;
88
public static final float GRAVITY = -0.01f;

core/src/org/jrenner/fps/HUD.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ public void changed(ChangeEvent event, Actor actor) {
142142

143143
private StringBuilder sb = new StringBuilder();
144144

145-
boolean debugHUD = false;
145+
/** output extra debug info to the in-game HUD */
146+
boolean debugHUD = true;
146147

147148
public void update() {
148149
//if (Main.frame % 10 != 0) return;
@@ -179,6 +180,7 @@ public void update() {
179180
sb.append("\n\nPhysics time: ").append(String.format("%4s", Main.physicsTime));
180181
sb.append("\nGround dist: ").append(String.format("%.4f", player.entity.distFromGround));
181182
sb.append("\nGround normal: ").append(Tools.fmt(Physics.inst.getFloorNormal(player.entity.getPosition())));
183+
sb.append("\nGroundPiece visibility: ").append(View.visibleGroundPieces).append(" / ").append(View.totalGroundPieces);
182184
}
183185
sb.append("\nPress T to chat\nPress R to respawn");
184186
label.setText(sb.toString());

core/src/org/jrenner/fps/LevelBuilder.java

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class LevelBuilder {
3636

3737
public static void init() {
3838
staticPieces = new Array<>();
39+
groundPieces = new Array<>();
3940
mb = new ModelBuilder();
4041
models = new Array<>();
4142
}
@@ -46,45 +47,49 @@ public LevelBuilder() {
4647

4748
public static Array<ModelInstance> staticGeometry;
4849

49-
public static ModelInstance ground;
50+
public static Array<ModelInstance> groundPieces;
51+
public static final float groundPieceSize = 16f;
5052

5153
public static void createLevel() {
5254
// graphical representation of the ground
5355
Log.debug("createLevel - create ground");
5456
if (Main.isClient()) {
55-
Model groundModel = Assets.manager.get("models/ground.g3db", Model.class);
5657
ModelBuilder mb = new ModelBuilder();
5758
mb.begin();
58-
MeshPartBuilder mpb = mb.part("first", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal | Usage.TextureCoordinates, groundModel.materials.first());
5959
Vector3 bl = new Vector3();
6060
Vector3 tl = new Vector3();
6161
Vector3 tr = new Vector3();
6262
Vector3 br = new Vector3();
6363
Vector3 norm = new Vector3(0f, 1f, 0f);
6464
// the size of each rect that makes up the ground
65-
int rectSize = 25;
66-
int rectCount = 0;
67-
for (int x = -100; x < GameWorld.WORLD_WIDTH; x += rectSize) {
68-
if (x % 20 == 0) {
69-
mpb = mb.part("section-" + x, GL20.GL_TRIANGLES, Usage.Position | Usage.Normal | Usage.TextureCoordinates, groundModel.materials.first());
70-
float u1 = 0f;
71-
float v1 = 0f;
72-
float u2 = rectSize / 5f;
73-
float v2 = rectSize / 5f;
74-
mpb.setUVRange(u1, v1, u2, v2);
75-
}
76-
for (int z = -100; z < GameWorld.WORLD_DEPTH; z += rectSize) {
77-
rectCount++;
78-
bl.set(x, 0, z);
79-
tl.set(x, 0, z + rectSize);
80-
tr.set(x + rectSize, 0, z + rectSize);
81-
br.set(x + rectSize, 0, z);
82-
mpb.rect(bl, tl, tr, br, norm);
65+
Texture groundTex = Assets.manager.get("textures/ground1.jpg", Texture.class);
66+
Material groundMat = new Material(TextureAttribute.createDiffuse(groundTex));
67+
MeshPartBuilder mpb = mb.part("ground", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal | Usage.TextureCoordinates, groundMat);
68+
float u1 = 0f;
69+
float v1 = 0f;
70+
float u2 = groundPieceSize / 5f;
71+
float v2 = groundPieceSize / 5f;
72+
mpb.setUVRange(u1, v1, u2, v2);
73+
bl.set(0, 0, 0);
74+
tl.set(0, 0, groundPieceSize);
75+
tr.set(groundPieceSize, 0, groundPieceSize);
76+
br.set(groundPieceSize, 0, 0);
77+
//mpb.rect(bl, tl, tr, br, norm);
78+
int divisions = ((int) groundPieceSize) / 4;
79+
mpb.patch(bl, tl, tr, br, norm, divisions, divisions);
80+
Model groundModel = mb.end();
81+
models.add(groundModel);
82+
groundPieces.clear();
83+
int count = 0;
84+
for (int x = 0; x < GameWorld.WORLD_WIDTH; x += groundPieceSize) {
85+
for (int z = 0; z < GameWorld.WORLD_DEPTH; z += groundPieceSize) {
86+
count++;
87+
ModelInstance groundPiece = new ModelInstance(groundModel);
88+
groundPiece.transform.setToTranslation(x, 0f, z);
89+
groundPieces.add(groundPiece);
8390
}
8491
}
85-
Log.debug("createLevel - created ground, rect count: " + rectCount);
86-
Model finalModel = mb.end();
87-
ground = new ModelInstance(finalModel);
92+
Log.debug("createLevel - created " + count + " groundPieces");
8893
}
8994

9095
// physical representation of the ground
@@ -101,7 +106,7 @@ public static void createLevel() {
101106
}
102107

103108
Log.debug("createLevel - create boxes");
104-
Box.createBoxes(20, 1, 10, 1, 10);
109+
Box.createBoxes(10);
105110
}
106111

107112
/** client builds statics, probably based on info from server */
@@ -163,7 +168,7 @@ private static void createStaticModels() {
163168
//float hi = GameWorld.WORLD_WIDTH;
164169
float x = 20f;
165170
float z = 0f;
166-
int numOfStaticObjects = 20;
171+
int numOfStaticObjects = 8;
167172
for (int i = 0; i < numOfStaticObjects; i++) {
168173
x = MathUtils.random(10f, 100f);
169174
z = MathUtils.random(10f, 100f);
@@ -197,8 +202,8 @@ private static void createStaticModels() {
197202
}
198203
if (Main.isClient()) {
199204
Model model = mb.end();
200-
ModelInstance gate = new ModelInstance(model);
201-
staticGeometry.add(gate);
205+
ModelInstance modelInst = new ModelInstance(model);
206+
staticGeometry.add(modelInst);
202207
}
203208
}
204209

core/src/org/jrenner/fps/Main.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ public class Main extends ApplicationAdapter {
3535
public AbstractClient client;
3636
public static boolean hasClient;
3737
public InputMultiplexer inputMulti;
38-
public static Application.ApplicationType Platform;
38+
public static Application.ApplicationType platform;
3939
public static ServerType serverType;
4040

4141
@Override
4242
public void create () {
4343
Log.setLevel(Log.DEBUG);
44-
Platform = Gdx.app.getType();
44+
platform = Gdx.app.getType();
4545
// we can pretend to be Android while running on desktop to test mobile features
4646
// such as mobile-specific input
47-
// Platform = Application.ApplicationType.Android;
47+
//platform = Application.ApplicationType.Android;
4848
Assets assets = new Assets();
4949
assets.loadAll();
5050
Log.debug("finished loading assets");
@@ -207,18 +207,18 @@ public static boolean isMobile() {
207207
}
208208

209209
public static boolean isAndroid() {
210-
return Platform == Application.ApplicationType.Android;
210+
return platform == Application.ApplicationType.Android;
211211
}
212212

213213
public static boolean isIOS() {
214-
return Platform == Application.ApplicationType.iOS;
214+
return platform == Application.ApplicationType.iOS;
215215
}
216216

217217
public static boolean isDesktop() {
218-
return Platform == Application.ApplicationType.Desktop;
218+
return platform == Application.ApplicationType.Desktop;
219219
}
220220

221-
public static boolean isHeadless() { return Platform == Application.ApplicationType.HeadlessDesktop; }
221+
public static boolean isHeadless() { return platform == Application.ApplicationType.HeadlessDesktop; }
222222

223223
public static NetClient getNetClient() {
224224
return (NetClient) inst.client;

core/src/org/jrenner/fps/Physics.java

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,37 @@ public void debugDrawDynamicEntity(DynamicEntity ent) {
233233
private static Vector3[] rectVectors = new Vector3[]{new Vector3(), new Vector3(), new Vector3(), new Vector3()};
234234

235235
public static int lastDistanceFromGroundRayHitCount;
236+
/** if a four-corners raycast was used, more than one ray might have hit, and the avg dist is stored here
237+
* otherwise it is equal to the dist of the single ray hit */
236238
public static float lastDistanceFromGroundAvgDist;
237239

238-
/** finds the distance from the bottom of the passed dimensions to the ground
240+
/** finds the distance from the bottom of the of the passed dimensions to the ground
241+
* This method only uses the center point
242+
* This is simpler than checking for each of the four corners
243+
* but less accurate
244+
* @return distance to the ground, or Float.NaN when raycast did not hit the ground */
245+
public float distanceFromGroundFast(Vector3 position, Vector3 dimen) {
246+
float hitDist = Float.NaN;
247+
float downStep = 2f + dimen.y; // length of ray
248+
float rayOriginHeight = 0f;
249+
// test single point
250+
rectVectors[0].set(position);
251+
Vector3 point = rectVectors[0];
252+
castRayStaticOnly(point, tmp.set(point).sub(0f, downStep, 0f));
253+
if (raycastReport.hit) {
254+
hitDist = raycastReport.hitDistance;
255+
}
256+
if (!Float.isNaN(hitDist)) {
257+
// if embedded in ground, a negative value will be returned
258+
hitDist -= (rayOriginHeight + dimen.y/2f);
259+
}
260+
lastDistanceFromGroundAvgDist = hitDist;
261+
return hitDist;
262+
}
263+
264+
/** finds the distance from the bottom of the passed dimensions to the ground.
265+
* This method uses the four corners of the dimensions
266+
* this is more expensive than checking a single point, but also more accurate
239267
* @return distance to the ground, or Float.NaN when raycast did not hit ground */
240268
public float distanceFromGround(Vector3 position, Vector3 dimen) {
241269
lastDistanceFromGroundRayHitCount = 0;
@@ -246,7 +274,7 @@ public float distanceFromGround(Vector3 position, Vector3 dimen) {
246274
float x = dimen.x / 4f;
247275
float z = dimen.z / 4f;
248276
float rayOriginHeight = 0f;
249-
// by starting the ray from the top of the dimensions
277+
// by starting the ray from the center of the dimensions
250278
// we can catch cases where the dimensions are already partially
251279
// embedded underneath the ground.
252280
// in this case, a negative distance will be returned
@@ -265,7 +293,7 @@ public float distanceFromGround(Vector3 position, Vector3 dimen) {
265293
}
266294
}
267295
}
268-
// we started the ray from the top, but we want the distance to ground from the bottom
296+
// we started the ray from the center, but we want the distance to ground from the bottom
269297
if (!Float.isNaN(lowest)) {
270298
// if embedded in ground, a negative value will be returned
271299
lowest -= (rayOriginHeight + dimen.y/2f);

core/src/org/jrenner/fps/Shadow.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class Shadow {
1919
private static Model model;
2020
public ModelInstance modelInstance;
2121
public static Array<Shadow> list;
22+
private float height;
2223

2324
public static void init() {
2425
list = new Array<>();
@@ -54,7 +55,12 @@ public Shadow(float size) {
5455
private static Vector3 tmp = new Vector3();
5556

5657
public void update(Vector3 position) {
57-
float height = Physics.inst.getShadowHeightAboveGround(position) - heightOffset;
58+
// optimize for Mobile
59+
if (Main.isMobile() && Main.frame % 6 != 0) {
60+
// don't update height
61+
} else {
62+
height = Physics.inst.getShadowHeightAboveGround(position) - heightOffset;
63+
}
5864
tmp.set(position.x, position.y - height, position.z);
5965
modelInstance.transform.setToTranslation(tmp);
6066
modelInstance.transform.rotate(Vector3.Y, Physics.inst.raycastReport.hitNormal);

0 commit comments

Comments
 (0)