Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by avandenberg · Dec 18, 2019 at 06:43 AM · voxelvolumegeometry

Find intersecting volume of two cubes -or- submerged volume of object

Hey Unity users!

I am trying to find out how much of an object is below a certain surface. I basically have a (fake) bath and want to use the displaced volume by the controlled object as a measure for the disturbance of the fluid.

This bath is static and has a fixed height. The controlled object can have any orientation/position. What I've tried:

  • Simplify the controlled object to a box & find out how far the box is below the surface. I managed to get the positions of all the vertices and the positions where the edges cross the surface of the bath. However, I found out that calculating this volume for an arbitrary orientation is rather difficult. I basically need a formula that calculates the volume of an arbitrary (irregular) polyhedron, but haven't been able to find something that works here.

  • I could also draw a voxel grid on the controlled object, and found out how much of it is underneath the surface, and use that to estimate the volume. However, I have no idea how to do this and haven't been able to find much guidance either.

  • I have found this thread: https://answers.unity.com/questions/1178637/finding-volume-of-two-3d-meshes-intersection.html but was not able to use it to solve my problem unfortunately.

Does anyone have an idea on how I could approach this problem? Any help would be greatly appreciated!

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image elenzil · Dec 18, 2019 at 06:29 PM 0
Share

looks like you developed an approach.

as i recall there was a demo on https://shadertoy.com about two months ago which had an analytical solution to the problem of what volume of a box is 'submerged'. unfortunately i haven't been able to find it.

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by avandenberg · Dec 18, 2019 at 03:12 PM

Managed to find out a way to do this. I created a voxel grid using the same mesh with NVidia Flex (https://assetstore.unity.com/packages/tools/physics/nvidia-flex-for-unity-1-0-beta-120425). Got the position of these particles in the first frame (this is in the update loop, since for whatever reason the particle positions are all 0,0,0 when the startfunction runs):

 if (m_particles == null) // For some reason the positions only get loaded in at the first update (not at start)
 {
     NVIDIA.Flex.FlexSolidActor skim_actor = skimmerObject.GetComponent<NVIDIA.Flex.FlexSolidActor>();
             
     m_particles = AddPos(ToVector3(skim_actor.particles), -skimmerObject.transform.position); // Get the position relative to the skimmer position
     skim_actor.enabled = false; // Turn off the flex object so that it doesn't interfere with anything
     Nparticles = m_particles.Length;
 }

Where ToVector3 is a custom function:

 Vector3[] ToVector3(Vector4[] parent) 
 {
     // For some reason the particle positions come in Vector4 in which the w is always 1, remove this component here.
     Vector3[] Vec3Arr = new Vector3[parent.Length];
 
     for (int i = 0; i < parent.Length; i++)
     {
         Vec3Arr[i] = new Vector3(parent[i].x, parent[i].y, parent[i].z);
     }
     return Vec3Arr;
 }

I check if the colliders are intersecting and then scan how many particles are below the surface:

 MeshCollider skimColl = skimmerObject.GetComponent<MeshCollider>(); // Use the meshcollider in this case? a bit more intensive i guess but as long as its convex & trigger is turned on it should be fine.
 Collider bathColl = zincObject.GetComponent<Collider>(); // Best if this is a BoxCollider but could be any collider.
 
 if (bathColl.bounds.Intersects(skimColl.bounds)) // Check if they are colliding at all to prevent unneccessary calculations
 {
     colliding = true; // Set a bool to display in Editor
 
     float surfaceY = zincObject.transform.position.y + zincObject.transform.localScale.y/2; // The height of the bath
 
     Vector3[] currPos = TransformArr(m_particles, skimmerObject.transform.localToWorldMatrix); // Get the actual position of each voxel
 
     int detected = scanBathForSkimmer(currPos, surfaceY); // Find out how many voxels are in the bath
 
     fractionSubmerged = detected / Nparticles; // The fraction of the object that is submerged.

The positions are found by using the controlled objects transformation matrix:

 int scanBathForSkimmer(Vector3[] pos, float ylevel) 
 {
     // since we already checked if the colliders are intersecting, and the bath can only be acessed from above
     // we only need to check the yposition for every voxel and see if it is below the surface or not.
     int detected = 0;
     for (int i = 0; i < pos.Length; i++)
     {
         if (pos[i].y > ylevel) detected++;
     }
     return detected;
 }


 Vector3[] TransformArr(Vector3[] parent, Matrix4x4 matrix)
 {
     Vector3[] transformed = new Vector3[parent.Length];

     for (int i=0; i< m_particles.Length; i++)
     {
         transformed[i] = matrix.MultiplyPoint3x4(m_particles[i]);
     }
     return transformed;
 }

And the bath is scanned using:

 int scanBathForSkimmer(Vector3[] pos, float ylevel) 
 {
     // since we already checked if the colliders are intersecting, and the bath can only be acessed from above
     // we only need to check the yposition for every voxel and see if it is below the surface or not.
     int detected = 0;
     for (int i = 0; i < pos.Length; i++)
     {
         if (pos[i].y > ylevel) detected++;
     }
     return detected;
 }

Owh and one more important part to this is that I customized the NVidia flex asset to output the particle positions, as this doesn't do so automatically. This is done by changing FlexContainer.cs to contain:

     private int m_numParticles = 0;

     List<FlexActor> m_actors = new List<FlexActor>(); 

     public int maxParticles { get { return m_maxParticles; } set { m_maxParticles = value; } }

     public int numParticles { get { return m_numParticles; } }

     public List<FlexActor> actors { get { return m_actors; } }

Modify its AddActor and RemoveActor function:

     public void AddActor(FlexActor actor)
     {
         if (m_actorCount == 0) CreateContainer();
                 actor.id = m_actorCount;
         ++m_actorCount;
                 m_actors.Add(actor); 
                 m_numParticles += actor.asset.particles.Length;
     }
 public void RemoveActor(FlexActor actor)
 {
             m_numParticles -= actor.asset.particles.Length;
             m_actors.Remove(actor); 
     --m_actorCount;
     if (m_actorCount == 0) DestroyContainer();
 }

Additionally you need to change the FlexActor.cs to contain:

  [SerializeField]
  Vector4[] m_particles;
  [SerializeField]
  Vector3[] m_velocities;

 public Vector4[] particles
 {
     get { return m_particles; }
 }

 public Vector3[] velocities
 {
     get { return m_velocities; }
 }

And change the AqcuireAsset and ReleaseAsset functions:

     void AcquireAsset()
     {
         if (subclassAsset)
         {
             m_currentAsset = subclassAsset;
             m_currentAsset.onBeforeRebuild += OnBeforeRecreate;
             m_currentAsset.onAfterRebuild += OnAfterRecreate;
                     m_particles = new Vector4[m_currentAsset.particles.Length]; 
                     m_velocities = new Vector3[m_currentAsset.particles.Length]; 
         }
     }

     void ReleaseAsset()
     {
         if (m_currentAsset)
         {
             m_currentAsset.onBeforeRebuild -= OnBeforeRecreate;
             m_currentAsset.onAfterRebuild -= OnAfterRecreate;
             m_currentAsset = null;
                     m_particles = null; 
                     m_velocities = null; 
         }
     }

Add the following line to the OnFlexUpdate function (after the UpdateBounds call):

     UpdateParticles(_particleData);

A new function, defined by:

             void UpdateParticles(FlexContainer.ParticleData _particleData)
             {
                 if (m_container != null && m_indices != null && m_indices.Length > 0)
                 {
                     _particleData.GetParticles(m_indices[0], m_indices.Length, m_particles);
                     _particleData.GetVelocities(m_indices[0], m_indices.Length, m_velocities); 
                 }
             }

This function is the most important part and is what enables the updating of the particle positions. I found these changes by investigating the following git repo: https://github.com/neuroailab/flex-ml-agents/

A bit of a big workaround but I had most of the functionality implemented already so extending it like this wasn't that much of a problem.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

120 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

What is the best way to render a volume from a stack of 2D slices? 0 Answers

How to fill a volume with a procedurally generated 3d voxel grid? 0 Answers

Volume detection. 0 Answers

Check if GameObject is within the volume of a cone. 4 Answers

Rounding edges of cubes (Voxels and Marching Cubes) 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges