SimArboreal Release - Formerly "Tree Editor"


#1

So, I’ve managed to port all of the prototype functionality over to an officially released Open Source library and application called SimArboreal.

The project is in two separate pieces.

  1. The SimArboreal library. This just contains the base jar and an arboreal-assets jar. If you want to generate trees in your application then you just need this library.

If you just want to load saved j3os, all you need is the arboreal-assets.jar

Both of these can be found here: (as well as all of the source code)
https://code.google.com/p/simsilica-tools/source/browse/#svn%2Ftrunk%2FSimArboreal%2Frelease

  1. The SimArboreal-Editor. This is used to edit the tree parameters, save/load tree parameters files, and export to j3o. This is what I prototyped before but it’s been pretty well cleaned up and rearchitected to be more supportable.

Releases for that can be found here: (as well as all of the source code)
https://code.google.com/p/simsilica-tools/source/browse/#svn%2Ftrunk%2FSimArboreal-Editor%2Frelease
…or:
https://simsilica-tools.googlecode.com/svn/trunk/SimArboreal-Editor/release/

Or if you are lazy, the download links are:
https://simsilica-tools.googlecode.com/svn/trunk/SimArboreal-Editor/release/SimArboreal-Editor-Windows.zip
https://simsilica-tools.googlecode.com/svn/trunk/SimArboreal-Editor/release/SimArboreal-Editor-Linux.zip
https://simsilica-tools.googlecode.com/svn/trunk/SimArboreal-Editor/release/SimArboreal-Editor-MacOSX.zip

Using the Editor

It pretty much works the same as the old one but I will be providing better, more complete documentation, a little later.

The main points:
Spacebar - toggles between movement and edit mode (the app starts in camera mode)
WASD - moves the movement camera mode
Cursor keys/Mouse - changes camera direction in movement mode;
Shift - moves faster
Shift + Ctrl - moves super fast

The editor layout is a little different and I added a slider for a rough time of day (to control the lighting direction) and a slider for shadow intensity.

Other than that, it’s pretty much identical.

Fun to play with…

Internally, I split the tree generation into two parts. One uses the tree parameters to apply a simplified L-system to generate a “tree”… which is essentially just a rough abstraction of the tree parts. The second part takes that “tree” and generates a mesh. In the future, I will provide different second stages for different levels-of-detail.

It’s also possible to construct the “tree” directly in code and bypass the L-system. I don’t have an example of this yet… but it might be fun to make a 3D tree font.

For those looking at the code, the Tree and Segment classes (the “tree” abstraction mentioned above) still need some cleanup. Specifically, the uv-related parameters in the Segment are not used. (Texture mapping has to be done at mesh generation time or it goes wonky.)

Thanks for reading this far.

Edit: just changed the topic title to make more sense.


Best way for tree leaves
Does JME have shaped drop shadows?
(July 2017) Monthly WIP screenshot thread
Should I make a BioMonkey 2.0?
(March 2015) Monthly WIP Screenshot Thread
#2

For fun, here is the rule file for those big fat trees in the last screen shot. Just cut+paste+save it to a .simap.json file and you can load it into the editor.
[java]
{
“baseScale” : 1.0,
“branches” : [
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.972,
“inherit” : false,
“lengthScale” : 0.70000005,
“lengthSegments” : 2,
“radialSegments” : 12,
“radiusScale” : 0.62,
“segmentVariation” : 1.0,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 1.0,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.972,
“inherit” : false,
“lengthScale” : 0.70000005,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 0.75,
“segmentVariation” : 1.0,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
}
],
“formatVersion” : 1,
“generateLeaves” : false,
“leafScale” : 1.3,
“rootHeight” : 1.4,
“roots” : [
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.3,
“inherit” : false,
“lengthScale” : 0.7,
“lengthSegments” : 1,
“radialSegments” : 6,
“radiusScale” : 0.59999996,
“segmentVariation” : 0.0,
“sideJointCount” : 5,
“sideJointStartAngle” : 0.0,
“taper” : 1.0,
“tipRotation” : 0.0,
“twist” : 0.4802703
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : false,
“lengthScale” : 1.1,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 0.9,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.34103402,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : false,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : false,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
}
],
“seed” : 2,
“textureURepeat” : 4,
“textureVScale” : 0.45,
“trunkHeight” : 1.8000001,
“trunkRadius” : 1.3684057
}
[/java]


#3

Congratz to the release, and thanks for sharing! =)


#4

Some other trees I was playing with on the way to bed:


And the .simap.json for it:
[java]
{
“baseScale” : 1.0,
“branches” : [
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 1.2478302,
“inherit” : false,
“lengthScale” : 2.989911,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 0.8365399,
“segmentVariation” : 0.35942808,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 1.0,
“tipRotation” : 0.0,
“twist” : 0.03861005
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.47471404,
“hasEndJoint” : false,
“inclination” : 1.1121352,
“inherit” : false,
“lengthScale” : 0.55,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 1.0,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.51,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.23103553,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : false,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 3,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : false,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
}
],
“formatVersion” : 1,
“generateLeaves” : true,
“leafScale” : 1.0,
“rootHeight” : 0.3,
“roots” : [
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.5,
“inherit” : false,
“lengthScale” : 1.1,
“lengthSegments” : 1,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.0,
“sideJointCount” : 5,
“sideJointStartAngle” : 0.0,
“taper” : 1.0,
“tipRotation” : 0.0,
“twist” : 0.6861004
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : false,
“lengthScale” : 1.0,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.5,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : true,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : false,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
},
{
“enabled” : false,
“formatVersion” : 1,
“gravity” : 0.1,
“hasEndJoint” : false,
“inclination” : 0.872,
“inherit” : true,
“lengthScale” : 0.6,
“lengthSegments” : 4,
“radialSegments” : 6,
“radiusScale” : 1.0,
“segmentVariation” : 0.4,
“sideJointCount” : 4,
“sideJointStartAngle” : 0.0,
“taper” : 0.7,
“tipRotation” : 0.0,
“twist” : 0.0
}
],
“seed” : 0,
“textureURepeat” : 4,
“textureVScale” : 0.45,
“trunkHeight” : 0.5,
“trunkRadius” : 0.2
}
[/java]


#5

Really nice tool, a lot of customizations, love it.
A way to change the textures?


#6
@haze said: Really nice tool, a lot of customizations, love it. A way to change the textures?

Not yet but when you load the trees in your game you can of course give them whatever textures you want.


#7

I started the very initial groundwork for LOD support. The idea being that for a specific tree, one might configure different LOD parameters for different distances. The goal is to have three basic reduction strategies.

Strategy 1: simply reduce the levels of the tree that are drawn. The theory being that from a distance, the interior branches or the low level roots won’t really be seen anyway. Furthermore, at distance it is often acceptable to use a reduced number of radials in the branch segments.

Strategy 2: tricksy hobbitses… a flattened polygon render where branch segments are rendered with lit billboarded quads. Hard to describe quickly… if this works this will be the magic LOD as I should be able to reduce the right kind of tree down to about 320 triangles or so. Even less if I can cut the leaf canopy in half… could be as few as 180. We’ll see.

Strategy 3: generate an impostor atlas of a few sample trees to render on lit billboarded quads. This will obviously end up being two triangles per tree.

So far, I’ve been playing with strategy 1 and the results are pretty encouraging. I was really hoping for a 4:1 reduction but with the starter tree it’s an even better 7:1 and the quality is nice: Rendering 7 trees for the price of one is savings you can count on.

Note: top is fully quality, bottom is reduced quality.


Scroll panel in lemur
#8

Ooops… found some more polys that I was rendering by accident. This LOD strategy actually ends up 16.6:1 for this tree:

16 for the price of one.

There is a small imperfection in this one, though, since the leaves end up shifting ever so slightly. Some precision problem that creeps in between rendering a branch and laying out a branch. Could end up causing a noticeable jump between LOD levels and then I’ll fix it. The whole point of this level was to be a nearly seamless transition for most trees.


#9

SDK editor and plugin would be cool.


#10
@normen said: SDK editor and plugin would be cool.
Yeah it would be cool if it was plopped in near the terrain editor :D

#11

Would be really cool to combine this with @jayfella and @sploreg’s terrain editor changes so that we can create paging terrains and paint on trees in the editor :slight_smile:


#12

I got the LOD framework working on actual distance now so I was able to create some default parameters using only stage 1 of my reduction code. So I made a video.

The settings aren’t very aggressive as to minimize popping. There are effectively 3 levels of detail here and they cut in a 20 meters and 40 meters distance. If you want to try and spot the popping you will probably have to view it HD. Though it seems youtube processing blurs the faster bits which makes it even harder there. To me it’s quite obvious for the lone tree that the people are standing next to.

The last and fastest run is more like what my own game would need. For that one, I could get away with a much more aggressive LOD.

It might be interesting to note that there are about as many triangles in the fully zoomed out view as there are in the most zoomed in view. 190k zoomed out, 150k zoomed in… watching the stats is fun as it moves in and out they climb like crazy. :slight_smile:


#13

Um… wow. That’s pretty freakin’ seamless. Amazing work!


#14
@t0neg0d said: Um... wow. That's pretty freakin' seamless. Amazing work!

Thanks. Of course, it climbs up to like 1 or 2 million triangles or so at one point I think… so real LOD would have to be more aggressive. The hope is that in a real forest the popping would be less noticeable anyway.


#15

I finally got the next LOD strategy working: axis-aligned flat quads… with some lighting trickery. There is still a texture stretching issue that I need to fix but the results are encouraging so far, even up close:

At distance, these will be fine, I think.


#16

Heh… I’d use these close up. (You should see my wicked tree modeling skills) =)


#17

I made a video that kind of shows how the new LOD level works.

[video]http://youtu.be/YmfunYkDzIE[/video]


#18

Result as usual.

Pretty impressive things


#19

I made some progress on impostors for the final type of LOD. There is still much to tweak and stuff but they are coming along. I made a video.

In this video, I have LOD setup really aggressively. The normal “high” level of detail only extends 10 meters before cutting over to the flat-poly version in the previous video… it only lasts until 20 meters and then it flips over to impostors.

You can tell the impostors most easily because the lighting on the leaves isn’t quite right and the shadows are way wrong. The fix to both of these problems is kind of the same, though… give up an extra quad to impostor the tree canopy separately. That is not without its own issues, though.

The other biggest source of “popping” is the fact that the impostors are only rendered from 4 different views. I may take it up to 8 to see how it does. The next steps will require some thinking and experimentation. Some fading might go a long way to alleviating all of the popping issues anyway.

Anyway, here is the video: (Fraps really does a number on my FPS sometimes.)
[video]http://youtu.be/033HjdzjHxQ[/video]


#20

So, I tried a few impostor lighting experiments before ultimately just deciding to generate normal maps for them. In the long run so much less hassle.

Here are some of the outcome. I’ve set the variations to 0 so that all of the near and far trees are in the same orientation. Also, to help the effect I’m viewing the forest at an angle where the impostors happen to match exactly (after all, lighting is what I’m showing).

This first picture is with the sun in normal position. The best (only?) way to tell the impostors is that their ground shadows are thin instead of the nice ones in the foreground: (they start about four rows back)

This one has the sun at the horizon sort of behind our right shoulder… very dramatic lighting but the impostors still keep up:

Finally, another more normal lighting angle… this one past mid-day (versus the first pic which is before mid-day):

Now I just need to think of something clever for the shadows… or decide that trees really far away don’t really need them.