Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

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