您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

329 行
15 KiB

  1. package roadtrip.view;
  2. import com.jme3.asset.AssetManager;
  3. import com.jme3.bullet.PhysicsSpace;
  4. import com.jme3.bullet.collision.shapes.BoxCollisionShape;
  5. import com.jme3.bullet.collision.shapes.ConeCollisionShape;
  6. import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
  7. import com.jme3.bullet.control.RigidBodyControl;
  8. import com.jme3.light.AmbientLight;
  9. import com.jme3.light.DirectionalLight;
  10. import com.jme3.material.Material;
  11. import com.jme3.math.ColorRGBA;
  12. import com.jme3.math.Vector2f;
  13. import com.jme3.math.Vector3f;
  14. import com.jme3.post.FilterPostProcessor;
  15. import com.jme3.post.filters.DepthOfFieldFilter;
  16. import com.jme3.renderer.Camera;
  17. import com.jme3.scene.Geometry;
  18. import com.jme3.scene.Node;
  19. import com.jme3.scene.Spatial;
  20. import com.jme3.scene.shape.Box;
  21. import com.jme3.terrain.geomipmap.*;
  22. import com.jme3.terrain.geomipmap.grid.FractalTileLoader;
  23. import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
  24. import com.jme3.terrain.geomipmap.lodcalc.LodCalculator;
  25. import com.jme3.terrain.noise.ShaderUtils;
  26. import com.jme3.terrain.noise.basis.FilteredBasis;
  27. import com.jme3.terrain.noise.filter.IterativeFilter;
  28. import com.jme3.terrain.noise.filter.OptimizedErode;
  29. import com.jme3.terrain.noise.filter.PerturbFilter;
  30. import com.jme3.terrain.noise.filter.SmoothFilter;
  31. import com.jme3.terrain.noise.fractal.FractalSum;
  32. import com.jme3.terrain.noise.modulator.NoiseModulator;
  33. import com.jme3.texture.Texture;
  34. import java.util.Random;
  35. import roadtrip.model.MapObjectInstance;
  36. import roadtrip.model.ProceduralMapQuadBlock;
  37. import roadtrip.model.TerrainDataProvider;
  38. import roadtrip.view.model.GameWorldState;
  39. import roadtrip.view.model.Player;
  40. /**
  41. * Created by dejvino on 14.01.2017.
  42. */
  43. public class GameWorldView {
  44. public static boolean DEBUG = false;//true;
  45. private final GameWorldState state;
  46. private final AssetManager assetManager;
  47. private final Camera camera;
  48. private final Node rootNode;
  49. private final PhysicsSpace physicsSpace;
  50. private final HideControl.TargetProvider targetProvider;
  51. public TerrainView terrain = new TerrainView(new TerrainDataProvider());
  52. public GameWorldView(GameWorldState gameWorldState, AssetManager assetManager,
  53. Camera camera, Node rootNode, PhysicsSpace physicsSpace,
  54. HideControl.TargetProvider targetProvider) {
  55. this.state = gameWorldState;
  56. this.assetManager = assetManager;
  57. this.camera = camera;
  58. this.rootNode = rootNode;
  59. this.physicsSpace = physicsSpace;
  60. this.targetProvider = targetProvider;
  61. }
  62. public static GameWorldView create(GameWorldState gameWorldState,
  63. AssetManager assetManager, Camera camera, Node rootNode,
  64. PhysicsSpace physicsSpace, HideControl.TargetProvider targetProvider) {
  65. GameWorldView gameWorldView = new GameWorldView(gameWorldState, assetManager, camera, rootNode, physicsSpace, targetProvider);
  66. gameWorldView.initialize();
  67. return gameWorldView;
  68. }
  69. private void initialize()
  70. {
  71. // Environment
  72. DirectionalLight dl = new DirectionalLight();
  73. dl.setColor(ColorRGBA.LightGray);
  74. dl.setDirection(new Vector3f(1, -1, 1));
  75. rootNode.addLight(dl);
  76. AmbientLight al = new AmbientLight();
  77. al.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
  78. rootNode.addLight(al);
  79. // TERRAIN TEXTURE material
  80. terrain.mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md");
  81. if (DEBUG) {
  82. terrain.mat_terrain.getAdditionalRenderState().setWireframe(true);
  83. }
  84. float heightScale = 400f;
  85. // Parameters to material:
  86. // regionXColorMap: X = 1..4 the texture that should be appliad to state X
  87. // regionX: a Vector3f containing the following information:
  88. // regionX.x: the start height of the region
  89. // regionX.y: the end height of the region
  90. // regionX.z: the texture scale for the region
  91. // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :)
  92. // slopeColorMap: the texture to be used for cliffs, and steep mountain sites
  93. // slopeTileFactor: the texture scale for slopes
  94. // terrainSize: the total size of the terrain (used for scaling the texture)
  95. Texture textureMid = this.assetManager.loadTexture("Textures/map-mid.png");
  96. textureMid.setWrap(Texture.WrapMode.Repeat);
  97. Texture textureLow = this.assetManager.loadTexture("Textures/map-low.png");
  98. textureLow.setWrap(Texture.WrapMode.Repeat);
  99. Texture textureHigh = this.assetManager.loadTexture("Textures/map-high.png");
  100. textureHigh.setWrap(Texture.WrapMode.Repeat);
  101. float modif = (heightScale / 100f) / 3f;
  102. terrain.mat_terrain.setTexture("region1ColorMap", textureLow);
  103. terrain.mat_terrain.setVector3("region1", new Vector3f(0, 80 * modif, terrain.texLowScale));
  104. terrain.mat_terrain.setTexture("region2ColorMap", textureMid);
  105. terrain.mat_terrain.setVector3("region2", new Vector3f(100 * modif, 160 * modif, terrain.texMidScale));
  106. terrain.mat_terrain.setTexture("region3ColorMap", textureHigh);
  107. terrain.mat_terrain.setVector3("region3", new Vector3f(190 * modif, 240 * modif, terrain.texHighScale));
  108. terrain.mat_terrain.setTexture("region4ColorMap", textureLow);
  109. terrain.mat_terrain.setVector3("region4", new Vector3f(250 * modif, 350 * modif, terrain.texLowScale));
  110. terrain.mat_terrain.setTexture("slopeColorMap", textureHigh);
  111. terrain.mat_terrain.setFloat("slopeTileFactor", 32);
  112. terrain.mat_terrain.setFloat("terrainSize", 513);
  113. terrain.terrainDataProvider.base = new FractalSum();
  114. terrain.terrainDataProvider.base.setRoughness(0.6f);
  115. terrain.terrainDataProvider.base.setFrequency(1.0f);
  116. terrain.terrainDataProvider.base.setAmplitude(1.0f);
  117. terrain.terrainDataProvider.base.setLacunarity(4.12f);
  118. terrain.terrainDataProvider.base.setOctaves(8);
  119. terrain.terrainDataProvider.base.setScale(0.02125f);
  120. terrain.terrainDataProvider.base.addModulator(new NoiseModulator() {
  121. @Override
  122. public float value(float... in) {
  123. return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1);
  124. }
  125. });
  126. FilteredBasis ground = new FilteredBasis(terrain.terrainDataProvider.base);
  127. terrain.terrainDataProvider.perturb = new PerturbFilter();
  128. terrain.terrainDataProvider.perturb.setMagnitude(0.119f);
  129. terrain.terrainDataProvider.therm = new OptimizedErode();
  130. terrain.terrainDataProvider.therm.setRadius(5);
  131. terrain.terrainDataProvider.therm.setTalus(0.011f);
  132. terrain.terrainDataProvider.smooth = new SmoothFilter();
  133. terrain.terrainDataProvider.smooth.setRadius(1);
  134. terrain.terrainDataProvider.smooth.setEffect(0.3f);
  135. terrain.terrainDataProvider.iterate = new IterativeFilter();
  136. terrain.terrainDataProvider.iterate.addPreFilter(terrain.terrainDataProvider.perturb);
  137. terrain.terrainDataProvider.iterate.addPostFilter(terrain.terrainDataProvider.smooth);
  138. terrain.terrainDataProvider.iterate.setFilter(terrain.terrainDataProvider.therm);
  139. terrain.terrainDataProvider.iterate.setIterations(2);
  140. ground.addPreFilter(terrain.terrainDataProvider.iterate);
  141. int patchSize = 16;
  142. Vector3f terrainScale = new Vector3f(8f, 1f, 8f);
  143. //terrain.terrainGrid = new TerrainGrid("terrain", 16 + 1, 512 + 1, new FractalTileLoader(ground, 300f));
  144. terrain.terrainGrid = new FineTerrainGrid("terrain", patchSize + 1, 128 + 1, terrainScale, new FractalTileLoader(ground, heightScale));
  145. terrain.terrainGrid.setMaterial(terrain.mat_terrain);
  146. //terrain.terrainGrid.setLocalTranslation(0, -200, 0);
  147. terrain.terrainGrid.setLocalScale(terrainScale);
  148. this.rootNode.attachChild(terrain.terrainGrid);
  149. final TerrainLodControl lodControl = new FineTerrainGridLodControl(terrain.terrainGrid, camera);
  150. lodControl.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 3.7f)); // patch size, and a multiplier
  151. terrain.terrainGrid.addControl(lodControl);
  152. final Spatial treeModel = assetManager.loadModel("Models/tree.j3o");
  153. final Spatial houseModel = assetManager.loadModel("Models/house1.j3o");
  154. final Spatial grassModel = assetManager.loadModel("Models/grass.j3o");
  155. Material rockMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
  156. rockMat.setColor("Color", ColorRGBA.Gray);
  157. Geometry rockGeom = new Geometry("rock", new Box(1f, 1f, 1f));
  158. rockGeom.setMaterial(rockMat);
  159. final Node rockModel = new Node("rockNode");
  160. rockModel.attachChild(rockGeom);
  161. final FineTerrainGrid terrainGrid = terrain.terrainGrid;
  162. terrainGrid.addListener(new TerrainGridListener() {
  163. @Override
  164. public void gridMoved(Vector3f newCenter) {
  165. }
  166. @Override
  167. public void tileAttached(Vector3f cell, TerrainQuad quad) {
  168. lodControl.forceUpdate();
  169. while(quad.getControl(RigidBodyControl.class)!=null){
  170. quad.removeControl(RigidBodyControl.class);
  171. }
  172. quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrainGrid.getLocalScale()), 0));
  173. physicsSpace.add(quad);
  174. removeQuadObjectsNode(quad);
  175. String quadObjectsNodeKey = getQuadObjectsNodeKey(quad);
  176. Node objects = new Node(quadObjectsNodeKey);
  177. populateQuadObjectsNode(quad, objects);
  178. rootNode.attachChild(objects);
  179. }
  180. protected void populateQuadObjectsNode(TerrainQuad quad, Node objects)
  181. {
  182. ProceduralMapQuadBlock mapQuadBlock = state.proceduralMap.getMapQuadBlock(quad);
  183. /*/ DEBUG pole in the middle of a quad
  184. Spatial m = treeModel.clone();
  185. m.setLocalTranslation(quad.getWorldTranslation().add(new Vector3f(0f, getHeight(quad, quad.getWorldTranslation()), 0f)));
  186. m.setLocalScale(new Vector3f(1f, 20f, 1f));
  187. objects.attachChild(m);
  188. /**/
  189. // Add map objects
  190. Random rand = mapQuadBlock.getBlockRandom();
  191. for (MapObjectInstance mapObject : mapQuadBlock.getMapObjects()) {
  192. Vector3f pos = mapObject.getPosition();
  193. Vector3f scale = Vector3f.UNIT_XYZ;
  194. Vector3f boxHalf = Vector3f.UNIT_XYZ;
  195. Spatial modelInstance;
  196. RigidBodyControl modelPhysics;
  197. switch (mapObject.getType()) {
  198. case "tree":
  199. modelInstance = treeModel.clone();
  200. float s = 0.2f + rand.nextFloat() * 5f;
  201. scale = new Vector3f(s, s, s);
  202. boxHalf = new Vector3f(s * 0.2f, s * 3f, s * 0.2f);
  203. modelPhysics = new RigidBodyControl(new BoxCollisionShape(boxHalf), 0f);
  204. break;
  205. case "house":
  206. modelInstance = houseModel.clone();
  207. boxHalf = new Vector3f(2f + rand.nextFloat() * 10f, 2f + rand.nextFloat() * 10f, 2f + rand.nextFloat() * 10f);
  208. scale = boxHalf;
  209. modelPhysics = new RigidBodyControl(new BoxCollisionShape(boxHalf), 0f);
  210. break;
  211. default:
  212. throw new RuntimeException("Unhandled object type: " + mapObject.getType());
  213. }
  214. modelInstance.setLocalTranslation(pos);
  215. modelInstance.setLocalScale(scale);
  216. // TODO: physics from the model and not hard-coded
  217. //RigidBodyControl control = treeInstance.getControl(RigidBodyControl.class);
  218. if (modelPhysics != null) {
  219. modelPhysics.isActive();
  220. modelInstance.addControl(modelPhysics);
  221. modelPhysics.setPhysicsLocation(pos);
  222. physicsSpace.add(modelPhysics);
  223. }
  224. objects.attachChild(modelInstance);
  225. }
  226. int w = 128;
  227. for (int i = 0; i < w*w; i++) {
  228. int x = i % w;
  229. int z = i / w;
  230. if (((x % 8) + (z % 8)) != 0) continue;
  231. Vector3f pos = new Vector3f(x - w/2f + 0.25f*terrainGrid.getLocalScale().x, 0f, z - w/2f + 0.25f*terrainGrid.getLocalScale().z).addLocal(quad.getWorldTranslation());
  232. pos.addLocal(0f, getHeight(quad, pos), 0f);
  233. Vector3f scale = Vector3f.UNIT_XYZ;
  234. Spatial modelInstance;
  235. float s = 0.1f;
  236. if (i == 0) {
  237. s = 0.4f;
  238. } else if ((x % 16) + (z % 16) == 0) {
  239. s = 0.2f;
  240. }
  241. switch ("grass") {
  242. case "grass":
  243. modelInstance = rockModel.clone();
  244. scale = new Vector3f(s, s, s);
  245. break;
  246. default:
  247. throw new RuntimeException("Unhandled object type");
  248. }
  249. modelInstance.setLocalTranslation(pos);
  250. modelInstance.setLocalScale(scale);
  251. modelInstance.addControl(new HideControl(20f + 140f * s, targetProvider));
  252. objects.attachChild(modelInstance);
  253. }
  254. }
  255. @Override
  256. public void tileDetached(Vector3f cell, TerrainQuad quad) {
  257. if (quad.getControl(RigidBodyControl.class) != null) {
  258. physicsSpace.remove(quad);
  259. quad.removeControl(RigidBodyControl.class);
  260. }
  261. removeQuadObjectsNode(quad);
  262. }
  263. protected void removeQuadObjectsNode(TerrainQuad quad)
  264. {
  265. Spatial quadObjectsNodeOld = rootNode.getChild(getQuadObjectsNodeKey(quad));
  266. if (quadObjectsNodeOld != null) {
  267. physicsSpace.removeAll(quadObjectsNodeOld);
  268. quadObjectsNodeOld.removeFromParent();
  269. }
  270. }
  271. private String getQuadObjectsNodeKey(TerrainQuad quad)
  272. {
  273. return "Objects-" + quad.getName();
  274. }
  275. private float getHeight(TerrainQuad quad, Vector3f pos)
  276. {
  277. return quad.getHeight(new Vector2f(pos.x, pos.z));
  278. }
  279. });
  280. /**/
  281. }
  282. }