Obi Official Forum
Help Rendering rope and performance cost - Printable Version

+- Obi Official Forum (https://obi.virtualmethodstudio.com/forum)
+-- Forum: Obi Users Category (https://obi.virtualmethodstudio.com/forum/forum-1.html)
+--- Forum: Obi Rope (https://obi.virtualmethodstudio.com/forum/forum-4.html)
+--- Thread: Help Rendering rope and performance cost (/thread-3779.html)



Rendering rope and performance cost - Zombie1111 - 22-02-2023

I have been experimenting with using colliders and joints instead of using obi rope because it may fit my game better. However when I got the joints to behave properly I thought I could just modify obi ropes render components a little to get it to work with my joints, but it unfortunately was not that easy.

I have two questions!
1: I tried disabling the obiPathSmoother component and it decreased the performance cost of each rope by around 50%. Is really 50% of the performance cost of a rope just rendering it?

2: Is there anyway I could use obi rope to render a rope using joints? I have a array of positions I want the rope to go through. How does obi rope know where to render the rope?


RE: Rendering rope and performance cost - josemendez - 23-02-2023

(22-02-2023, 06:33 PM)Zombie1111 Wrote: I have two questions!
1: I tried disabling the obiPathSmoother component and it decreased the performance cost of each rope by around 50%. Is really 50% of the performance cost of a rope just rendering it?

Hi!

Yes, roughly. Rope rendering uses an inherently sequential algorithm, called "parallel frame transport". Basically it involves choosing an initial orthonormal frame, and "transporting" it along a curve in a way that it minimizes the change in rotation along the curve. Then, you take these orthonormal frames and use them to build a mesh.

ObiPathSmoother is in charge of using parallel frame transport to generate a list of frames. It can also drop frames (decimation) and/or add extra frames (smoothing). Then, the ObiExtrudedRopeRenderer takes this list of frames and builds the actual mesh. Both generating the list of frames and building the mesh are fairly costly operations. The cost can be reduced considerably by using decimation (which results in less frames to process) and/or using a simpler rope section (less geometry to deal with).

(22-02-2023, 06:33 PM)Zombie1111 Wrote: 2: Is there anyway I could use obi rope to render a rope using joints? I have a array of positions I want the rope to go through. How does obi rope know where to render the rope?

An array of positions is not enough to render a rope, you also need orientations. These can be either automatically calculated from positions trough parallel transport, or provided by the rigidbodies themselves. Either way, you can modify ObiPathSmoother to use your own positions as input instead of the particle's. The rest of the rendering pipeline would remain unchanged.

It's fairly simple to do. You only need to modify AllocateRawChunks() and PathFrameFromParticle() in ObiPathSmoother.cs.

- AllocateRawChunks() generates a list of initial empty frames, one per particle in the rope, taking into account discontinuities in the rope (cuts/torn parts). Modify it to generate one frame per entry in your positions array instead. In case you don't plan on having discontinuities, it's a trivial thing to do:

Code:
private void AllocateRawChunks(Vector3[] positions)
        {
            using (m_AllocateRawChunksPerfMarker.Auto())
            {
                rawChunks.Clear();

               AllocateChunk(positions.Length);
            }
        }

- PathFrameFromParticle() sets the position/orientation of a frame to match a particle. Modify it to read the position from your array instead. Again if you have a continuous array of positions, it's an easy change:

Code:
private void PathFrameFromParticle(Vector3[] positions, ref ObiPathFrame frame, int arrayIndex, bool interpolateOrientation = true)
        {
            frame.position = positions[arrayIndex];
            frame.thickness = 0.1f;
            // optionally update frame thickness, color, etc.
            // if you also have an array of quaternions/matrices that represent orientation, you can write frame.normal/tangent/bitangent too.
        }

You'd also have to slightly modify GenerateSmoothChunks() which is the entry point of the entire rope rendering system, to pass an an array of positions instead of an ObiRopeBase instance.

kind regards,


RE: Rendering rope and performance cost - Zombie1111 - 24-02-2023

I still cant get it to render the rope! I have modified the AllocateRawChunks and the PathFrameFromParticle function to use an array of rigidbodies like you said.

I think the issue may be that I must call one of the functions in the pathsmootherscript manually? Because non of them gets ever called (Except for the onEnable/onDisable when I enable/disable the script)

This is what the two functions looks like now

Code:
        private void AllocateRawChunks(Rigidbody[] positions)
        {
            using (m_AllocateRawChunksPerfMarker.Auto())
            {
                rawChunks.Clear();

                AllocateChunk(positions.Length);
            }
        }



        private void PathFrameFromParticle(ObiRopeBase actor, ref ObiPathFrame frame, int particleIndex, bool interpolateOrientation = true)
        {
            // Update current frame values from particles:
            //frame.position = w2l.MultiplyPoint3x4(actor.GetParticlePosition(particleIndex));
            frame.position = ropePositions[particleIndex].worldCenterOfMass;
            //frame.thickness = actor.GetParticleMaxRadius(particleIndex);
            frame.thickness = 0.1f;
            //frame.color = actor.GetParticleColor(particleIndex);
            frame.color = Color.red;
           
            // Use particle orientation if possible:
            if (actor.usesOrientedParticles)
            {
                //Quaternion current = actor.GetParticleOrientation(particleIndex);
                Quaternion current = ropePositions[particleIndex].rotation;
                //Quaternion previous = actor.GetParticleOrientation(Mathf.Max(0, particleIndex - 1));
                Quaternion previous = ropePositions[Mathf.Max(0, particleIndex - 1)].rotation;
                Quaternion average = w2lRotation * (interpolateOrientation ? Quaternion.SlerpUnclamped(current, previous, 0.5f) : current);
                frame.normal = average * Vector3.up;
                frame.binormal = average * Vector3.right;
                frame.tangent = average * Vector3.forward;
            }
        }
Maybe I also have to modify the for loops that call the PathFrameFromParticle function?


RE: Rendering rope and performance cost - josemendez - 27-02-2023

(24-02-2023, 08:21 PM)Zombie1111 Wrote: I think the issue may be that I must call one of the functions in the pathsmootherscript manually? Because non of them gets ever called (Except for the onEnable/onDisable when I enable/disable the script)

Yes, you need to call GenerateSmoothChunks() passing an an array of positions instead of an ObiRopeBase instance as indicated in my previous post. If you want to trigger a renderer update too, you should also call the OnCurveGenerated() event.

See how both are usually called in the Actor_OnInterpolate() callback, as a response to the actor -rope in this case- finishing interpolating physics state.


(24-02-2023, 08:21 PM)Zombie1111 Wrote: This is what the two functions looks like now

Both look fine at first glance.

Let me know if you need further help,

cheers!


RE: Rendering rope and performance cost - Zombie1111 - 27-02-2023

(27-02-2023, 09:29 AM)josemendez Wrote: Yes, you need to call GenerateSmoothChunks() passing an an array of positions instead of an ObiRopeBase instance as indicated in my previous post. If you want to trigger a renderer update too, you should also call the OnCurveGenerated() event.

See how both are usually called in the Actor_OnInterpolate() callback, as a response to the actor -rope in this case- finishing interpolating physics state.



Both look fine at first glance.

Let me know if you need further help,

cheers!

I still cant get it to work! Im now calling the GenerateSmoothChunks() and OnCurveGenerated() functions but still no rope showing up. My guess is that I must modify the OnCurveGenerated() function? Because it requires a actor (Im just passing the actor as null), in the OnCurveGenerated() function it checks if a mesh is null and it obiously is and just returns instantly before doing anything.

This is what my functions looks like now
(https://pastebin.com/0gTNmifd, message was too long so could not paste it here)

Im calling GenerateSmoothChunks() from another script in the Update() loop using transform.GetComponent<Obi.ObiPathSmoother>().GenerateSmoothChunks(allRopeRigids.ToArray(), 0);
Here are the components I have attatched to the gameobject
(Could not attatch or paste ) https://imgur.com/a/5EXTB0C



RE: Rendering rope and performance cost - josemendez - 28-02-2023

Attached you'll find a working example. You can add these components to any GameObject, no need for an ObiRope to be present.

The ObiPathSmoother component has an array of transforms as a public member variable, that you can populate from the inspector.


kind regards,