diff --git a/FinalReport.md b/FinalReport.md new file mode 100644 index 00000000..3de05df4 --- /dev/null +++ b/FinalReport.md @@ -0,0 +1,307 @@ +# Procedural Terrain using Cesium - Final Report + +![](images/presentation/final_shaded.png) + +### Table of Contents + +1. Design Document +2. Results +3. Evaluation +4. Future Work +5. Acknowledgements + +**The code in this repository is a copy of the code in [this](https://github.com/rms13/Procedural-3D-Tiles-Server) repository, which is a fork of Cesium.** + +**The project is not deployed as it creates a server to serve tilesets to cesium. gh-pages do not support server creation** + +------------------------------------ + +## Design Document + +### Introduction +This project consists of procedural generation of terrain and textures for Cesium. Cesium fetches tiles with geometry data from a server. We will be adding proceduralism to Cesium by providing the procedural terrain in place of pre-modelled structures. + +### Goal +The geometry data Cesium fetches from the servers is based on the camera position. When the camera moves to an object, a higher resolution mesh is rendered. Our goal is to develop an algorithm that can generate terrain and textures in such incremental levels of detail. We will be creating a web server to provide the generated content. + +### Inspiration/ Reference +Some cool demos that inspired us to do this project: +- Ixaleno: A 4kb executable by IQ: tps://www.youtube.com/watch?v=XAWPCmVC5jA +- fp.skiView: IQ again: https://www.shadertoy.com/view/XdjXDK +- Planet Shadertoy: by reinder: https://www.shadertoy.com/view/4tjGRh + +### Specification +Our final product would feature: +- Procedurally generated terrain. +- Procedurally generated texture for the terrain. +- Varying levels of detail for the terrain and the textures based on the distance of the camera from the terrain. +- Web server serving the content to Cesium. + +### Techniques + +#### Terrain Generation +1. For the procedural terrain generation part we are planning to make a 3D height field using pseudorandom perlin noise that will be divided into a set of tiles to discretise the terrain creation. + +![](./images/dd_img2.png) +![](./images/dd_img3.png) +![](./images/dd_img4.jpg) + +2. Another method for obtaining the initial seed values for the terrain can be generated using various fractal patterns as mentioned below. + +3. Using the seed random data converted to a 2D array, we will apply the Diamond-Square algorithm to procedurally generate and tessellate the terrain with realistic looking mountain, valleys and rough terrain. + +![](./images/dd_img5.gif) +![](./images/dd_img6.gif) + +4. Another approach that can be used to generate the terrain would be as mentioned in this article [[1]](http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/) using voronoi patterns. We don’t exactly know how cesium tiling works and how we can use this methods to procedurally generate more definition in the terrain as the level of detail increases. We will get a better idea on which methods are feasible to use once we get an understanding on how cesium works. + +#### Texture Generation +We will be working on multiple texture generation algorithms to achieve different terrain effects. + +1. Fractals: This can be used if the finer details are to be added to coarser images, as fractals are repetitive. Also, we can get other cool terrain features like rivers using fractals. + +2. Voronoi patterns / Cell noise / Worley noise: To achieve a dry land kind of effect, one of these methods will be used. These can also be used for texturing stones. + +![](./images/dd_img7.jpg) + +3. Ridged fractal/perlin noise: This will be used for creating smoother looking textures like desert or snow, and for blending the textures. This is very similar to the original Perlin noise algorithm, with some modifications [[2]](http://www.inear.se/2010/04/ridged-perlin-noise). We will be using either one of those. Examples of ridged fractal noise textures: + +![](./images/dd_img8.jpg) +![](./images/dd_img9.jpg) +![](./images/dd_img10.jpg) + +4. Blending different textures for smoother transition. Dirt and snow on mountains, sand and water on beaches, etc. don’t have hard edges. We don’t have a proper idea of what the best method would be to achieve this. There are some articles describing the use of height maps to do this [[3]](http://www.cprogramming.com/discussionarticles/texture_generation.html). We will get a better idea about this as we begin working on the generation algorithms. + + +### Design +As stated before, Cesium obtains tiles from the server. We will be creating a web server that provides the 3D tile content. + +![](./images/dd_img11.png) + +------------------------------------ + +## Results + +[YouTube video](https://www.youtube.com/watch?v=qH6zrUEBTnE) + +Terrain (gif): + +![](images/report/increase_detail.gif) + +Texture (png and gif): + +![](images/report/textureimg.png) + +![](images/report/texture.gif) + +------------------------------------ + +## Evaluation + +### Terrain + +#### How A Tile Is Rendered Using Cesium + +- `Tile Request:`First the Cesium server is requested with a tile to be drawn. A tile is represented by any one of the quads in the image as shown below. + +![](images/presentation/coarse_wire.png) + +- `Bounding Box:`For the requested tile, four corners are created based on the position of the points along the latitude and longitude on the sphere. + +- The four corners are run through the 3D multi octave noise to generate the noise value for them which will be used as a metric to estimate the max and min height of the encompassing bounding box. + +- While generating the bounding box the distance of the camera is also taken into account as the octaves to which the noise is sampled is dependent on it. The farther the distance the less number of octaves to sample and the closer the distance the more the octaves. This + +configuration helps in determining a tighter fit bounding box. + +- The distance metric is not sufficient to generate a tight bounding box, we also need to estimate and __add__ the __error__. There could be points inside the tile for which the height value may exceed the maximum or minimum bounds so in order to estimate the error we go three depths deep i.e we calculate the error for k+3 octaves, where k = octaves. + + __Error = pow(persistence,k+1) + pow(persistence,k+2) + pow(persistence,k+3)__ + + ![](images/presentation/coarse_bounding.png) + + +-`Subdivide Tile:`once we have the bounding box for the tile we subdivide the tile in a 9x9 grid. This provides more mesh to generate the terrain on. + + +-`Level Of Detail:` The closer the mesh is to the camera the more tiles will be rendered and the more tiles there are the more subdivided mesh to render the terrain on. + +![](images/presentation/fine_wire.png) + + +`Terrain Generation` + +- For the terrain generation I am using a 3D multi octave lattice noise. + +- Multi octave noise convolutes noise values or gradients specified at integer lattice points. + +- For each pass/ octave the amplitude is reduced by a factor of the persistence and the sampling frequency is increased. + + - For higher octaves in the noise the corrosponding noise sampled becomes increasingly coarse, using this property of the lattice noise to my advantage I have used the distance of the tile as a metric to define the octaves of noise. + + - When the terrain is farther away from the camera the octaves will be less making the terrain smooth and as the camera comes closer the octaves will increase making the terrain more and more coarse and more defined. + + + +- Finally the subdivided vertices of the tile are run through the 3D multi octave noise and are offset using the noise as as a height field value. + + + +- Once the terrain is generated the geometry is then tessellated and the vertice, normal and indice information is packed into a buffer and sent to the shader to render using the `GLTF format`. + + + + ![](images/presentation/fine_bounding.png) + + + + ![](images/presentation/fine_flat.png) + + + +`Normals:` Using the same normals for the vertice points as before they were offsetted by the noise height field and storing them only once per vertex will lead to flat shading as seen in the image above. To counteract this we calculate and store the normals per vertex per face which will produce the correct shading. + + + +![](images/presentation/fine_shaded.png) + + +### Texture + +The texture generation part involved exploration of different texturing techniques and fine-tuning the results to get realistic results. These techniques are described in this section. + +The plan was to use multi-octave noise and fractals for the base texture, and add more variation using other techniques like voronoi diagrams. Fractals seemed to be a good option as we were dealing with increasing levels of detail. But as we decided to implement the texture in the fragment shader, I decided to use only multi-octave noise as changing levels of detail is not difficult to deal with in the shader. The final texture is a combination of multi-octave value noise and voronoi diagrams. + + + +#### Multi-Octave Value Noise + +This is what [Inigo Quilez](http://www.iquilezles.org/index.html) used in his demo [elevated]( https://www.shadertoy.com/view/MdX3Rr) for modeling the terrain and simulating erosion like effects. + +Value noise is a noise generation technique much like Perlin noise. Value noise takes a pseudo random number as an input, and gives a noise value based on a quadratic, cubic, or quintic equation. The derivatives of the equation can be used as noise derivatives, which is useful in erosion simulation. + +I modelled a terrain using ridged value noise in the vertex shader for testing the texture. Mapping the noise to the terrain gave the following result: + +![](images/m1-texture2.PNG) + +The presence of snow is determined by a combination of the height and the noise value at any point. The noise derivatives are used along with the noise to obtain the erosion/sliding of snow. I could not find much literature explaining the math behind the implementation of such effects, so I tweaked the values until it worked the way I thought it should. The derivative, in a way, should give the slope (change in noise) at the point. So, assuming it will show up more at high altitudes, it should flow down. Animating the implementation with time shows some such behavior. But I am not completely sure if that is how it really works. + + + +#### Modifications to Value Noise + +To add more detail to the terrain, I decided to explore some interesting techniques that work with pseudo-random noise, as I was computing value noise anyway. + +**Ridged Value Noise:** It is a way of adding sharp ridges in an otherwise smooth value noise. The value of noise is in the range of [-1,1]. Absolute of noise flips the negative part to positive, creating a sharp discontinuity at 0. Subtracting this value from 1.0 inverts the resulting *graph*, producing sharp edges when viewed from top. The first image below is value noise and the second one is the corresponding ridged noise. I tried combining this with the original noise, but the results weren't convincing. + +![](images/presentation/value.png) + +![](images/presentation/value_ridged.png) + + +**Distorting textures using sine function:** It is a widely used method, where one inputs the noise value to the sine function. The results of this were also not very convincing. It looks like a marble texture which in no way could help me add details to the terrain texture. + +![](images/presentation/sine_noise.png) + + + +#### Voronoi diagrams + +Ridged noise and sine distortion having failed, I decided to give voronoi diagrams a try. They are used in many demos for modeling and shading rocks and terrain. + +>In mathematics, a Voronoi diagram is a partitioning of a plane into regions based on distance to points in a specific subset of the plane. - Wikipedia + +The voronoi diagram generated using the nearest of the sampled points, looks like this: + +![](images/presentation/voro.png) + +Multiple voronoi diagrams with closest (V0), second closest(V1), ... points can be computed simultaneously and combined to get interesting results. + +V1 - V0 : + +![](images/presentation/voro_diff.png) + +V1 x V0 : + +![](images/presentation/voro_mul.png) + +> V1 x V0 when scaled down a lot, gives good enough details to add to the terrain. Currently, in the code, it is scaled down by 200 times. If finer details are needed, it can be scaled down more. + + +#### Blending the textures + +These texturing methods are applied simultaneously and blended to get a final texture for fragments. + +The base color (gray and brown) combined using noise: + +![](images/presentation/final_base.png) + +Adding more color (two shades of green) using offsetted noise to get more variation: + +![](images/presentation/final_base_green.png) + +Adding voronoi (unevenly): + +![](images/presentation/final_base_green_voro.png) + +Adding snow (using the noise derivatives for fake erosion): + +![](images/presentation/final_base_green_voro_snow.png) + +Diffuse shading: + +![](images/presentation/final_shaded.png) + +------------------------------------ + +## Future Work + +**Rudraksha** + +- Given more time I would like to work on further optimizing the terrain generation by implementing the terrain inside the shader instead of the server. + +**Rishabh** + +- I would like to generate the terrain in the vertex shader using the same value noise algorithm. As this is a pseudo random noise, I can get the same values in the fragment shader and compute accurate height and noise derivatives to get better erosion effects. Currently, it is done using the noise that is not related to the height field. As a result, it does not look like as good as it does using the vertex shader I used for initial testing. + +- I will also like to explore more types of terrains and their textures. + +- Another interesting thing to explore would be generating weather effects like clouds, erosion due to wind, water, etc. Animation of such effects should be achievable using time variable in shader. + +------------------------------------ + +## Acknowledgements + +- Thanks to Austin for helping setup the server. + +- Thanks to Austin and Rachel for helping understand the architecture of Cesium. Also for helping with developing an efficient way to generate the bounding boxes. + +- Perlin noise reference: https://en.wikipedia.org/wiki/Perlin_noise + +- Reference for terrain generation using noise: + + - http://www.redblobgames.com/articles/noise/introduction.html + + - http://www.iquilezles.org/www/articles/morenoise/morenoise.htm + + - http://www.iquilezles.org/www/articles/voronoise/voronoise.htm + + - http://www.iquilezles.org/www/articles/warp/warp.htm + +- References for texturing: + + - Value noise by Inigo Quilez: http://www.iquilezles.org/www/articles/morenoise/morenoise.htm + - + - Basic lighting: https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php + - Gamma correction: https://learnopengl.com/#!Advanced-Lighting/Gamma-Correction + - Voronoi diagrams: + - GPU approach: http://nullprogram.com/blog/2014/06/01/ + - Intro to cell noise: http://www.carljohanrosen.com/share/CellNoiseAndProcessing.pdf + - More cell noise: https://aftbit.com/cell-noise-2/ + + - Terrain algorithms: http://www.decarpentier.nl/scape-procedural-basics + - Paper on thermal erosion on GPU: http://old.cescg.org/CESCG-2011/papers/TUBudapest-Jako-Balazs.pdf + - Cool ridge noise texture examples: http://www.inear.se/2010/04/ridged-perlin-noise/ + - Noise examples and techniques for textures: http://www.upvector.com/?section=Tutorials&subsection=Intro%20to%20Procedural%20Textures + - Useful fractal formulae for planets towards the end: http://luthuli.cs.uiuc.edu/~daf/courses/computergraphics/week8/shading.pdf + - Colors: Earth Tones: http://www.varian.net/dreamview/dreamcolor/earth.html diff --git a/README.md b/README.md index 71a9296d..40252715 100644 --- a/README.md +++ b/README.md @@ -1,112 +1,84 @@ -# CIS700 Procedural Graphics: Final Project +### CIS700 Procedural Graphics: Final Project +# Procedural Terrain using Cesium +#### By: Rudraksha Shah and Rishabh Shah -Time to show off your new bag of procedural tricks by creating one polished final project. For this assignment you will have four weeks to create and document a portfolio piece that demonstrates your mastery of procedural thinking and implementation. You may work in groups of up to three (working alone is fine too). You may use any language / platform you choose for this assignment (given our approval if it’s not JavaScript/WebGL or C++/OpenGL). +[Youtube Video](https://www.youtube.com/watch?v=qH6zrUEBTnE) -As usual with this class, we want to encourage you to take this opportunity to explore and experiment. To get you started, however, we’ve provided a few open-ended prompts below. Interesting and complex visuals are the goal in all of these prompts, but they encourage focus on different aspects of proceduralism. +----- -## Prompts: +![](./images/dd_img1.jpg) -- ### A classic 4k demo - * In the spirit of the demo scene, create an animation that fits into a 4k executable that runs in real-time. Feel free to take inspiration from the many existing demos. Focus on efficiency and elegance in your implementation. - * Examples: [cdak by Quite & orange](https://www.youtube.com/watch?v=RCh3Q08HMfs&list=PLA5E2FF8E143DA58C) +### Introduction +This project consists of procedural generation of terrain and textures for Cesium. Cesium fetches tiles with geometry data from a server. We will be adding proceduralism to Cesium by providing the procedural terrain in place of pre-modelled structures. -- ### A forgery - * Taking inspiration from a particular natural phenomenon or distinctive set of visuals, implement a detailed, procedural recreation of that aesthetic. This includes modeling, texturing and object placement within your scene. Does not need to be real-time. Focus on detail and visual accuracy in your implementation. - * Examples: - - [Snail](https://www.shadertoy.com/view/ld3Gz2), [Journey](https://www.shadertoy.com/view/ldlcRf), Big Hero 6 Wormhole: [Image 1](http://2.bp.blogspot.com/-R-6AN2cWjwg/VTyIzIQSQfI/AAAAAAAABLA/GC0yzzz4wHw/s1600/big-hero-6-disneyscreencaps.com-10092.jpg) , [Image 2](https://i.stack.imgur.com/a9RGL.jpg) +### Goal +The geometry data Cesium fetches from the servers is based on the camera position. When the camera moves to an object, a higher resolution mesh is rendered. Our goal is to develop an algorithm that can generate terrain and textures in such incremental levels of detail. We will be creating a web server to provide the generated content. -- ### A game level - * Like generations of game makers before us, create a game which generates an navigable environment (eg. a roguelike dungeon, platforms) and some sort of goal or conflict (eg. enemy agents to avoid or items to collect). Must run in real-time. Aim to create an experience that will challenge players and vary noticeably in different playthroughs, whether that means complex dungeon generation, careful resource management or a sophisticated AI model. Focus on designing a system that will generate complex challenges and goals. - * Examples: Spore, Dwarf Fortress, Minecraft, Rogue +### Inspiration/ Reference +Some cool demos that inspired us to do this project: +- Ixaleno: A 4kb executable by IQ: tps://www.youtube.com/watch?v=XAWPCmVC5jA +- fp.skiView: IQ again: https://www.shadertoy.com/view/XdjXDK +- Planet Shadertoy: by reinder: https://www.shadertoy.com/view/4tjGRh -- ### An animated environment / music visualizer - * Create an environment full of interactive procedural animation. The goal of this project is to create an environment that feels responsive and alive. Whether or not animations are musically-driven, sound should be an important component. Focus on user interactions, motion design and experimental interfaces. - * Examples: [Panoramical](https://www.youtube.com/watch?v=gBTTMNFXHTk), [Bound](https://www.youtube.com/watch?v=aE37l6RvF-c) -- ### Own proposal - * You are of course **welcome to propose your own topic**. Regardless of what you choose, you and your team must research your topic and relevant techniques and come up with a detailed plan of execution. You will meet with some subset of the procedural staff before starting implementation for approval. +### Specification +Our final product would feature: +- Procedurally generated terrain. +- Procedurally generated texture for the terrain. +- Varying levels of detail for the terrain and the textures based on the distance of the camera from the terrain. +- Web server serving the content to Cesium. -**Final grading will be individual** and will be based on both the final product and how well you were able to achieve your intended effect according to your execution plan. Plans change of course, and we don’t expect you to follow your execution plan to a T, but if your final project looks pretty good, but you cut corners and only did 30% of what you outlined in your design doc, you will be penalized. +### Techniques -But overall, have fun! This is your opportunity to work on whatever procedural project inspires you. The best way to ensure a good result is to pick something you’re passionate about. :) +#### Terrain Generation +1. For the procedural terrain generation part we are planning to make a 3D height field using pseudorandom perlin noise that will be divided into a set of tiles to discretise the terrain creation. -## Timeline +![](./images/dd_img2.png) +![](./images/dd_img3.png) +![](./images/dd_img4.jpg) -- 4/08 Design doc due / Have met with procedural staff -- 4/18 Milestone 1 (short write-up + demo) -- 4/25 Milestone 2 (short write-up + demo) -- 5/3 Final presentations (3-5 pm, Siglab), final reports due +2. Another method for obtaining the initial seed values for the terrain can be generated using various fractal patterns as mentioned below. -## Design Doc +3. Using the seed random data converted to a 2D array, we will apply the Diamond-Square algorithm to procedurally generate and tessellate the terrain with realistic looking mountain, valleys and rough terrain. -Your design doc should follow the following template. Note, each section can be pretty short, but cover them all! This will serve as valuable documentation when showing this project off in the future AND doing a good job will make it much easier for you to succeed, so please take this seriously. +![](./images/dd_img5.gif) +![](./images/dd_img6.gif) -### Design Doc Template: +4. Another approach that can be used to generate the terrain would be as mentioned in this article [[1]](http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/) using voronoi patterns. We don’t exactly know how cesium tiling works and how we can use this methods to procedurally generate more definition in the terrain as the level of detail increases. We will get a better idea on which methods are feasible to use once we get an understanding on how cesium works. -- #### Introduction - * What motivates this project? -- #### Goal - * What do you intend to achieve with this project? -- #### Inspiration/reference: - * Attach some materials, visual or otherwise you intend as reference -- #### Specification: - * Outline the main features of your project -- #### Techniques: - * What are the main technical/algorithmic tools you’ll be using? Give an overview, citing specific papers/articles -- #### Design: - * How will your program fit together? Make a simple free-body diagram illustrating the pieces. -- #### Timeline: - * Create a week-by-week set of milestones for each person in your group. +#### Texture Generation +We will be working on multiple texture generation algorithms to achieve different terrain effects. +1. Fractals: This can be used if the finer details are to be added to coarser images, as fractals are repetitive. Also, we can get other cool terrain features like rivers using fractals. -Along with your final project demo, you will submit a final report, in which you will update correct your original design doc as needed and add a few post-mortem items. +2. Voronoi patterns / Cell noise / Worley noise: To achieve a dry land kind of effect, one of these methods will be used. These can also be used for texturing stones. -## Milestones +![](./images/dd_img7.jpg) -To keep you honest / on-track, we will be checking on your progress at weekly intervals, according to milestones you’ll define at the outset (pending our approval). For each of the two milestones prior to the final submission, you will submit a short write up explaining whether or not you individually achieved your goals (specifying the files where the work happened), along with a link to a demo / images. These don’t have to be super polished -- we just want to see that you’re getting things done. +3. Ridged fractal/perlin noise: This will be used for creating smoother looking textures like desert or snow, and for blending the textures. This is very similar to the original Perlin noise algorithm, with some modifications [[2]](http://www.inear.se/2010/04/ridged-perlin-noise). We will be using either one of those. Examples of ridged fractal noise textures: -Example: +![](./images/dd_img8.jpg) +![](./images/dd_img9.jpg) +![](./images/dd_img10.jpg) -“Milestone 1: - Adam: -Made some procedural terrain code in src/terrain.js. Implemented 3D simplex noise to do it. Also applied coloring via custom shader based on this cool paper X (see src/shaders/dirt.glsl). IMAGE +4. Blending different textures for smoother transition. Dirt and snow on mountains, sand and water on beaches, etc. don’t have hard edges. We don’t have a proper idea of what the best method would be to achieve this. There are some articles describing the use of height maps to do this [[3]](http://www.cprogramming.com/discussionarticles/texture_generation.html). We will get a better idea about this as we begin working on the generation algorithms. -Austin: -I managed to set up my voronoi diagram shader (see src/shaders/voronoi.glsl). -Experimented with different scattering techniques. It’s working with the euclidean distance metric. I’m using it in src/main.js to color stones. IMAGE +5. Since we are aiming for realistic images, we would like to explore Whittaker diagram for biomes of multiple terrain types [[4]](https://w3.marietta.edu/~biol/biomes/biome_main.htm), if time permits. It uses data like temperature and humidity to define biomes. -Rachel: -I tried really hard to make my toon shader work (src/shaders/toon.glsl), but I still have a bug! T_T BUGGY IMAGE. DEMO LINK” - -## Final Report - -In addition to your demo, you will create a final report documenting your project overall. This document should be clear enough to explain the value and details of your project to a random computer graphics person with no knowledge of this class. - -### Final Report Template: - -- #### Updated design doc: - * All the sections of your original design doc, corrected if necessary -- #### Results: - * Provide images of your finished project -- #### Evaluation (this is a big one!): - * How well did you do? What parameters did you tune along the way? Include some WIP shots that compare intermediate results to your final. Explain why you made the decisions you did. -- #### Future work: - * Given more time, what would you add/improve -- #### Acknowledgements: - * Cite _EVERYTHING_. Implemented a paper? Used some royalty-free music? Talked to classmates / a professor in a way that influenced your project? Attribute everything! - -## Logistics - -Like every prior project, your code will be submitted via github. Fork the empty final project repo and start your code base from there. Take this as an opportunity to practice using git properly in a team setting if you’re a new user. For each weekly submission, provide a link to your pull request. Your repo will contain all the code and documentation associated with your project. The readme for your repo will eventually be your final report. At the top level, include a folder called “documentation”, where you’ll put your design doc and milestone write-ups. - -Don’t wait to merge your code! Seriously, there be dragons. Try to have a working version including all your code so that compatibility and merge issues don’t sneak up on you near the end. - -## Grading - -- 15% Design Doc (graded as a group) -- 15% Milestone 1 (graded as a group) -- 15% Milestone 2 (graded as a group) -- 55% Final demo + report (graded individually) - -NOTE: We’ve been pretty lax about our late policy throughout the semester, but our margins on the final project are tight, therefore late submissions will NOT be accepted. If you have a significant reason for being unable to complete your goals, talk to us, and we’ll discuss getting you an incomplete and figure out an adjusted work plan with your group. +### Design +As stated before, Cesium obtains tiles from the server. We will be creating a web server that provides the 3D tile content. +![](./images/dd_img11.png) +### Timeline +- 09 April - 15 April + - Rishabh & Rudraksha: Getting the server part working. + - Rishabh: Start with ridged fractal/perlin noise. + - Rudraksha: Understand the tiling method used by cesium to start working on the terrain generation. +- 16 April - 22 April + - Rishabh: Complete ridged fractal/perlin noise and start with Voronoi / fractals depending on the terrain types that are going to be generated. + - Rudraksha: Generate the terrain height field data and pack it in the .gltf format for output to cesium. +- 23 April - 29 April + - Rishabh: Complete all the texture generation part. Work on the blending of textures if not already taken care of while implementing the generation. + - Rudraksha: Finish any remaining details and merge the code. +- 30 April - 03 May + - Time buffer. diff --git a/images/DS.png b/images/DS.png new file mode 100644 index 00000000..9763e8ad Binary files /dev/null and b/images/DS.png differ diff --git a/images/IV.png b/images/IV.png new file mode 100644 index 00000000..73f56ecd Binary files /dev/null and b/images/IV.png differ diff --git a/images/SS.png b/images/SS.png new file mode 100644 index 00000000..c6c5bcf9 Binary files /dev/null and b/images/SS.png differ diff --git a/images/T1.png b/images/T1.png new file mode 100644 index 00000000..e0d3b958 Binary files /dev/null and b/images/T1.png differ diff --git a/images/T2.png b/images/T2.png new file mode 100644 index 00000000..9c8dcff7 Binary files /dev/null and b/images/T2.png differ diff --git a/images/WFT1.png b/images/WFT1.png new file mode 100644 index 00000000..55e9aed8 Binary files /dev/null and b/images/WFT1.png differ diff --git a/images/WFT2.png b/images/WFT2.png new file mode 100644 index 00000000..f21d377b Binary files /dev/null and b/images/WFT2.png differ diff --git a/images/dd_img1.jpg b/images/dd_img1.jpg new file mode 100644 index 00000000..25606e5e Binary files /dev/null and b/images/dd_img1.jpg differ diff --git a/images/dd_img10.jpg b/images/dd_img10.jpg new file mode 100644 index 00000000..898d7589 Binary files /dev/null and b/images/dd_img10.jpg differ diff --git a/images/dd_img11.png b/images/dd_img11.png new file mode 100644 index 00000000..66a3a3a5 Binary files /dev/null and b/images/dd_img11.png differ diff --git a/images/dd_img2.png b/images/dd_img2.png new file mode 100644 index 00000000..2709f734 Binary files /dev/null and b/images/dd_img2.png differ diff --git a/images/dd_img3.png b/images/dd_img3.png new file mode 100644 index 00000000..e01e4faf Binary files /dev/null and b/images/dd_img3.png differ diff --git a/images/dd_img4.jpg b/images/dd_img4.jpg new file mode 100644 index 00000000..88827f50 Binary files /dev/null and b/images/dd_img4.jpg differ diff --git a/images/dd_img5.gif b/images/dd_img5.gif new file mode 100644 index 00000000..ae94aa46 Binary files /dev/null and b/images/dd_img5.gif differ diff --git a/images/dd_img6.gif b/images/dd_img6.gif new file mode 100644 index 00000000..61ed7314 Binary files /dev/null and b/images/dd_img6.gif differ diff --git a/images/dd_img7.jpg b/images/dd_img7.jpg new file mode 100644 index 00000000..53cd1f45 Binary files /dev/null and b/images/dd_img7.jpg differ diff --git a/images/dd_img8.jpg b/images/dd_img8.jpg new file mode 100644 index 00000000..a3729499 Binary files /dev/null and b/images/dd_img8.jpg differ diff --git a/images/dd_img9.jpg b/images/dd_img9.jpg new file mode 100644 index 00000000..f511d9f4 Binary files /dev/null and b/images/dd_img9.jpg differ diff --git a/images/m1-abs_value_noise.PNG b/images/m1-abs_value_noise.PNG new file mode 100644 index 00000000..cf5dd93e Binary files /dev/null and b/images/m1-abs_value_noise.PNG differ diff --git a/images/m1-ridged_value_noise.PNG b/images/m1-ridged_value_noise.PNG new file mode 100644 index 00000000..a60e6a7a Binary files /dev/null and b/images/m1-ridged_value_noise.PNG differ diff --git a/images/m1-texture1.PNG b/images/m1-texture1.PNG new file mode 100644 index 00000000..bdff8652 Binary files /dev/null and b/images/m1-texture1.PNG differ diff --git a/images/m1-texture2.PNG b/images/m1-texture2.PNG new file mode 100644 index 00000000..1e63cf9b Binary files /dev/null and b/images/m1-texture2.PNG differ diff --git a/images/m1-value_2nd_derivative.PNG b/images/m1-value_2nd_derivative.PNG new file mode 100644 index 00000000..dc4129e6 Binary files /dev/null and b/images/m1-value_2nd_derivative.PNG differ diff --git a/images/m1-value_noise.PNG b/images/m1-value_noise.PNG new file mode 100644 index 00000000..fd9d5b10 Binary files /dev/null and b/images/m1-value_noise.PNG differ diff --git a/images/presentation/Screenshot (25)(1).png b/images/presentation/Screenshot (25)(1).png new file mode 100644 index 00000000..c405776e Binary files /dev/null and b/images/presentation/Screenshot (25)(1).png differ diff --git a/images/presentation/Screenshot_1.png b/images/presentation/Screenshot_1.png new file mode 100644 index 00000000..c405776e Binary files /dev/null and b/images/presentation/Screenshot_1.png differ diff --git a/images/presentation/coarse_bounding.png b/images/presentation/coarse_bounding.png new file mode 100644 index 00000000..3aa34db5 Binary files /dev/null and b/images/presentation/coarse_bounding.png differ diff --git a/images/presentation/coarse_wire.png b/images/presentation/coarse_wire.png new file mode 100644 index 00000000..21e19a6f Binary files /dev/null and b/images/presentation/coarse_wire.png differ diff --git a/images/presentation/final_base.png b/images/presentation/final_base.png new file mode 100644 index 00000000..373fa426 Binary files /dev/null and b/images/presentation/final_base.png differ diff --git a/images/presentation/final_base_green.png b/images/presentation/final_base_green.png new file mode 100644 index 00000000..7dfbf4f6 Binary files /dev/null and b/images/presentation/final_base_green.png differ diff --git a/images/presentation/final_base_green_voro.png b/images/presentation/final_base_green_voro.png new file mode 100644 index 00000000..3ed2285d Binary files /dev/null and b/images/presentation/final_base_green_voro.png differ diff --git a/images/presentation/final_base_green_voro_snow.png b/images/presentation/final_base_green_voro_snow.png new file mode 100644 index 00000000..831828b0 Binary files /dev/null and b/images/presentation/final_base_green_voro_snow.png differ diff --git a/images/presentation/final_img.png b/images/presentation/final_img.png new file mode 100644 index 00000000..f75a79e7 Binary files /dev/null and b/images/presentation/final_img.png differ diff --git a/images/presentation/final_shaded.png b/images/presentation/final_shaded.png new file mode 100644 index 00000000..5238cf5d Binary files /dev/null and b/images/presentation/final_shaded.png differ diff --git a/images/presentation/final_value.png b/images/presentation/final_value.png new file mode 100644 index 00000000..0618845b Binary files /dev/null and b/images/presentation/final_value.png differ diff --git a/images/presentation/fine_bounding.png b/images/presentation/fine_bounding.png new file mode 100644 index 00000000..cf246044 Binary files /dev/null and b/images/presentation/fine_bounding.png differ diff --git a/images/presentation/fine_flat.png b/images/presentation/fine_flat.png new file mode 100644 index 00000000..ae957a3d Binary files /dev/null and b/images/presentation/fine_flat.png differ diff --git a/images/presentation/fine_shaded.png b/images/presentation/fine_shaded.png new file mode 100644 index 00000000..6a841cbe Binary files /dev/null and b/images/presentation/fine_shaded.png differ diff --git a/images/presentation/fine_wire.png b/images/presentation/fine_wire.png new file mode 100644 index 00000000..8ae29875 Binary files /dev/null and b/images/presentation/fine_wire.png differ diff --git a/images/presentation/sine_noise.png b/images/presentation/sine_noise.png new file mode 100644 index 00000000..01dd3a4a Binary files /dev/null and b/images/presentation/sine_noise.png differ diff --git a/images/presentation/value.png b/images/presentation/value.png new file mode 100644 index 00000000..98364675 Binary files /dev/null and b/images/presentation/value.png differ diff --git a/images/presentation/value_abs.png b/images/presentation/value_abs.png new file mode 100644 index 00000000..1adcd35e Binary files /dev/null and b/images/presentation/value_abs.png differ diff --git a/images/presentation/value_ridged.png b/images/presentation/value_ridged.png new file mode 100644 index 00000000..95040b61 Binary files /dev/null and b/images/presentation/value_ridged.png differ diff --git a/images/presentation/voro.png b/images/presentation/voro.png new file mode 100644 index 00000000..8c928e7f Binary files /dev/null and b/images/presentation/voro.png differ diff --git a/images/presentation/voro_diff.png b/images/presentation/voro_diff.png new file mode 100644 index 00000000..d54e6ee3 Binary files /dev/null and b/images/presentation/voro_diff.png differ diff --git a/images/presentation/voro_mul.png b/images/presentation/voro_mul.png new file mode 100644 index 00000000..7e36ed15 Binary files /dev/null and b/images/presentation/voro_mul.png differ diff --git a/images/presentation/voro_mul_small.png b/images/presentation/voro_mul_small.png new file mode 100644 index 00000000..cea09d57 Binary files /dev/null and b/images/presentation/voro_mul_small.png differ diff --git a/images/presentation/voro_v0xv1.png b/images/presentation/voro_v0xv1.png new file mode 100644 index 00000000..3cf0d849 Binary files /dev/null and b/images/presentation/voro_v0xv1.png differ diff --git a/images/report/increase_detail.gif b/images/report/increase_detail.gif new file mode 100644 index 00000000..8c3c5c94 Binary files /dev/null and b/images/report/increase_detail.gif differ diff --git a/images/report/terrain/Screen Shot 2017-04-30 at 7.40.35 PM.png b/images/report/terrain/Screen Shot 2017-04-30 at 7.40.35 PM.png new file mode 100644 index 00000000..9b47db24 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-04-30 at 7.40.35 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-04-30 at 7.40.53 PM.png b/images/report/terrain/Screen Shot 2017-04-30 at 7.40.53 PM.png new file mode 100644 index 00000000..d50c7cd6 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-04-30 at 7.40.53 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-04-30 at 7.41.00 PM.png b/images/report/terrain/Screen Shot 2017-04-30 at 7.41.00 PM.png new file mode 100644 index 00000000..e34a37f0 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-04-30 at 7.41.00 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-04-30 at 7.41.10 PM.png b/images/report/terrain/Screen Shot 2017-04-30 at 7.41.10 PM.png new file mode 100644 index 00000000..aca89f0c Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-04-30 at 7.41.10 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-04-30 at 7.41.35 PM.png b/images/report/terrain/Screen Shot 2017-04-30 at 7.41.35 PM.png new file mode 100644 index 00000000..3b3d1d72 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-04-30 at 7.41.35 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-01 at 1.45.20 PM.png b/images/report/terrain/Screen Shot 2017-05-01 at 1.45.20 PM.png new file mode 100644 index 00000000..84f703bf Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-01 at 1.45.20 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-01 at 1.45.27 PM.png b/images/report/terrain/Screen Shot 2017-05-01 at 1.45.27 PM.png new file mode 100644 index 00000000..1b908259 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-01 at 1.45.27 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-01 at 1.46.06 PM.png b/images/report/terrain/Screen Shot 2017-05-01 at 1.46.06 PM.png new file mode 100644 index 00000000..683cc5c3 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-01 at 1.46.06 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-02 at 1.11.27 PM.png b/images/report/terrain/Screen Shot 2017-05-02 at 1.11.27 PM.png new file mode 100644 index 00000000..1c9c8f80 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-02 at 1.11.27 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-02 at 1.11.34 PM.png b/images/report/terrain/Screen Shot 2017-05-02 at 1.11.34 PM.png new file mode 100644 index 00000000..2d087b9c Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-02 at 1.11.34 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-02 at 1.11.48 PM.png b/images/report/terrain/Screen Shot 2017-05-02 at 1.11.48 PM.png new file mode 100644 index 00000000..447b22ca Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-02 at 1.11.48 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-02 at 2.16.27 PM.png b/images/report/terrain/Screen Shot 2017-05-02 at 2.16.27 PM.png new file mode 100644 index 00000000..19ddf97a Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-02 at 2.16.27 PM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-03 at 11.52.39 AM.png b/images/report/terrain/Screen Shot 2017-05-03 at 11.52.39 AM.png new file mode 100644 index 00000000..543172b4 Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-03 at 11.52.39 AM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-03 at 11.53.14 AM.png b/images/report/terrain/Screen Shot 2017-05-03 at 11.53.14 AM.png new file mode 100644 index 00000000..a5fa2b3a Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-03 at 11.53.14 AM.png differ diff --git a/images/report/terrain/Screen Shot 2017-05-03 at 11.53.43 AM.png b/images/report/terrain/Screen Shot 2017-05-03 at 11.53.43 AM.png new file mode 100644 index 00000000..af055f7e Binary files /dev/null and b/images/report/terrain/Screen Shot 2017-05-03 at 11.53.43 AM.png differ diff --git a/images/report/terrain/Tile_Terrain_W_N_S.png b/images/report/terrain/Tile_Terrain_W_N_S.png new file mode 100644 index 00000000..a91f875c Binary files /dev/null and b/images/report/terrain/Tile_Terrain_W_N_S.png differ diff --git a/images/report/terrain/Tile_terrain_W_N.png b/images/report/terrain/Tile_terrain_W_N.png new file mode 100644 index 00000000..273656df Binary files /dev/null and b/images/report/terrain/Tile_terrain_W_N.png differ diff --git a/images/report/terrain/Tile_terrain_W_textured.png b/images/report/terrain/Tile_terrain_W_textured.png new file mode 100644 index 00000000..68de62d0 Binary files /dev/null and b/images/report/terrain/Tile_terrain_W_textured.png differ diff --git a/images/report/terrain/Tile_terrain_Wo_N.png b/images/report/terrain/Tile_terrain_Wo_N.png new file mode 100644 index 00000000..983e8dd8 Binary files /dev/null and b/images/report/terrain/Tile_terrain_Wo_N.png differ diff --git a/images/report/terrainimg.png b/images/report/terrainimg.png new file mode 100644 index 00000000..eaa86fbb Binary files /dev/null and b/images/report/terrainimg.png differ diff --git a/images/report/texture.gif b/images/report/texture.gif new file mode 100644 index 00000000..336ab6ce Binary files /dev/null and b/images/report/texture.gif differ diff --git a/images/report/textureimg.png b/images/report/textureimg.png new file mode 100644 index 00000000..98c46db7 Binary files /dev/null and b/images/report/textureimg.png differ diff --git a/images/shadercesium.gif b/images/shadercesium.gif new file mode 100644 index 00000000..fdbca664 Binary files /dev/null and b/images/shadercesium.gif differ diff --git a/images/sinenoise.gif b/images/sinenoise.gif new file mode 100644 index 00000000..9f2c1305 Binary files /dev/null and b/images/sinenoise.gif differ diff --git a/milestone reports/milestone1.md b/milestone reports/milestone1.md new file mode 100644 index 00000000..e81b1a91 --- /dev/null +++ b/milestone reports/milestone1.md @@ -0,0 +1,76 @@ +### Milestone-1 Report: + +### Rishabh + +- I tried setting up Cesium and the server we will be using to send the data to cesium. I spent an entire day trying to get cesium to work but it just won't. So I downloaded an older version, and it worked. But I still can't get the server to work. So for now, my code is in [this](https://github.com/rms13/Project1-Noise) repo. Rudraksha is looking into the server issue. + +- `shaders/mountain-frag.glsl` fragment shader contains the shader that textures the mountain. Value Noise algorithm is used as the noise generator. It is a slightly modified version (the noise function and the matrices are different) of what IQ shows [here](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm). The derivatives of noise are used to simulate erosion effects. It still needs some work. + +- `shaders/mountain-vert.glsl` vertex shader uses Ridged Value Noise to model mountains. This is *not* the terrain we will be using for the final version. It's used only for testing the texture. The terrain part (using Diamond Square algorithm) is being done by [Rudraksha](https://github.com/rudraksha20). + +- Demo: https://github.com/rms13/Project1-Noise + +#### Example images: + +Value noise: + +![](../images/m1-value_noise.PNG) + +Absolute value noise: + +![](../images/m1-abs_value_noise.PNG) + +Ridged value noise: + +![](../images/m1-ridged_value_noise.PNG) + +2nd derivative of value noise: + +![](../images/m1-value_2nd_derivative.PNG) + +Example texture: + +![](../images/m1-texture1.PNG) + +Example texture with terrain: + +![](../images/m1-texture2.PNG) + + +### Rudraksha Shah + +#### Procedural Terrain: + +`Main.js:` contains the implementation of the Diamond Square algorithm that I have implemented to procedurally generate the terrain. + +`TODO:` I am working on improving the terrain structure and removing the artifacts created by the random number and the diamond square algorithm. + +`Diamond Square Algorithm:` consists of the following main steps + +- Initial Grid: + +![](../images/IV.png) + +- The Diamond Step + +![](../images/DS.png) + +- The Square Step + +![](../images/SS.png) + + + +### Tessellated Terrain Mesh Images: + +![](../images/T1.png) + +![](../images/T2.png) + +### Tessellated Terrain WireFrame Images: + +![](../images/WFT1.png) + +![](../images/WFT2.png) + +- Demo: https://rudraksha20.github.io/Final-Project/ diff --git a/milestone reports/milestone2.md b/milestone reports/milestone2.md new file mode 100644 index 00000000..893ea48c --- /dev/null +++ b/milestone reports/milestone2.md @@ -0,0 +1,36 @@ +### Milestone-2 Report: + +### Rishabh + +- Finally we have the server thanks to Austin!! We haven't merged our code, so it is not yet deployed. The texture does not become more defined as you go closer as I have hardcoded the number of octaves. I will be changing them based on the viewer distance to change the levels of detail. + +![](../images/shadercesium.gif) + + +- `shaders/sinenoise-frag.glsl` fragment shader is an accidental marble texture that I did not intend to make. + + I found articles on warping noise functions with other noise functions while looking up Voronoi diagrams. I thought I could use the Ridged noise with just sine functions to get cool streams and rivers. [cegaton](https://blender.stackexchange.com/questions/45892/is-it-possible-to-distort-a-voronoi-texture-like-the-wave-textures-distortion-sl) does it using voronoise. + + So I tried it, and It looks more like marble than rivers. I don't think it will work for this project. + + I am still understanding voronoise and how to integrate it to the texture I already have. + +![](../images/sinenoise.gif) + +- Demo (of marble texture): https://rms13.github.io/Project1-Noise +- Source: https://github.com/rms13/Project1-Noise + + +### Rudraksha Shah + + + +- With the server working (thanks to Austin!) I worked on setting up the tiles of the sphere to procedurally generate the terrain andf render it out per tile. I was able to get the terrain (though flat) to show up instead of each tile but I am having issues with the normals which is why I do not have any Images to show as mostly everything looks black without shading. + + + +- Also as the code is not working correctly I have not pushed it to git will do as soon as I get it up and running. + + + +- For the future I will work on either gerenating the terrain with spherical coordinates as is the way Austin has gave us the implementation or will change the code to render a flat 2D plane which renders tiles which I will use to render the terrain. diff --git a/source/demo/index.html b/source/demo/index.html new file mode 100644 index 00000000..d7a86947 --- /dev/null +++ b/source/demo/index.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/source/demo/main.js b/source/demo/main.js new file mode 100644 index 00000000..dce55700 --- /dev/null +++ b/source/demo/main.js @@ -0,0 +1,18 @@ + +/*global Cesium*/ + +var viewer = new Cesium.Viewer('cesiumContainer', { + +}); + +var scene = viewer.scene; +scene.globe.show = false; + +var tileset = new Cesium.Cesium3DTileset({ + url: '/' +}); + +scene.primitives.add(tileset); + +viewer.extend(Cesium.viewerCesium3DTilesInspectorMixin); +viewer.cesium3DTilesInspector.viewModel.tileset = tileset; \ No newline at end of file diff --git a/source/package.json b/source/package.json new file mode 100644 index 00000000..4daa7148 --- /dev/null +++ b/source/package.json @@ -0,0 +1,22 @@ +{ + "scripts": { + "start": "nodemon server.js --ignore example/", + "serve": "node server.js", + "postinstall": "cd cesium && npm install", + "build": "cd cesium && npm run release" + }, + "dependencies": { + "3d-tiles-tools": "^0.1.2", + "cesium": "^1.32.1", + "compression": "^1.6.2", + "express": "^4.15.2", + "gltf-pipeline": "0.1.0-alpha11", + "morgan": "^1.8.1", + "three": "^0.85.2", + "yargs": "^7.0.2" + }, + "devDependencies": { + "gh-pages-deploy": "^0.4.2", + "nodemon": "^1.11.0" + } +} diff --git a/source/server.js b/source/server.js new file mode 100644 index 00000000..5f773abf --- /dev/null +++ b/source/server.js @@ -0,0 +1,96 @@ +'use strict'; + +(function() { + // Parse options to start server + const yargs = require('yargs').options({ + port: { + default: 3000, + description: 'Port to listen on.' + }, + public: { + type: 'boolean', + description: 'Run a public server that listens on all interfaces.' + }, + help: { + alias: 'h', + type: 'boolean', + description: 'Show this help' + } + }); + const argv = yargs.argv; + + if (argv.help) { + return yargs.showHelp(); + } + + const express = require('express'); + const compression = require('compression'); + const path = require('path'); + const logger = require('morgan'); + + const app = express(); + app.use(compression()); + app.use(function(req, res, next) { + res.header("Access-Control-Allow-Origin", "*"); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + next(); + }); + app.use(logger('tiny')); + app.set('json spaces', 2); + + const server = app.listen(argv.port, argv.public ? undefined : 'localhost', function() { + console.log('Terrain server running at http://%s:%d/', server.address().address, server.address().port); + }); + + const options = { + generationDepth: 3, + rootError: 2500000, + errorFactor: 0.5, + worldRadius: 6378137, + maxHeight: 100000 + }; + + const TreeProvider = require('./treeProvider'); + const TerrainProvider = require('./terrainProvider'); + + var treeProvider = new TreeProvider(options); + var terrainProvider = new TerrainProvider(treeProvider); + + app.get('/tileset.json', function(req, res) { + res.json({ + asset: { + version: '0.0', + gltfUpAxis: 'Z' + }, + geometricError: options.rootError, + root: treeProvider.getRoot() + }); + }); + + app.get('/(:hemisphere)_(:index).json', function(req, res) { + const index = req.params.index; + const hemisphere = req.params.hemisphere; + + var node = treeProvider.generateNode(hemisphere, parseInt(index), 0); + res.json({ + asset: { + version: '0.0' + }, + geometricError: node.geometricError, + root: node + }); + }); + + app.get('/(:hemisphere)_(:index).b3dm', function(req, res) { + const index = req.params.index; + const hemisphere = req.params.hemisphere; + + terrainProvider.generateTerrain(hemisphere, parseInt(index)).then(function(terrain) { + res.send(terrain); + }); + }); + + app.use('/Cesium', express.static(path.join(__dirname, 'cesium/Build/Cesium'))); + app.use('/', express.static(__dirname)); + +})(); \ No newline at end of file diff --git a/source/shaders/terrainFS.glsl b/source/shaders/terrainFS.glsl new file mode 100644 index 00000000..20614be6 --- /dev/null +++ b/source/shaders/terrainFS.glsl @@ -0,0 +1,143 @@ +// FINAL FRAGMENT SHADER FOR TEXTURING THE TERRAIN + +precision highp float; +varying vec3 v_normal; +uniform vec4 u_diffuse; +varying vec3 noisefs; +varying vec3 pos; + +// NOISE FUNCTIONS FROM: http://www.science-and-fiction.org/rendering/noise.html +float rand2D(in vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} +float rand3D(in vec3 co){ + return fract(sin(dot(co.xyz ,vec3(12.9898,78.233,144.7272))) * 43758.5453); +} + +// iq's value noise algorithm: +vec4 noised( in vec3 x ) +{ + vec3 p = floor(x); + vec3 w = fract(x); + + vec3 u = w*w*w*(w*(w*6.0-15.0)+10.0); + vec3 du = 30.0*w*w*(w*(w-2.0)+1.0); + + float a = rand3D( p+vec3(0,0,0) ); + float b = rand3D( p+vec3(1,0,0) ); + float c = rand3D( p+vec3(0,1,0) ); + float d = rand3D( p+vec3(1,1,0) ); + float e = rand3D( p+vec3(0,0,1) ); + float f = rand3D( p+vec3(1,0,1) ); + float g = rand3D( p+vec3(0,1,1) ); + float h = rand3D( p+vec3(1,1,1) ); + + float k0 = a; + float k1 = b - a; + float k2 = c - a; + float k3 = e - a; + float k4 = a - b - c + d; + float k5 = a - c - e + g; + float k6 = a - b - e + f; + float k7 = - a + b + c - d + e - f - g + h; + + return vec4( -1.0 + 2.0* (k0 + k1*u.x + k2*u.y + k3*u.z + k4*u.x*u.y + k5*u.y*u.z + k6*u.z*u.x + k7*u.x*u.y*u.z), + 2.0 * du * vec3( k1 + k4*u.y + k6*u.z + k7*u.y*u.z, k2 + k5*u.z + k4*u.x + k7*u.z*u.x, k3 + k6*u.x + k5*u.y + k7*u.x*u.y ) ); +} + + +const mat3 m3 = mat3( 0.00, 0.80, 0.60, + -0.80, 0.36,-0.48, + -0.60,-0.48, 0.64 ); +const mat3 m3i = mat3( 0.00,-0.80,-0.60, + 0.80, 0.36,-0.48, + 0.60,-0.48, 0.64 ); +// FBM - PROCESSING FOR OCTAVES AND ACCUMULATING DERIVATIVES +vec4 fbm( in vec3 x) +{ + float f = 2.0; + float s = 0.5; + float a = 0.0; + float b = 0.5; + vec3 d = vec3(0.0); + mat3 m = mat3( 1.00, 0.00, 0.00, + 0.00, 1.00, 0.00, + 0.00, 0.00, 1.00); + + for( int i=0; i < 12; i++ ) // 0..octaves + { + vec4 n = noised(x); + //n = 1.0 - abs(n); // UNCOMMENT FOR RIDGED NOISE + + a += b*n.x; + d += b*m*n.yzw; + b *= s; + x = f*m3*x; + m = f*m3i*m; + } + return vec4( a, d ); +} + +vec2 voronoi( in vec3 x) +{ + vec3 p = floor( x ); + vec3 f = fract( x ); + vec2 res = vec2( 8.0 ); + for( int k=-1; k<=1; k++ ) + for( int j=-1; j<=1; j++ ) + for( int i=-1; i<=1; i++ ) + { + vec3 b = vec3( float(i), float(j), float(k) ); + vec3 r = vec3( b ) - f + rand3D( p + b ); + float d = dot( r, r ); + if( d < res.x ) + res = vec2( d, res.x ); + else if( d < res.y ) + res.y = d; + } + + return vec2(sqrt(res)); +} + +void main() +{ + vec4 n = fbm(pos); // Value Noise + vec2 voro = voronoi((200.0*pos)); // Multiplier controls the size of the voronoi regions. + + float nfs = noisefs[0]*0.5+0.5; + + vec3 col; + vec3 colBase; + vec3 colSnow; + vec3 colForest; + + //Distorting voronoi and noise with sine + float vn = (1.0+(sin((n[0])*10.0)/2.0))*voro[1]*voro[0]; + + // BASE + colBase = mix(vec3(0.1,0.1,0.1),vec3(0.45,0.35,0.3),vn); + colBase = mix(colBase,vec3(0.15,0.15,0.15),n[0]*nfs); + + // FOREST + colForest = mix(vec3(0.1,0.15,0.05),vec3(0.15,0.20,0.13),vn); + colForest = mix(colForest,colBase,n[0]*nfs); + colBase = mix(colForest,colBase,0.5+0.5*n[0]*nfs); + + // SNOW + colSnow = vec3(1.,0.98,0.98); // SNOW: 255,250,250 + col = mix(colBase,colSnow,(nfs-3.0*n[0]-2.0*n[1]-n[2])/10.0); + + col = max(colBase,col); // CLAMPING LOWEST VALUES TO BASE COLOR + + // DIFFUSE LIGHTING + vec4 color = vec4(col, 0.); + vec4 diffuse = vec4(0., 0., 0., 1.); + diffuse = vec4(0.95, 0.95, 0.95, 1.); + vec3 normal = normalize(v_normal); + diffuse.xyz *= max(dot(v_normal,normalize(vec3(1.,1.,2.))), 0.05); + color.xyz *= diffuse.xyz; + color = vec4(color.rgb * diffuse.a, diffuse.a); + + float gamma = 2.2; + gl_FragColor = vec4( pow(color.rgb, vec3(1.0/gamma)) , 1.0 ); +} diff --git a/source/shaders/terrainVS.glsl b/source/shaders/terrainVS.glsl new file mode 100644 index 00000000..7fbc8dc2 --- /dev/null +++ b/source/shaders/terrainVS.glsl @@ -0,0 +1,19 @@ +precision highp float; +attribute vec3 a_position; +attribute vec3 a_normal; +varying vec3 v_normal; +uniform mat3 u_normalMatrix; +uniform mat4 u_modelViewMatrix; +uniform mat4 u_projectionMatrix; +varying vec3 pos; +attribute vec3 a_noise; +varying vec3 noisefs; + +void main(void) +{ + vec4 pos1 = u_modelViewMatrix * vec4(a_position,1.0); + v_normal = u_normalMatrix * a_normal;//u_normalMatrix * a_normal; + pos = vec3(a_position/8000000.0);//a_normal; + noisefs= a_noise; + gl_Position = u_projectionMatrix * pos1; +} diff --git a/source/shaders/test shaders/RidgedValueTerrain-vert.glsl b/source/shaders/test shaders/RidgedValueTerrain-vert.glsl new file mode 100644 index 00000000..e81e3f9b --- /dev/null +++ b/source/shaders/test shaders/RidgedValueTerrain-vert.glsl @@ -0,0 +1,94 @@ +// Ridged Value noise terrain used for terrain generation for testing the shaders. +// Actual terrain is being modeled in terrainProvider.js + +varying vec2 vUv; +varying vec3 pos; +uniform bool Terrain; + +// NOISE FUNCTIONS FROM: http://www.science-and-fiction.org/rendering/noise.html +float rand2D(in vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} +float rand3D(in vec3 co){ + return fract(sin(dot(co.xyz ,vec3(12.9898,78.233,144.7272))) * 43758.5453); +} + +// iq's value noise algorithm: +vec4 noised( in vec3 x ) +{ + vec3 p = floor(x); + vec3 w = fract(x); + + vec3 u = w*w*w*(w*(w*6.0-15.0)+10.0); + vec3 du = 30.0*w*w*(w*(w-2.0)+1.0); + + float a = rand3D( p+vec3(0,0,0) ); + float b = rand3D( p+vec3(1,0,0) ); + float c = rand3D( p+vec3(0,1,0) ); + float d = rand3D( p+vec3(1,1,0) ); + float e = rand3D( p+vec3(0,0,1) ); + float f = rand3D( p+vec3(1,0,1) ); + float g = rand3D( p+vec3(0,1,1) ); + float h = rand3D( p+vec3(1,1,1) ); + + float k0 = a; + float k1 = b - a; + float k2 = c - a; + float k3 = e - a; + float k4 = a - b - c + d; + float k5 = a - c - e + g; + float k6 = a - b - e + f; + float k7 = - a + b + c - d + e - f - g + h; + + return vec4( -1.0 + 2.0 * (k0 + k1*u.x + k2*u.y + k3*u.z + k4*u.x*u.y + k5*u.y*u.z + k6*u.z*u.x + k7*u.x*u.y*u.z), + 2.0 * du * vec3( k1 + k4*u.y + k6*u.z + k7*u.y*u.z, k2 + k5*u.z + k4*u.x + k7*u.z*u.x, k3 + k6*u.x + k5*u.y + k7*u.x*u.y ) ); +} + + +const mat3 m3 = mat3( 0.00, 0.80, 0.60, + -0.80, 0.36,-0.48, + -0.60,-0.48, 0.64 ); +const mat3 m3i = mat3( 0.00,-0.80,-0.60, + 0.80, 0.36,-0.48, + 0.60,-0.48, 0.64 ); +// FBM - PROCESSING FOR OCTAVES AND ACCUMULATING DERIVATIVES +vec4 fbm( in vec3 x) +{ + float f = 2.0; // could be 2.0 + float s = 0.5; // could be 0.5 + float a = 0.0; + float b = 0.5; + vec3 d = vec3(0.0); + mat3 m = mat3( 1.00, 0.00, 0.00, + 0.00, 1.00, 0.00, + 0.00, 0.00, 1.00); + for( int i=0; i < 8; i++ ) // octaves = 8.. + { + vec4 n = noised(x); + // ADDING RIDGES + n = 1.0-abs(n); + a += b*n.x; + d += b*m*n.yzw; + b *= s; + x = f*m3*x; + m = f*m3i*m; + } + return vec4( a, d ); +} + +void main() +{ + vUv = uv; + + if(Terrain) + { + vec4 n = fbm(position); + pos = (n[0]*0.5+0.5) * normal; + } + else + { + pos=position; + } + + gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 ); +} diff --git a/source/shaders/test shaders/mountain-frag.glsl b/source/shaders/test shaders/mountain-frag.glsl new file mode 100644 index 00000000..20f07e81 --- /dev/null +++ b/source/shaders/test shaders/mountain-frag.glsl @@ -0,0 +1,151 @@ +// EXPERIMENTAL SHADER FOR BASE TEXTURE AND SNOW + +varying vec2 vUv; +varying vec3 pos; + +uniform float Red; +uniform float Green; +uniform float Blue; +uniform float Red1; +uniform float Green1; +uniform float Blue1; + +uniform float time; +uniform int NoiseType; +uniform bool Preset1; +//uniform sampler2D image; + +// NOISE FUNCTIONS FROM: +// http://www.science-and-fiction.org/rendering/noise.html +float rand2D(in vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} +float rand3D(in vec3 co){ + return fract(sin(dot(co.xyz ,vec3(12.9898,78.233,144.7272))) * 43758.5453); +} + +// iq's value noise algorithm: +vec4 noised( in vec3 x ) +{ + vec3 p = floor(x); + vec3 w = fract(x); + + vec3 u = w*w*w*(w*(w*6.0-15.0)+10.0); + vec3 du = 30.0*w*w*(w*(w-2.0)+1.0); + + float a = rand3D( p+vec3(0,0,0) ); + float b = rand3D( p+vec3(1,0,0) ); + float c = rand3D( p+vec3(0,1,0) ); + float d = rand3D( p+vec3(1,1,0) ); + float e = rand3D( p+vec3(0,0,1) ); + float f = rand3D( p+vec3(1,0,1) ); + float g = rand3D( p+vec3(0,1,1) ); + float h = rand3D( p+vec3(1,1,1) ); + + float k0 = a; + float k1 = b - a; + float k2 = c - a; + float k3 = e - a; + float k4 = a - b - c + d; + float k5 = a - c - e + g; + float k6 = a - b - e + f; + float k7 = - a + b + c - d + e - f - g + h; + + return vec4( -1.0+2.0*(k0 + k1*u.x + k2*u.y + k3*u.z + k4*u.x*u.y + k5*u.y*u.z + k6*u.z*u.x + k7*u.x*u.y*u.z), + 2.0* du * vec3( k1 + k4*u.y + k6*u.z + k7*u.y*u.z, + k2 + k5*u.z + k4*u.x + k7*u.z*u.x, + k3 + k6*u.x + k5*u.y + k7*u.x*u.y ) ); +} + + +const mat3 m3 = mat3( 0.00, 0.80, 0.60, + -0.80, 0.36,-0.48, + -0.60,-0.48, 0.64 ); +const mat3 m3i = mat3( 0.00,-0.80,-0.60, + 0.80, 0.36,-0.48, + 0.60,-0.48, 0.64 ); +// FBM - PROCESSING FOR OCTAVES AND ACCUMULATING DERIVATIVES +vec4 fbm( in vec3 x) +{ + float f = 2.0; // could be 2.0 + float s = 0.5; // could be 0.5 + float a = 0.0; + float b = 0.5; + vec3 d = vec3(0.0); + mat3 m = mat3( 1.00, 0.00, 0.00, + 0.00, 1.00, 0.00, + 0.00, 0.00, 1.00); + //int oct = octaves; + for( int i=0; i < 8; i++ ) // octaves = 8.. + { + vec4 n = noised(x); + // ADDING RIDGES + if(NoiseType==1 && !Preset1) // ABS NOISE + n = abs(n); + else if(NoiseType==2 && !Preset1) // RIDGED NOISE + n = 1.0-abs(n); + + a += b*n.x; // accumulate values + d += b*m*n.yzw; // accumulate derivatives + b *= s; + x = f*m3*x; + m = f*m3i*m; + } + return vec4( a, d ); +} + +void main() { + //gl_FragColor = vec4( noise3(pos), 1.0 ); + + vec4 n = fbm(time*pos); + //float random = rand3D(pos); + vec3 col; + vec3 colBase; + vec3 colSnow; + + if(Preset1) // MOUNTAINS SHADER + { + // EARTH TONES: http://www.varian.net/dreamview/dreamcolor/earth.html + // col = clamp(n[0]+1.0,0.5,1.0) * vec3(0.37,0.27,0.18); + + //colBase = mix(vec3(115.,69.,35.)/4.0,vec3(95.,71.,47.)/4.0,n[0]*length(pos)) / 255.; // BLENDING LAYERS: Grayish base + Brownish soil + fine-tuning using noise (height and n).. + + colBase = mix(vec3(0.2,0.2,0.2),vec3(0.4,0.35,0.3),n[2]/5.0); + colBase = mix(colBase,vec3(0.15,0.15,0.15),n[0]*length(pos)); + + colSnow = vec3(1.,0.98,0.98); // SNOW: 255,250,250 + + // COL : 1. Snow at higher altitudes (length(pos)) blended with some randomness (n[0]) to avoid hard edges at a fixed height. + // 2. Simulate erosion using derivatives (n[1],n[2]). + // - High altitude and snow accumulation (colSnow) -> low alt (colBase) + // - equivalent to (I guess) Higher noise value to lower noise value + // - equivalent to (I guess) subtracting the derivatives. Seems to work. + col = mix(colBase,colSnow,(length(pos)-3.0*n[0]-2.0*n[1]-n[2])/10.0); + + col = max(colBase,col); // CLAMPING LOWEST VALUES TO BASE COLOR + } + else // ADJUSTABLE COLORS FOR DEBUGGING + { + float no = n[0]; + float r = mix(Red,Red1,no); + float g = mix(Green,Green1,no); + float b = mix(Blue,Blue1,no); + + col = vec3(r,g,b); + + //col = vec3(n[0],n[0],n[0])*vec3(1.0,0.5,0.1)+vec3(0.2,0.2,0.2); + } + + col = sqrt(col); // gamma correction + gl_FragColor = vec4( col.rgb, 1.0 ); +} + + +/* // OLD SHADER - DOES NOTHING.. GETS THE COLOR FROM VERTEX SHADER AND PLOTS IT +void main() +{ + vec2 uv = vec2(1,1) - vUv; + vec4 color = texture2D( image, uv ); + gl_FragColor = vec4( color.rgb, 1.0 ); +} +*/ diff --git a/source/shaders/test shaders/sinenoise-frag.glsl b/source/shaders/test shaders/sinenoise-frag.glsl new file mode 100644 index 00000000..f1fadb00 --- /dev/null +++ b/source/shaders/test shaders/sinenoise-frag.glsl @@ -0,0 +1,140 @@ +// EXPERIMENTAL SHADER FOR BASE TEXTURE AND DISTORTION WITH SINE + +varying vec2 vUv; +varying vec3 pos; + +uniform float Red; +uniform float Green; +uniform float Blue; +uniform float Red1; +uniform float Green1; +uniform float Blue1; + +uniform float time; +uniform int NoiseType; +uniform bool Preset1; +uniform bool Preset2; +//uniform sampler2D image; + +// NOISE FUNCTIONS FROM: +// http://www.science-and-fiction.org/rendering/noise.html +float rand2D(in vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} +float rand3D(in vec3 co){ + return fract(sin(dot(co.xyz ,vec3(12.9898,78.233,144.7272))) * 43758.5453); +} + +// iq's value noise algorithm: +vec4 noised( in vec3 x ) +{ + vec3 p = floor(x); + vec3 w = fract(x); + + vec3 u = w*w*w*(w*(w*6.0-15.0)+10.0); + vec3 du = 30.0*w*w*(w*(w-2.0)+1.0); + + float a = rand3D( p+vec3(0,0,0) ); + float b = rand3D( p+vec3(1,0,0) ); + float c = rand3D( p+vec3(0,1,0) ); + float d = rand3D( p+vec3(1,1,0) ); + float e = rand3D( p+vec3(0,0,1) ); + float f = rand3D( p+vec3(1,0,1) ); + float g = rand3D( p+vec3(0,1,1) ); + float h = rand3D( p+vec3(1,1,1) ); + + float k0 = a; + float k1 = b - a; + float k2 = c - a; + float k3 = e - a; + float k4 = a - b - c + d; + float k5 = a - c - e + g; + float k6 = a - b - e + f; + float k7 = - a + b + c - d + e - f - g + h; + + return vec4( -1.0 + 2.0 * (k0 + k1*u.x + k2*u.y + k3*u.z + k4*u.x*u.y + k5*u.y*u.z + k6*u.z*u.x + k7*u.x*u.y*u.z), + 2.0 * du * vec3( k1 + k4*u.y + k6*u.z + k7*u.y*u.z, k2 + k5*u.z + k4*u.x + k7*u.z*u.x, k3 + k6*u.x + k5*u.y + k7*u.x*u.y ) ); +} + + +const mat3 m3 = mat3( 0.00, 0.80, 0.60, + -0.80, 0.36,-0.48, + -0.60,-0.48, 0.64 ); +const mat3 m3i = mat3( 0.00,-0.80,-0.60, + 0.80, 0.36,-0.48, + 0.60,-0.48, 0.64 ); +// FBM - PROCESSING FOR OCTAVES AND ACCUMULATING DERIVATIVES +vec4 fbm( in vec3 x) +{ + float f = 2.0; // could be 2.0 + float s = 0.5; // could be 0.5 + float a = 0.0; + float b = 0.5; + vec3 d = vec3(0.0); + mat3 m = mat3( 1.00, 0.00, 0.00, + 0.00, 1.00, 0.00, + 0.00, 0.00, 1.00); + + for( int i=0; i < 8; i++ ) // octaves = 8.. + { + vec4 n = noised(x); + // ADDING RIDGES + if(NoiseType==1 && !Preset1) // ABS NOISE + n = abs(n); + else if(NoiseType==2 && !Preset1) // RIDGED NOISE + n = 1.0-abs(n); + + a += b*n.x; + d += b*m*n.yzw; + b *= s; + x = f*m3*x; + m = f*m3i*m; + } + return vec4( a, d ); +} + +void main() { + + vec4 n = fbm(time*pos); + vec3 col; + vec3 colBase; + vec3 colSnow; + + if(Preset1) // MOUNTAINS SHADER + { + // EARTH TONES: http://www.varian.net/dreamview/dreamcolor/earth.html + // col = clamp(n[0]+1.0,0.5,1.0) * vec3(0.37,0.27,0.18); + + //n[0] =(1.0+(sin(n[0]*60.0)/2.0)); + + colBase = mix(vec3(115.,69.,35.)/4.0,vec3(95.,71.,47.)/4.0,n[0]*length(pos)) / 255.; // BLENDING LAYERS: Grayish base + Brownish soil + fine-tuning using noise (height and n).. + colSnow = vec3(1.,0.98,0.98); // SNOW: 255,250,250 + + // COL : 1. Snow at higher altitudes (length(pos)) blended with some randomness (n[0]) to avoid hard edges at a fixed height. + // 2. Simulate erosion using derivatives (n[1],n[2]). + // - High altitude and snow accumulation (colSnow) -> low alt (colBase) + // - equivalent to (I guess) Higher noise value to lower noise value + // - equivalent to (I guess) subtracting the derivatives. Seems to work. + col = mix(colBase,colSnow,(length(pos)-3.0*n[0]-2.0*n[1]-n[2])/5.0); + + col = max(colBase,col); // CLAMPING LOWEST VALUES TO BASE COLOR + } + else // ADJUSTABLE COLORS FOR DEBUGGING + { + float no = n[0]; + //col = vec3(1.0+(sin((pos.x*10.0+n[0])*60.0)/2.0)); + if(Preset2) + col = vec3(1.0+(sin((n[0])*60.0)/2.0)); + else + { + float r = mix(Red,Red1,no); + float g = mix(Green,Green1,no); + float b = mix(Blue,Blue1,no); + col = vec3(r,g,b); + } + //col = vec3(n[0],n[0],n[0])*vec3(1.0,0.5,0.1)+vec3(0.2,0.2,0.2); + } + + col = sqrt(col); // gamma correction + gl_FragColor = vec4( col.rgb, 1.0 ); +} diff --git a/source/shaders/test shaders/voronoi-frag.glsl b/source/shaders/test shaders/voronoi-frag.glsl new file mode 100644 index 00000000..815629fd --- /dev/null +++ b/source/shaders/test shaders/voronoi-frag.glsl @@ -0,0 +1,206 @@ +// EXPERIMENTAL SHADER FOR VORONOI AND BLENDING WITH NOISE + +varying vec2 vUv; +varying vec3 pos; + +uniform float Red; +uniform float Green; +uniform float Blue; +uniform float Red1; +uniform float Green1; +uniform float Blue1; + +uniform float time; +uniform int NoiseType; +uniform bool Preset1; +uniform bool Preset2; + +// NOISE FUNCTIONS FROM: http://www.science-and-fiction.org/rendering/noise.html +float rand2D(in vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} +float rand3D(in vec3 co){ + return fract(sin(dot(co.xyz ,vec3(12.9898,78.233,144.7272))) * 43758.5453); +} + +// iq's value noise algorithm: +vec4 noised( in vec3 x ) +{ + vec3 p = floor(x); + vec3 w = fract(x); + + vec3 u = w*w*w*(w*(w*6.0-15.0)+10.0); + vec3 du = 30.0*w*w*(w*(w-2.0)+1.0); + + float a = rand3D( p+vec3(0,0,0) ); + float b = rand3D( p+vec3(1,0,0) ); + float c = rand3D( p+vec3(0,1,0) ); + float d = rand3D( p+vec3(1,1,0) ); + float e = rand3D( p+vec3(0,0,1) ); + float f = rand3D( p+vec3(1,0,1) ); + float g = rand3D( p+vec3(0,1,1) ); + float h = rand3D( p+vec3(1,1,1) ); + + float k0 = a; + float k1 = b - a; + float k2 = c - a; + float k3 = e - a; + float k4 = a - b - c + d; + float k5 = a - c - e + g; + float k6 = a - b - e + f; + float k7 = - a + b + c - d + e - f - g + h; + + return vec4( -1.0+2.0*(k0 + k1*u.x + k2*u.y + k3*u.z + k4*u.x*u.y + k5*u.y*u.z + k6*u.z*u.x + k7*u.x*u.y*u.z), + 2.0* du * vec3( k1 + k4*u.y + k6*u.z + k7*u.y*u.z, + k2 + k5*u.z + k4*u.x + k7*u.z*u.x, + k3 + k6*u.x + k5*u.y + k7*u.x*u.y ) ); +} + + +const mat3 m3 = mat3( 0.00, 0.80, 0.60, + -0.80, 0.36,-0.48, + -0.60,-0.48, 0.64 ); +const mat3 m3i = mat3( 0.00,-0.80,-0.60, + 0.80, 0.36,-0.48, + 0.60,-0.48, 0.64 ); +// FBM - PROCESSING FOR OCTAVES AND ACCUMULATING DERIVATIVES +vec4 fbm( in vec3 x) +{ + float f = 2.0; // could be 2.0 + float s = 0.5; // could be 0.5 + float a = 0.0; + float b = 0.5; + vec3 d = vec3(0.0); + mat3 m = mat3( 1.00, 0.00, 0.00, + 0.00, 1.00, 0.00, + 0.00, 0.00, 1.00); + //int oct = octaves; + for( int i=0; i < 10; i++ ) // octaves = 8.. + { + vec4 n = noised(x); + // ADDING RIDGES + if(NoiseType==1 && !Preset1) // ABS NOISE + n = abs(n); + else if(NoiseType==2 && !Preset1) // RIDGED NOISE + n = 1.0-abs(n); + + a += b*n.x; // accumulate values + d += b*m*n.yzw; // accumulate derivatives + b *= s; + x = f*m3*x; + m = f*m3i*m; + } + return vec4( a, d ); +} + +vec2 voronoi( in vec3 x , in vec4 n ) +{ + vec3 p = floor( x ); + vec3 f = fract( x ); + float id = 0.0; + vec2 res = vec2( 8.0 ); + + for( int k=-1; k<=1; k++ ) + for( int j=-1; j<=1; j++ ) + for( int i=-1; i<=1; i++ ) + { + vec3 b = vec3( float(i), float(j), float(k) ); + vec3 r = vec3( b ) - f + rand3D( p + b ); + float d = dot( r, r ); + + if( d < res.x ) + { + id = dot( p+b , vec3(1.0,57.0,113.0 ) ); + res = vec2( d, res.x ); + } + else if( d < res.y ) + { + res.y = d; + } + } + + return vec3( sqrt( res ), abs(id) ); +} + +// SMOOTH VORONOI +float voronoi( in vec3 x ) +{ + vec3 p = floor( x ); + vec3 f = fract( x ); + + float res = 100.0; + for( int k=-1; k<=1; k++ ) + for( int j=-1; j<=1; j++ ) + for( int i=-1; i<=1; i++ ) + { + vec3 b = vec3( float(i), float(j), float(k) ); + vec3 r = vec3( b ) - f + rand3D( p + b ); + float d = dot( r, r ); + + //res = min(d,res); + res += 1.0/pow( d, 16.0 ); + } + + return pow( 1.0/res, 1.0/32.0 ); + //return sqrt( res ); +} + +void main() +{ + vec4 n = fbm(time*pos); + vec3 voro = voronoi((150.0*pos),n); //90 + + vec3 col; + vec3 colBase; + vec3 colSnow; + vec3 colForest; + + if(Preset1) + { + //float vn = voro; + float vn = voro[1]*voro[0];//smoothstep(0.0,0.9,voro[0]); + + // BASE + colBase = mix(vec3(0.2,0.2,0.2),vec3(0.4,0.35,0.3),vn); + colBase = mix(colBase,vec3(0.15,0.15,0.15),n[0]*length(pos)); + + // FOREST + colForest = mix(vec3(0.1,0.15,0.05),vec3(0.15,0.24,0.13),vn); + colForest = mix(colForest,colBase,n[0]*length(pos)); + colBase = mix(colForest,colBase,0.5+0.5*n[0]*length(pos)); + + // SNOW + colSnow = vec3(1.,0.98,0.98); // SNOW: 255,250,250 + col = mix(colBase,colSnow,(length(pos)-3.0*n[0]-2.0*n[1]-n[2])/10.0); + col = max(colBase,col); // CLAMPING LOWEST VALUES TO BASE COLOR + } + else if(!Preset2) + { + col = vec3(1.0+(sin((voro[1]-voro[0])*120.0)/2.0)); + } + else // ADJUSTABLE COLORS FOR DEBUGGING + { + float no = voro[1]*voro[0]; + //float no = voro;//[1]-voro[0];//(1.0+(sin((1.0-voro[0]))/2.0)); + + float r = mix(Red,Red1,no); + float g = mix(Green,Green1,no); + float b = mix(Blue,Blue1,no); + col = vec3(r,g,b); + + //col = vec3(n[0],n[0],n[0])*vec3(1.0,0.5,0.1)+vec3(0.2,0.2,0.2); + //col = voronoi(time*pos); + } + + // DIFFUSE LIGHTING + vec4 color = vec4(0., 0., 0., 0.); + vec4 diffuse = vec4(0., 0., 0., 1.); + diffuse = vec4(0.8, 0.8, 0.8, 1.);//u_diffuse; + diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.); + color.xyz += diffuse.xyz; + color = vec4(color.rgb * diffuse.a, diffuse.a); + gl_FragColor = color; + +// col = sqrt(col); // gamma correction +// gl_FragColor = vec4( col.rgb, 1.0 ); +} diff --git a/source/terrainProvider.js b/source/terrainProvider.js new file mode 100644 index 00000000..d9b9825e --- /dev/null +++ b/source/terrainProvider.js @@ -0,0 +1,741 @@ +'use strict'; + +const Cesium = require('cesium'); +const gltfPipeline = require('gltf-pipeline'); +const glbToB3dm = require('3d-tiles-tools/lib/glbToB3dm'); +const addPipelineExtras = gltfPipeline.addPipelineExtras; +const getBinaryGltf = gltfPipeline.getBinaryGltf; +const loadGltfUris = gltfPipeline.loadGltfUris; +const processJSON = gltfPipeline.Pipeline.processJSON; +const addCesiumRTC = gltfPipeline.addCesiumRTC; + +//TERRAIN GENERATION STUFF +const THREE = require('three'); + +//NOISE GENERATION +function getFractionalPart(a) +{ +// if(a < 0) +// { +// return -(Math.abs(a) - Math.floor(Math.abs(a))); +// } +// else if(a > 0) +// { +// return a - Math.floor(a); +// } +// else if(a == 0) + return a - Math.floor(a); + +} + +function getIntigerPart(a) +{ +// if(a < 0) +// { +// return -(Math.floor(Math.abs(a))); +// } +// else if(a > 0) +// { +// return Math.floor(a); +// } +// else if(a == 0) + return Math.floor(a); +} + +function dotProduct(x1, y1, z1, x2, y2, z2) +{ + var dotproduct = ((x1 * x2) + (y1 * y2) + (z1 * z2)); + return dotproduct; +} + +function Noise3D(x, y, z) +{ + var ft = Math.sin(dotProduct(x,y,z, 12.989, 78.233, 157)) * 43758.5453; + + return getFractionalPart(ft); +} + + +function SmoothNoise3D(X, Y, Z) +{ + var far = (Noise3D(X-1, Y+1, Z+1) + Noise3D(X+1, Y+1, Z+1) + Noise3D(X-1, Y+1, Z-1) + Noise3D(X+1, Y+1, Z-1) + Noise3D(X-1, Y-1, Z+1) + Noise3D(X+1, Y-1, Z+1) + Noise3D(X-1, Y-1, Z-1) + Noise3D(X+1, Y-1, Z-1)) / 64.0;//80.0; + + var medium = (Noise3D(X-1, Y+1, Z) + Noise3D(X+1, Y+1, Z) + Noise3D(X-1, Y-1, Z) + Noise3D(X+1, Y-1, Z) + Noise3D(X, Y+1, Z+1) + Noise3D(X, Y+1, Z-1) + Noise3D(X, Y-1, Z+1) + Noise3D(X, Y-1, Z-1) + Noise3D(X-1, Y, Z+1) + Noise3D(X+1, Y, Z+1) + Noise3D(X-1, Y, Z-1) + Noise3D(X+1, Y, Z-1)) / 32.0;//60.0; + + var closest = (Noise3D(X-1, Y, Z) + Noise3D(X+1, Y, Z) + Noise3D(X, Y-1, Z) + Noise3D(X, Y+1, Z) + Noise3D(X, Y, Z+1) + Noise3D(X, Y, Z-1)) / 16.0;//19.999; + + var self = Noise3D(X, Y, Z) / 8.0; + + + return self + closest + medium + far; +} + + +function Interpolate(a, b, x) +{ + var t = (1.0 - Math.cos(x * 3.14159)) * 0.5; + + return a * (1.0 - t) + b * t; +} + + + +function InterpolateNoise3D(x, y, z, p) +{ + var int_X = getIntigerPart(x); + var int_Y = getIntigerPart(y); + var int_Z = getIntigerPart(z); + + var float_X = getFractionalPart(x); + var float_Y = getFractionalPart(y); + var float_Z = getFractionalPart(z); + + //8 Points on the lattice sorrunding the given point + var p1 = SmoothNoise3D(int_X, int_Y, int_Z); + var p2 = SmoothNoise3D(int_X + 1, int_Y, int_Z); + var p3 = SmoothNoise3D(int_X, int_Y + 1, int_Z); + var p4 = SmoothNoise3D(int_X + 1, int_Y + 1, int_Z); + var p5 = SmoothNoise3D(int_X, int_Y, int_Z + 1); + var p6 = SmoothNoise3D(int_X + 1, int_Y, int_Z + 1); + var p7 = SmoothNoise3D(int_X, int_Y + 1, int_Z + 1); + var p8 = SmoothNoise3D(int_X + 1, int_Y + 1, int_Z + 1); + + var i1 = Interpolate(p1, p2, float_X); + var i2 = Interpolate(p3, p4, float_X); + var i3 = Interpolate(p5, p6, float_X); + var i4 = Interpolate(p7, p8, float_X); + + var n1 = Interpolate(i1, i2, float_Y); + var n2 = Interpolate(i3, i4, float_Y); + + var t1 = Interpolate(n1, n2, float_Z); + + return t1; +} + + +function Generate_Noise3D(posx, posy, posz, persistance, octaves) +{ + var total = 0.0; + var p = persistance; + var n = octaves; + + //int i = 0; + for(var i=0; i < octaves; i++) + { + var frequency = Math.pow(1/p, i);//Math.pow(2, i);/// 120000000;//12000000.0; + var amplitude = Math.pow(p, i); + + total = total + InterpolateNoise3D((posx)* frequency / 600000, (posy) * frequency / 600000, (posz) * frequency / 600000, amplitude) * amplitude; + + } + + return total; +} + +//NOISE GENERATION OVER + +//GETTING THE TREE DEPTH +function getDepth(index) { + var depth = 0; + while (index > 0) { + ++depth; + index = Math.ceil(index / 4) - 1; + } + return depth; //depth / 100 +} + +//SETTING UP THE POS AND NORMAL VECTORS FROM RADIANS TO CARTESIAN COORDINATES +function TerrainProvider(treeProvider) { + this.treeProvider = treeProvider; +} + + +var scratchCartographic = new Cesium.Cartographic(); +var scratchCartesian = new Cesium.Cartesian3(); + +function setPosition(originlon, originlat, lon, lat, height, result) { + Cesium.Cartographic.fromRadians(lon, lat, height, scratchCartographic); + Cesium.Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian); + result[0] = scratchCartesian.x; + result[1] = scratchCartesian.y; + result[2] = scratchCartesian.z; + + + // position is relative to southwest corner + // Cesium.Cartographic.fromRadians(originlon, originlat, 0, scratchCartographic); + // Cesium.Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian); + // result[0] -= scratchCartesian.x; + // result[1] -= scratchCartesian.y; + // result[2] -= scratchCartesian.z; + + +} + +function setNormal(lon, lat, height, result) { + Cesium.Cartographic.fromRadians(lon, lat, height, scratchCartographic); + Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(scratchCartographic, scratchCartesian); + result[0] = scratchCartesian.x; + result[1] = scratchCartesian.y; + result[2] = scratchCartesian.z; +} + +//set normal from cartesian +var normal = []; +function setcartesiannormal(posx, posy, posz) { + normal = []; + + //convert cartesian positions to cartographics on a WGS84 ellpisoid + var position = new Cesium.Cartesian3(posx, posy, posz); + var cartographicPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position); + + //convert cartographics rep. to normal rep. on the ellipsoid + var normalCartesian = new Cesium.Cartesian3(); + Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(cartographicPosition, normalCartesian); + + normal[0] = normalCartesian.x; + normal[1] = normalCartesian.y; + normal[2] = normalCartesian.z; + +} + +//setting up the subdivision row positions +var pos_arr = []; +function getRowSubdivPos(depth, pointl, pointr, indexl, indexr) +{ + if(depth > 2) + { + return; + } + + pos_arr[(indexl + indexr) / 2] = new THREE.Vector3((pointr.x + pointl.x) / 2, (pointr.y + pointl.y) / 2, (pointr.z + pointl.z) / 2); + + depth += 1; + getRowSubdivPos(depth, pointl, pos_arr[(indexl + indexr) / 2], indexl, (indexl + indexr) / 2); + getRowSubdivPos(depth, pos_arr[(indexl + indexr) / 2], pointr, (indexl + indexr) / 2, indexr); + +} + +TerrainProvider.prototype.generateTerrain = function (hemisphere, index) { + // west, south, east, north + var region = this.treeProvider.generateBoundingRegion(hemisphere, index); + + + var northPole = (region[3] === Math.PI / 2); //false + var southPole = (region[1] === -Math.PI / 2); //false + var pole = false;//northPole || southPole; + +// var vertexCount = pole ? 3 : 9;//81;//9;//4; +// var indexCount = 3 * (vertexCount - 2); + +// var indices +// if(pole) +// +// else +// indices = new Uint16Array(24);//384); + var vertexCount, indexCount; + + if (pole) { + vertexCount = 3; + indexCount = 3; + } else { + vertexCount = 81;//9 + indexCount = 384;//24; + } + + var indices = new Uint16Array(indexCount); + + var normals = new Float32Array(3 * vertexCount); + var positions = new Float32Array(3 * vertexCount); + + var componentBytes = 3 * Float32Array.BYTES_PER_ELEMENT; + var corner; + + var noisearr = new Float32Array(3 * vertexCount); + + //for storing the positions and normals one for each indice values + var new_positions = new Float32Array(3 * indexCount); + var new_normals = new Float32Array(3 * indexCount); + var new_indices = new Uint16Array(indexCount); + var new_noisearr = new Float32Array(3 * indexCount); + + if (!pole) + { + // west, south, east, north + var SUBS = 3; + + var stepLong = (region[2] - region[0]) * Math.pow(0.5, SUBS); //left to right + var stepLat = (region[3] - region[1]) * Math.pow(0.5, SUBS); //bottom to top + + var CartographicPos = new Cesium.Cartographic(); + var CartesianPos = new Cesium.Cartesian3(); + + var p = 0; + for (var i = 0; i <= Math.pow(2,SUBS); ++i) + { + for (var j = 0; j <= Math.pow(2,SUBS); ++j) + { + var lat = region[1] + i * stepLat; + var long = region[0] + j * stepLong; + + //set the position + Cesium.Cartographic.fromRadians(long, lat, 0, CartographicPos); + Cesium.Ellipsoid.WGS84.cartographicToCartesian(CartographicPos, CartesianPos); + + positions[3*p+0] = CartesianPos.x; + positions[3*p+1] = CartesianPos.y; + positions[3*p+2] = CartesianPos.z; + + //set the normal + Cesium.Cartographic.fromRadians(long, lat, 0, CartographicPos); + Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(CartographicPos, CartesianPos); + + normals[3*p+0] = CartesianPos.x; + normals[3*p+1] = CartesianPos.y; + normals[3*p+2] = CartesianPos.z; + + //OFFSET THE POSITIONS OF THE VERTICES ALONG THE NORMAL USING NOISE + var tree_depth = getDepth(index); + var noise_val = Generate_Noise3D(positions[3*p+0], positions[3*p+1], positions[3*p+2], 0.5, tree_depth); + + noise_val = 0.5 + 0.5 * noise_val; + positions[3*p+0] = positions[3*p+0] + normals[3*p+0] * noise_val * 2000000; + positions[3*p+1] = positions[3*p+1] + normals[3*p+1] * noise_val * 2000000; + positions[3*p+2] = positions[3*p+2] + normals[3*p+2] * noise_val * 2000000; + + noisearr[3*p+0] = noise_val; + noisearr[3*p+1] = noise_val; + noisearr[3*p+2] = noise_val; + + p+=1; + } + } + } + else + { + // 0 1 2 3 + // west, south, east, north + //set position of the triangle based in the south pole or the north pole + var CartographicPos = new Cesium.Cartographic(); + var CartesianPos = new Cesium.Cartesian3(); + var p = 0; + + //south west + //set position + Cesium.Cartographic.fromRadians(region[0], region[1], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.cartographicToCartesian(CartographicPos, CartesianPos); + + positions[3*p+0] = CartesianPos.x; + positions[3*p+1] = CartesianPos.y; + positions[3*p+2] = CartesianPos.z; + + + //set the normal + Cesium.Cartographic.fromRadians(region[0], region[1], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(CartographicPos, CartesianPos); + + normals[3*p+0] = CartesianPos.x; + normals[3*p+1] = CartesianPos.y; + normals[3*p+2] = CartesianPos.z; + p++; + + if(!southPole) + { + //south east + //set position + Cesium.Cartographic.fromRadians(region[2], region[1], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.cartographicToCartesian(CartographicPos, CartesianPos); + + positions[3*p+0] = CartesianPos.x; + positions[3*p+1] = CartesianPos.y; + positions[3*p+2] = CartesianPos.z; + + + //set the normal + Cesium.Cartographic.fromRadians(region[2], region[1], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(CartographicPos, CartesianPos); + + normals[3 * p + 0] = CartesianPos.x; + normals[3 * p + 1] = CartesianPos.y; + normals[3 * p + 2] = CartesianPos.z; + p++; + } + + //north east + //set position + Cesium.Cartographic.fromRadians(region[2], region[3], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.cartographicToCartesian(CartographicPos, CartesianPos); + + positions[3*p+0] = CartesianPos.x; + positions[3*p+1] = CartesianPos.y; + positions[3*p+2] = CartesianPos.z; + + + //set the normal + Cesium.Cartographic.fromRadians(region[2], region[3], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(CartographicPos, CartesianPos); + + normals[3 * p + 0] = CartesianPos.x; + normals[3 * p + 1] = CartesianPos.y; + normals[3 * p + 2] = CartesianPos.z; + p++; + + + if(!northPole) + { + //north west + //set position + Cesium.Cartographic.fromRadians(region[0], region[3], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.cartographicToCartesian(CartographicPos, CartesianPos); + + positions[3*p+0] = CartesianPos.x; + positions[3*p+1] = CartesianPos.y; + positions[3*p+2] = CartesianPos.z; + + //set the normal + Cesium.Cartographic.fromRadians(region[0], region[3], 0, CartographicPos); + Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(CartographicPos, CartesianPos); + + normals[3 * p + 0] = CartesianPos.x; + normals[3 * p + 1] = CartesianPos.y; + normals[3 * p + 2] = CartesianPos.z; + p++; + } + + } + + //SETTING THE MIN AND MAX BOUNDS + var minPosition = [positions[0], positions[1], positions[2]]; + var maxPosition = [positions[0], positions[1], positions[2]]; + + let padding = 0; + for (let i = 0; i < vertexCount; ++i) { + minPosition[0] = Math.min(minPosition[0], positions[3 * i + 0] - padding); + minPosition[1] = Math.min(minPosition[1], positions[3 * i + 1] - padding); + minPosition[2] = Math.min(minPosition[2], positions[3 * i + 2] - padding); + maxPosition[0] = Math.max(maxPosition[0], positions[3 * i + 0] + padding); + maxPosition[1] = Math.max(maxPosition[1], positions[3 * i + 1] + padding); + maxPosition[2] = Math.max(maxPosition[2], positions[3 * i + 2] + padding); + } + + + if(pole) + indices.set([0,1,2]); + else + { + var ind = []; + //setup indices for the subdivided tile mesh + var j = 0; + for (var i = 0; i < 72; i++) { + if ((i + 1) % 9 == 0) + continue; + + ind[6 * j + 0] = i; + ind[6 * j + 1] = i + 1; + ind[6 * j + 2] = i + 10; + ind[6 * j + 3] = i; + ind[6 * j + 4] = i + 10; + ind[6 * j + 5] = i + 9; + + j++; + } + + for(var i = 0 ; i < ind.length; i++) + { + indices[i] = ind[i]; + } + + //creating per face vertex and storing multiple same vertices per face + //creating per face normals storing them multiple times per vertex per face + //creating per face noise storing noise values per vertex per face + //creating a new linear index array + + var A = new THREE.Vector3(0.0); + var B = new THREE.Vector3(0.0); + var C = new THREE.Vector3(0.0); + for(i = 0 ; i < indices.length; i+=3) + { + A.x = positions[3 * indices[i+2] + 0] - positions[3 * indices[i+1] + 0]; + A.y = positions[3 * indices[i+2] + 1] - positions[3 * indices[i+1] + 1]; + A.z = positions[3 * indices[i+2] + 2] - positions[3 * indices[i+1] + 2]; + + B.x = positions[3 * indices[i+0] + 0] - positions[3 * indices[i+1] + 0]; + B.y = positions[3 * indices[i+0] + 1] - positions[3 * indices[i+1] + 1]; + B.z = positions[3 * indices[i+0] + 2] - positions[3 * indices[i+1] + 2]; + + C.crossVectors(A,B); + C.normalize(); + + //store the vertices + new_positions[3*(i+0)+0] = positions[3*indices[i+0]+0]; + new_positions[3*(i+0)+1] = positions[3*indices[i+0]+1]; + new_positions[3*(i+0)+2] = positions[3*indices[i+0]+2]; + + new_positions[3*(i+1)+0] = positions[3*indices[i+1]+0]; + new_positions[3*(i+1)+1] = positions[3*indices[i+1]+1]; + new_positions[3*(i+1)+2] = positions[3*indices[i+1]+2]; + + new_positions[3*(i+2)+0] = positions[3*indices[i+2]+0]; + new_positions[3*(i+2)+1] = positions[3*indices[i+2]+1]; + new_positions[3*(i+2)+2] = positions[3*indices[i+2]+2]; + //done + + //storing the normals + new_normals[3*(i+0)+0] = C.x; + new_normals[3*(i+0)+1] = C.y; + new_normals[3*(i+0)+2] = C.z; + + new_normals[3*(i+1)+0] = C.x; + new_normals[3*(i+1)+1] = C.y; + new_normals[3*(i+1)+2] = C.z; + + new_normals[3*(i+2)+0] = C.x; + new_normals[3*(i+2)+1] = C.y; + new_normals[3*(i+2)+2] = C.z; + //done + + //storing the noise + new_noisearr[3*(i+0)+0] = noisearr[3*indices[i+0]+0]; + new_noisearr[3*(i+0)+1] = noisearr[3*indices[i+0]+1]; + new_noisearr[3*(i+0)+2] = noisearr[3*indices[i+0]+2]; + + new_noisearr[3*(i+0)+0] = noisearr[3*indices[i+1]+0]; + new_noisearr[3*(i+1)+1] = noisearr[3*indices[i+1]+1]; + new_noisearr[3*(i+2)+2] = noisearr[3*indices[i+1]+2]; + + new_noisearr[3*(i+0)+0] = noisearr[3*indices[i+2]+0]; + new_noisearr[3*(i+1)+1] = noisearr[3*indices[i+2]+1]; + new_noisearr[3*(i+2)+2] = noisearr[3*indices[i+2]+2]; + //done + + } + + for(var i = 0; i < indices.length; i++) + { + new_indices[i] = i; + } + + } + + //END PROCEDURAL TERRAIN STUFF + + var buffer = Buffer.concat([ + Buffer.from(new_indices.buffer), + Buffer.from(new_normals.buffer), + Buffer.from(new_positions.buffer), + Buffer.from(new_noisearr.buffer)//added + ], new_indices.byteLength + new_normals.byteLength + new_positions.byteLength + new_noisearr.byteLength); + + // https://github.com/KhronosGroup/glTF/tree/master/specification/1.0/schema + var gltf = { + accessors: { + accessor_ind: { + bufferView: "bufferView_ind", + byteOffset: 0, + byteStride: 0, + componentType: 5123, // UNSIGNED_SHORT + count: indexCount, + type: "SCALAR" + }, + accessor_nor: { + bufferView: "bufferViews_attr", + byteOffset: 0, + byteStride: 0, + componentType: 5126, // FLOAT + count: indexCount, + max: [1, 1, 1], + min: [-1, -1, -1], + type: "VEC3" + }, + accessor_pos: { + bufferView: "bufferViews_attr", + byteOffset: componentBytes * indexCount, + byteStride: 0, + componentType: 5126, // FLOAT + count: indexCount, + max: maxPosition, + min: minPosition, + type: "VEC3" + }, + accessor_noise: {//added + bufferView: "bufferViews_attr", + byteOffset: componentBytes * indexCount * 2, + byteStride: 0, + componentType: 5126, // FLOAT + count: indexCount, + max: [1, 1, 1], + min: [-1, -1, -1], + type: "VEC3" + } + + }, + asset: { + premultipliedAlpha: true, + profile: { + api: "WebGL", + version: "1.0.2" + }, + version: "1.0" + }, + bufferViews: { + bufferView_ind: { + buffer: "Terrain", + byteLength: indices.byteLength, + byteOffset: 0, + target: 34963 // ELEMENT_ARRAY_BUFFER + }, + bufferViews_attr: { + buffer: "Terrain", + byteLength: new_normals.byteLength + new_positions.byteLength + new_noisearr.byteLength, //added + byteOffset: new_indices.byteLength, + target: 34962 // ARRAY_BUFFER + } + }, + buffers: { + Terrain: { + byteLength: buffer.byteLength, + type: "arraybuffer", + uri: `data:application/octet-stream;base64,${buffer.toString('base64')}` + } + }, + materials: { + material_terrain: { + name: "MaterialTerrain", + technique: "technique_terrain", + values: { + diffuse: [0.8, 0.8, 0.8, 1] + } + } + }, + meshes: { + mesh_terrain: { + name: "Terrain", + primitives: [ + { + attributes: { + NORMAL: "accessor_nor", + POSITION: "accessor_pos", + NOISE: "accessor_noise" //added + }, + indices: "accessor_ind", + material: "material_terrain", + mode: 4 // triangles + } + ] + } + }, + nodes: { + node_terrain: { + children: [], + matrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], + meshes: ["mesh_terrain"], + name: "Terrain" + } + }, + programs: { + program_terrain: { + attributes: [ + "a_normal", + "a_position", + "a_noise"//added + ], + fragmentShader: 'terrainFS', + vertexShader: 'terrainVS' + } + }, + scene: "defaultScene", + scenes: { + defaultScene: { + nodes: [ + "node_terrain" + ] + } + }, + shaders: { + terrainFS: { + type: 35632, + uri: "shaders/terrainFS.glsl" + }, + terrainVS: { + type: 35633, + uri: "shaders/terrainVS.glsl" + } + }, + techniques: { + technique_terrain: { + attributes: { + a_normal: "normal", + a_position: "position", + a_noise: "noise" //added + }, + parameters: { + "diffuse": { + "type": 35666 + }, + "modelViewMatrix": { + "semantic": "MODELVIEW", + "type": 35676 + }, + "normal": { + "semantic": "NORMAL", + "type": 35665 + }, + "normalMatrix": { + "semantic": "MODELVIEWINVERSETRANSPOSE", + "type": 35675 + }, + "position": { + "semantic": "POSITION", + "type": 35665 + }, + "projectionMatrix": { + "semantic": "PROJECTION", + "type": 35676 + }, + "noise": {//added + "semantic": "NOISE", + "type": 35665 + }, + }, + program: "program_terrain", + states: { + enable: [ + 2929, // DEPTH_TEST + 2884 // CULL_FACE + ] + }, + uniforms: { + u_diffuse: "diffuse", + u_modelViewMatrix: "modelViewMatrix", + u_normalMatrix: "normalMatrix", + u_projectionMatrix: "projectionMatrix", + } + } + } + }; + + // addCesiumRTC(gltf, { + // longitude: region[0], + // latitude: region[1], + // height: 0 + // }); + + const pipelineOptions = { + basePath: __dirname, + optimizeForCesium: true + }; + + return processJSON(gltf, pipelineOptions) + .then(function (optimizedGltf) { + var gltfWithExtras = addPipelineExtras(optimizedGltf); + return loadGltfUris(gltfWithExtras); + }) + .then(function (pipelineGltf) { + var binaryGltf = getBinaryGltf(pipelineGltf, true, false); + var glbBuffer = binaryGltf.glb; + var b3dmBuffer = glbToB3dm(glbBuffer); + return b3dmBuffer; + }); +} + +module.exports = TerrainProvider; diff --git a/source/treeProvider.js b/source/treeProvider.js new file mode 100644 index 00000000..ef3f907e --- /dev/null +++ b/source/treeProvider.js @@ -0,0 +1,314 @@ + +'use strict'; +const Cesium = require('cesium'); + +function TreeProvider(options) { + this.generationDepth = options.generationDepth || 4; + this.rootError = options.rootError || 100000; //100; options.rootError || 100; + this.errorFactor = options.errorFactor || 0.25;//0.5 + this.worldRadius = options.worldRadius || 100000; // 100; options.worldRadius || 100; + this.maxHeight = options.maxHeight || 1000; //100; options.maxHeight || 10; + this.rootRegions = [ + // west, south, east, north, bottom, top + [ -Math.PI, -Math.PI / 2, 0, Math.PI / 2, 0, this.maxHeight ], + [ 0, -Math.PI / 2, Math.PI, Math.PI / 2, 0, this.maxHeight ] + ]; +} + +function getDepth(index) { + var depth = 0; + while (index > 0) { + ++depth; + index = Math.ceil(index / 4) - 1; + } + return depth; //depth / 100 +} + +TreeProvider.prototype.getRoot = function() { + return { + boundingVolume: { + sphere: [ 0, 0, 0, this.worldRadius ], + }, + geometricError: 100000000, + // geometricError: this.rootError, + refine: 'replace', + children: [ + this.generateNode(0, 1, 1), + this.generateNode(0, 2, 1), + this.generateNode(0, 3, 1), + this.generateNode(0, 4, 1), + + this.generateNode(1, 1, 1), + this.generateNode(1, 2, 1), + this.generateNode(1, 3, 1), + this.generateNode(1, 4, 1), + ] + }; +} + +TreeProvider.prototype.generateNode = function(hemisphere, index, generationDepth) { + var depth = getDepth(index); + var error = this.rootError * Math.pow(this.errorFactor, depth); + + var node = { + boundingVolume: { + region: this.generateBoundingRegion(hemisphere, index), + }, + geometricError: error, + refine: 'replace', + content: { + url: `${hemisphere}_${index}.b3dm` + }, + children: undefined + } + + if (generationDepth === this.generationDepth) { + node.content = { + url: `${hemisphere}_${index}.json` + } + } else { + node.children = [ + this.generateNode(hemisphere, 4 * index + 1, generationDepth + 1), + this.generateNode(hemisphere, 4 * index + 2, generationDepth + 1), + this.generateNode(hemisphere, 4 * index + 3, generationDepth + 1), + this.generateNode(hemisphere, 4 * index + 4, generationDepth + 1), + ] + } + + return node; +} + +// west, south, east, north + +var modifiers = [ + // south west + function(region) { + region[0] = region[0]; + region[1] = region[1]; + region[2] = (region[0] + region[2]) / 2; + region[3] = (region[1] + region[3]) / 2; + }, + // south east + function(region) { + region[0] = (region[0] + region[2]) / 2; + region[1] = region[1]; + region[2] = region[2]; + region[3] = (region[1] + region[3]) / 2; + }, + // north east + function(region) { + region[0] = (region[0] + region[2]) / 2; + region[1] = (region[1] + region[3]) / 2; + region[2] = region[2]; + region[3] = region[3]; + }, + // north west + function(region) { + region[0] = region[0]; + region[1] = (region[1] + region[3]) / 2; + region[2] = (region[0] + region[2]) / 2; + region[3] = region[3]; + }, +]; + +var indices = []; + + +//ofsetting the bounds to find the maximum and minimum for the bounding box using the 3D multioctave noise +function getFractionalPart(a) +{ + if(a < 0) + { + return -(Math.abs(a) - Math.floor(Math.abs(a))); + } + else if(a > 0) + { + return a - Math.floor(a); + } + else if(a == 0) + return 0; + +} + +function getIntigerPart(a) +{ + if(a < 0) + { + return -(Math.floor(Math.abs(a))); + } + else if(a > 0) + { + return Math.floor(a); + } + else if(a == 0) + return 0; +} + +function getPosition(lon, lat, height, pos) { + Cesium.Cartographic.fromRadians(lon, lat, height, scratchCartographic); + Cesium.Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian); + + pos[0] = scratchCartesian.x; + pos[1] = scratchCartesian.y; + pos[2] = scratchCartesian.z; + +} + +function getMax(a, b, c, d) +{ + return Math.max(Math.max(Math.max(a, b), c), d); +} + +function getMin(a, b, c, d) +{ + return Math.min(Math.min(Math.min(a, b), c), d); +} + +function dotProduct(x1, y1, z1, x2, y2, z2) +{ + var dotproduct = ((x1 * x2) + (y1 * y2) + (z1 * z2)); + return dotproduct; +} + +function Noise3D(x, y, z) +{ + var ft = Math.sin(dotProduct(x,y,z, 12.989, 78.233, 157)) * 43758.5453; + + return getFractionalPart(ft); +} + + +function SmoothNoise3D(X, Y, Z) +{ + var far = (Noise3D(X-1, Y+1, Z+1) + Noise3D(X+1, Y+1, Z+1) + Noise3D(X-1, Y+1, Z-1) + Noise3D(X+1, Y+1, Z-1) + Noise3D(X-1, Y-1, Z+1) + Noise3D(X+1, Y-1, Z+1) + Noise3D(X-1, Y-1, Z-1) + Noise3D(X+1, Y-1, Z-1)) / 64.0;//80.0; + + var medium = (Noise3D(X-1, Y+1, Z) + Noise3D(X+1, Y+1, Z) + Noise3D(X-1, Y-1, Z) + Noise3D(X+1, Y-1, Z) + Noise3D(X, Y+1, Z+1) + Noise3D(X, Y+1, Z-1) + Noise3D(X, Y-1, Z+1) + Noise3D(X, Y-1, Z-1) + Noise3D(X-1, Y, Z+1) + Noise3D(X+1, Y, Z+1) + Noise3D(X-1, Y, Z-1) + Noise3D(X+1, Y, Z-1)) / 32.0;//60.0; + + var closest = (Noise3D(X-1, Y, Z) + Noise3D(X+1, Y, Z) + Noise3D(X, Y-1, Z) + Noise3D(X, Y+1, Z) + Noise3D(X, Y, Z+1) + Noise3D(X, Y, Z-1)) / 16.0;//19.999; + + var self = Noise3D(X, Y, Z) / 8.0; + + + return self + closest + medium + far; +} + + +function Interpolate(a, b, x) +{ + var t = (1.0 - Math.cos(x * 3.14159)) * 0.5; + + return a * (1.0 - t) + b * t; +} + +function InterpolateNoise3D(x, y, z, p) +{ + var int_X = getIntigerPart(x); + var int_Y = getIntigerPart(y); + var int_Z = getIntigerPart(z); + + var float_X = getFractionalPart(x); + var float_Y = getFractionalPart(y); + var float_Z = getFractionalPart(z); + + //8 Points on the lattice sorrunding the given point + var p1 = SmoothNoise3D(int_X, int_Y, int_Z); + var p2 = SmoothNoise3D(int_X + 1, int_Y, int_Z); + var p3 = SmoothNoise3D(int_X, int_Y + 1, int_Z); + var p4 = SmoothNoise3D(int_X + 1, int_Y + 1, int_Z); + var p5 = SmoothNoise3D(int_X, int_Y, int_Z + 1); + var p6 = SmoothNoise3D(int_X + 1, int_Y, int_Z + 1); + var p7 = SmoothNoise3D(int_X, int_Y + 1, int_Z + 1); + var p8 = SmoothNoise3D(int_X + 1, int_Y + 1, int_Z + 1); + + var i1 = Interpolate(p1, p2, float_X); + var i2 = Interpolate(p3, p4, float_X); + var i3 = Interpolate(p5, p6, float_X); + var i4 = Interpolate(p7, p8, float_X); + + var n1 = Interpolate(i1, i2, float_Y); + var n2 = Interpolate(i3, i4, float_Y); + + var t1 = Interpolate(n1, n2, float_Z); + + return t1; +} + + +function Generate_Noise3D(posx, posy, posz, persistance, octaves) +{ + var total = 0.0; + var p = persistance; + var n = octaves; + + //int i = 0; + for(var i=0; i < octaves; i++) + { + var frequency = Math.pow(1/p, i);//Math.pow(2, i) / 12000000.0; + var amplitude = Math.pow(p, i); + + total = total + InterpolateNoise3D((posx)* frequency / 600000, (posy) * frequency / 600000, (posz) * frequency / 600000, amplitude) * amplitude; + } + + return total; +} + +//convert the radians to cartesian coordinates for getting the width of the tiles +var scratchCartographic = new Cesium.Cartographic(); +var scratchCartesian = new Cesium.Cartesian3(); + +var sw_pos = []; +var se_pos = []; +var nw_pos = []; +var ne_pos = []; + + + +TreeProvider.prototype.generateBoundingRegion = function(hemisphere, index) { + let region = this.rootRegions[hemisphere].slice(); + var depth = getDepth(index); + indices.length = 0; + while (index > 0) { + let next = Math.floor((index - 1) / 4); + let childIndex = index - next * 4; + indices.push(childIndex - 1); + index = next; + } + + for(let i = indices.length - 1; i >= 0; --i) { + modifiers[indices[i]](region); + } + + // west, south, east, north, bottom, top <- region + //getting the south west position in cartesian + getPosition(region[0],region[1],0, sw_pos); + + //getting the south east position in cartesian + getPosition(region[2],region[1],0, se_pos); + + //getting the north west position in cartesian + getPosition(region[0],region[3],0, nw_pos); + + //getting the north east position in cartesian + getPosition(region[2],region[3],0, ne_pos); + + var persistance = 0.5; + + //generate the noise value for the 4 corners + var noise_sw = Generate_Noise3D(sw_pos[0], sw_pos[1], sw_pos[2], persistance, depth); + var noise_se = Generate_Noise3D(se_pos[0], se_pos[1], se_pos[2], persistance, depth); + var noise_nw = Generate_Noise3D(nw_pos[0], nw_pos[1], nw_pos[2], persistance, depth); + var noise_ne = Generate_Noise3D(ne_pos[0], ne_pos[1], ne_pos[2], persistance, depth); + + var max = getMax(noise_sw, noise_se, noise_nw, noise_ne); + var min = getMin(noise_sw, noise_se, noise_nw, noise_ne); + + //estimating the error of the bounding box to (k + 3) octaves. Currently k = 4 + var error = Math.pow(0.5, depth + 1) + Math.pow(0.5, depth + 2) + Math.pow(0.5, depth + 3); + + region[region.length - 2] = (min - error) * 2000000; + region[region.length - 1] = (max + error) * 2000000; + + return region; +} + +module.exports = TreeProvider;