Florasynth procedural tree generator

Hey there,

The opacity problem you are having is most likely because the GLTF format does not support a separate alpha channel (opacity masks), which is how they are exported in Florasynth, and likely blender too (depending on your export settings). One solution would be to combine the color and opacity masks such that the color texture also has opacity. This would make it work right out of the box when you into import into threejs. Otherwise, export from Blender without the textures embedded, and then apply the textures separately after importing into threejs.

Also, yes feel free to use the minified code however you like so long as its for personal use.

Let me know if that helps.

Oh also, having a skeleton on your mesh would allow for dynamic wind sway for sure.

The skeleton is just a set of bones that can influence certain vertices, so you can apply different types of animations later on for dynamic wind sway.

yes but how can we add the skeleton automatically to the tree? and is there a wawy to automatically combine the color and opacity masks?

also what qualifies as personal use?

To add a skeleton automatically, you will need to write code that assigns each vertex to a bone.
Threejs bone system

Florasynth has no way to automatically merge the color and opacity masks. A workaround is to download both textures, and use an image editing software like Gimp to cutout the opacity map from the diffuse, and then use that texture as the new color map.

Alternatively, a comment in this thread mentions storing the alpha mask into an unused channel. Check it out

So long as you don’t distribute the code is fine.

Hi,

Amazing work … casually creating SpeedTree in ThreeJS :laughing:

one thing I’ve noticed while exporting the mesh is some times the leaves and branch are flipped


here is an isolated example. sorry if this was mentioned before.

Good luck and wishing you all the best!

1 Like

Thanks for the feedback!

I will have to look into this, did this occur from a GLTF export or an OBJ export?

1 Like

B"H
I had the same issue

B"H
I had the same issue with glb exportere and trying to load the opacity maps. ideally one day if u can make it all open source so we can work on it :slight_smile: would be good

B"H
If u want i can buy the code from u to make it opensource. or at least find a way to make it add skeleton auotmaically and/or leaves correct direction. would pay to get the code tho

Yea I may make it open source at some point, but for now I’ll look into it

reach out to me at jacopofb03@gmail.com if you want to discuss this

Hello,

it happens in GLTF export, I’ve tested it with OBJ and GLTF for the same tree and in OBJ it exported just fine, in GLTF all leaves are flipped!

1 Like

same cant get leaves to show up noramlly unless i export textures and manually flip the image

B"H

New upadte has leaves working great.

NOW we need to just add bones automatically to make it able to sway in the wind.

Any ideas?

so far got

// Create an armature and add bones
const skeleton = new THREE.SkeletonHelper(model);
scene.add(skeleton);

        const boneRoot = new THREE.Bone();
        boneRoot.position.set(0, 0, 0);
        model.add(boneRoot);

        // Function to recursively create bones along branches
        function createBones(geometry, parentBone, depth = 0) {
            const position = geometry.attributes.position.array;
            const segmentLength = 10; // Adjust as necessary

            for (let i = 0; i < position.length; i += segmentLength * 3) {
                const bone = new THREE.Bone();
                bone.position.set(position[i], position[i + 1], position[i + 2]);
                parentBone.add(bone);

                if (depth < 3) { // Adjust the depth as necessary
                    createBones(geometry, bone, depth + 1);
                }
            }
        }

        // Traverse the model to find branches and create bones
        model.traverse((child) => {
            if (child.isMesh) {
                createBones(child.geometry, boneRoot);
            }
        });

        // Example of custom bone animation
        const bones = [];
        boneRoot.traverse((child) => {
            if (child.isBone) {
                bones.push(child);
            }
        });

        // Animate bones for swaying effect
        const swayFrequency = 0.5;
        const swayAmplitude = 0.05;

        function swayBones(time) {
            bones.forEach((bone, index) => {
                const sway = Math.sin(time * swayFrequency + index) * swayAmplitude;
                bone.rotation.z = sway;
            });
        }

but would be ncice to have uatomaitlcally

B"H

B"H

Ran into an issue with the leaves, they work and are trans[raent but the ones behind seem to be visible through ones in front , is this a GLTF issue or something else?

Screen Shot 2024-06-04 at 2.35.22 PM.png

Blessings and Success

That sounds like a depth sorting issue, enabling alphaTest and depthTest/Write on the leaf texture could/should do the trick. something like depthWrite:true, depthTest: true, alphaTest:.2

r.e. using a skeleton to animate the trees… that sounds really inefficient. I think you could probably only get ~10 trees if you animated them in that fashion. Additionally the swaying would have to be implemented per tree in js, which is also an inefficient use of the limited javascript cycles you have available.

A more efficient approach is to use a modified vertex shader to implement swaying. That way all the logic is handled by the GPU and you can use instancing to render LOTS of trees.

B"H
How can we do that

Here’s the setup I use in my forest renderer:


let fs='fragmentShader'
let vs='vertexShader'
let ck = THREE.ShaderChunk;
let timeUniform={
    get value(){return performance.now()/1000;},
    set value(v){}
}
function TreeShader(s){
    s.uniforms.uTime = timeUniform;
    s[vs]=`
    varying vec3 vPosWorld;
    uniform float uTime;
    `+s[vs];
    let pv = ck.project_vertex;
    pv = pv.replace(`mvPosition = modelViewMatrix * mvPosition;`,`
    vPosWorld = vec3(modelMatrix * mvPosition);
    mvPosition = modelViewMatrix * mvPosition;
    float offset = pow((vPosWorld.y-modelMatrix[3].y)*.1,2.);
    vPosWorld.x += .02*offset*sin(uTime*2.5);
    mvPosition = viewMatrix * vec4(vPosWorld,1.);
    `)
    s[vs]=s[vs].replace(`#include <project_vertex>`,pv)
}


Then in your code once you’ve loaded the tree…
you set the trees:

 material.onBeforeCompile = TreeShader;

So for instance if you’re loading the tree from a GLTF… inside your load callback you:

gltf.scene.traverse( e => e.material && (e.material.onBeforeCompile = TreeShader) )

B"H
I guess this would be for the trunk material in the case of florasynth?

Has to be on all the trees materials otherwise the leaves wont sway with the trunk, but you should only have to do it once for each tree model.
Once it’s applied you can use:
let newTree = tree.clone()
to make copies of the tree for placement or use instancing.
(I don’t know exactly how florasynths materials are set up, but… give this a shot see if it works. :slight_smile: