Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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