• 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
1
Question by Fluidmind · Sep 11, 2020 at 12:14 AM · dots

3D Gravity - how to stand up?

I have a system that runs the gravity calculation emanating from massive object origins. What I do is tag PhysicsVelocity entities within range of constant forces (AppliedPressure in the code), and the next system just applies that directly to PhysicsVelocity. This isn't where I'm having the problem.


Now that I have spherical gravity, I want entities with a certain tag (Lifeform in this case) to "stand", basically point their +y axis at -sum(AppliedPressure). I feel like there is math or a simple solution to this. Below is the current state of my LifeformBehavior system. When in play mode, once the body in question touches the planet (my trigger right now for trying to reorient), my goal is to send a quaternion that will do the job of aligning the axis' above. putting in logic to make it a progressive action is secondary, but something I want to incorporate. (perhaps animation states?)


Things I have considered:


Using Quaternion.LookDirection, using -sum(AppliedPressure) as up, but getting or better yet storing and using a forward facing on say the lifeform doesn't seem maintainable, as I'd have to update that value by extracting it from the rotation value every frame. Part of the problem with these approaches, is not all lifeforms will be in contact with any given planet at a time. Capturing and transforming the quaternion is unnecessary for anything not under AppliedPressure.


Using quaternion.AngleAxis, (or AxisAngle, whichever is not deprecated), but the problem remains that I can easily calculate the Axis (-sum(AppliedPressure), but storing the angle is again on the lifeform.


So what's the problem? Well, first, by player doesn't point anything reliably at the planet. I can maintain control of the rotation of the player object through the input system, but it flops around on the planet surface and refuses to stand. I could use any help you have to offer.

 using System.Collections;
 using System.Collections.Generic;
 using Unity.Entities;
 using Unity.Jobs;
 using UnityEngine;
 using Unity.Physics;
 using Unity.Transforms;
 using Unity.Collections;
 using Unity.Mathematics;
 using Unity.Physics.Systems;
 using Unity.Burst;
 using System.Text;
 using UnityEditor.UIElements;
 using System.Runtime.InteropServices;
 using RaycastHit = Unity.Physics.RaycastHit;
 
 [UpdateInGroup(typeof(LateSimulationSystemGroup))]
 [UpdateBefore(typeof(ForceApplier))]
 public class LifeformBehaviorSystem : JobComponentSystem
 {
     ContactDetection standJob;
     JobHandle standJobHandle;
 
     BuildPhysicsWorld BuildPhysicsWorldSystem;
     StepPhysicsWorld StepPhysicsWorldSystem;
     EntityCommandBufferSystem ECBS;
 
     EntityQuery Lifeforms;
     ComponentType[] LifeformDescription = new ComponentType[1];
 
     protected override void OnCreate()
     {
         BuildPhysicsWorldSystem = World.GetExistingSystem<BuildPhysicsWorld>();
         StepPhysicsWorldSystem = World.GetExistingSystem<StepPhysicsWorld>();
         ECBS = World.GetExistingSystem<EntityCommandBufferSystem>();
 
         LifeformDescription[0] = typeof(Lifeform);
         Lifeforms = GetEntityQuery(LifeformDescription);
     }
     protected override JobHandle OnUpdate(JobHandle inputDeps)
     {
         SimulationCallbacks.Callback prepareCallback = (ref ISimulation simulation, ref PhysicsWorld world, JobHandle inDeps) =>
         {
             
             EntityCommandBuffer _ecb = ECBS.CreateCommandBuffer();
 
             JobHandle result = new ContactDetection()
             {
                 translationData = GetComponentDataFromEntity<Translation>(),
                 rotationData = GetComponentDataFromEntity<Rotation>(),
                 lifeformData = GetComponentDataFromEntity<Lifeform>(),
                 pressureData = GetBufferFromEntity<AppliedPressure>(),
                 ecb = _ecb.ToConcurrent()
             }.Schedule(
                 World.GetExistingSystem<StepPhysicsWorld>().Simulation,
                 ref World.GetExistingSystem<BuildPhysicsWorld>().PhysicsWorld,
                 inDeps
                 );
             ECBS.AddJobHandleForProducer(result);
             result = JobHandle.CombineDependencies(result, inDeps);
             return result;
         };
 
         StepPhysicsWorldSystem.EnqueueCallback(SimulationCallbacks.Phase.PostCreateContactJacobians, prepareCallback, inputDeps);
         GroundedCheckJob groundedCheck = new GroundedCheckJob()
         {
             entityType = GetArchetypeChunkEntityType(),
             lifeformType = GetArchetypeChunkComponentType<Lifeform>(),
             rotationType = GetArchetypeChunkComponentType<Rotation>(),
             translationType = GetArchetypeChunkComponentType<Translation>(),
             postProcessTag = GetArchetypeChunkComponentType<PostProcessLifeformCollision>(),
             pressureBuffer = GetArchetypeChunkBufferType<AppliedPressure>(),
             ecb = ECBS.CreateCommandBuffer().ToConcurrent(),
 
         };
 
 
         return inputDeps;
     }
 
     protected struct GroundedCheckJob : IJobChunk
     {
         public ArchetypeChunkEntityType entityType;
         public ArchetypeChunkComponentType<Lifeform> lifeformType;
         public ArchetypeChunkComponentType<Rotation> rotationType;
         public ArchetypeChunkComponentType<Translation> translationType;
         public ArchetypeChunkComponentType<PostProcessLifeformCollision> postProcessTag;
         public ArchetypeChunkBufferType<AppliedPressure> pressureBuffer;
         public EntityCommandBuffer.Concurrent ecb;
 
         public void Execute(ArchetypeChunk Lifeforms, int chunkIndex, int firstEntityIndex)
         {
             NativeArray<Entity> EntityList = Lifeforms.GetNativeArray(entityType);
             NativeArray<Lifeform> lifeformDetails = Lifeforms.GetNativeArray<Lifeform>(lifeformType);
             NativeArray<Rotation> rotationData = Lifeforms.GetNativeArray<Rotation>(rotationType);
             NativeArray<Translation> translationData = Lifeforms.GetNativeArray<Translation>(translationType);
             BufferAccessor<AppliedPressure> pressureData = Lifeforms.GetBufferAccessor<AppliedPressure>(pressureBuffer);
             float3 pressureVector = float3.zero;
             NativeList<RaycastCommand> groundChecks = new NativeList<RaycastCommand>(Lifeforms.Count, Allocator.TempJob);
             for (int thisEntity = 0; thisEntity < Lifeforms.Count; thisEntity++)
             {
                 for (int pressureIndex = 0; pressureIndex < pressureData[thisEntity].Length; pressureIndex++)
                 {
                     pressureVector += pressureData[thisEntity][pressureIndex].Vector;
                 }
                 if (math.length(pressureVector) == 0) return;
                 rotationData[thisEntity] = new Rotation()
                 {
                     Value = Quaternion.AngleAxis(2*math.acos(rotationData[thisEntity].Value.value.w), -pressureVector)
                 };
                 pressureVector = float3.zero;
                 ecb.AddComponent<Rotation>(chunkIndex, EntityList[thisEntity], new Rotation() { Value = Quaternion.RotateTowards(rotationData[thisEntity].Value, quaternion.AxisAngle(-pressureVector, lifeformDetails[thisEntity].angle), 300) });
 
             }
             //NativeArray<RaycastHit> groundHits = new NativeArray<RaycastHit>(groundChecks.Length, Allocator.TempJob);
             //RaycastCommand.ScheduleBatch(groundChecks, groundHits, 50);
 
         }
     }
 
     protected struct PostProcessLifeformCollision : IComponentData { }
     protected struct ContactDetection : IJacobiansJob
     {
         public ComponentDataFromEntity<Lifeform> lifeformData;
         [ReadOnly] public ComponentDataFromEntity<Translation> translationData;
         public ComponentDataFromEntity<Rotation> rotationData;
         [ReadOnly] public BufferFromEntity<AppliedPressure> pressureData;
         public EntityCommandBuffer.Concurrent ecb;
 
         //[BurstCompile]
         [BurstDiscard]
         public void Execute(ref ModifiableJacobianHeader header, ref ModifiableContactJacobian jacobian)
         {
             Entity lifeform = Entity.Null;
             if (lifeformData.Exists(header.EntityA) && lifeform == Entity.Null) lifeform = header.EntityA;
             if (lifeformData.Exists(header.EntityB) && lifeform == Entity.Null) lifeform = header.EntityB;
             if (lifeform == Entity.Null) return;
             ContactJacobianAngular a = new ContactJacobianAngular();
             a.AngularA = 0;
             a.AngularB = 0;
             ContactJacAngAndVelToReachCp t = new ContactJacAngAndVelToReachCp();
             t.Jac = a;
             t.VelToReachCp = 0;
             //header.SetAngularJacobian(0, t);
             //header.SetAngularJacobian(1, t);
             //jacobian.AngularFriction = a;
 
             int jobMarker = header.EntityA.Index;
             jobMarker += header.EntityA.Version * (int)math.pow(10, math.log10(jobMarker));
             jobMarker += header.EntityB.Index * (int)math.pow(10, math.log10(jobMarker));
             jobMarker += header.EntityA.Version * (int)math.pow(10, math.log10(jobMarker));
 
             ecb.AddComponent<PostProcessLifeformCollision>(jobMarker, lifeform, new PostProcessLifeformCollision());
         }
 
         public void Execute(ref ModifiableJacobianHeader header, ref ModifiableTriggerJacobian jacobian)
         {
         }
     }
 
 }
Comment
Add comment · Show 3
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 andrew-lukasik · Sep 16, 2020 at 11:45 AM 0
Share

Rotation component is kind of a local rotation and is not needed to control rotations, necessarily. You can modify LocalToWorld matrix directly without any additional memory overhead (since LTW is required by Render$$anonymous$$eshSystem already).

avatar image andrew-lukasik · Sep 16, 2020 at 11:58 AM 0
Share

Another upside of using LocalToWorld is that you don't need to store UP vector anywhere, since it's just float3 up = math.mul( localToWorld.Rotation , new float3{y=1} ); anytime you actually need that direction.

avatar image suIly · Sep 16, 2020 at 02:34 PM 0
Share

dang that's a lot of code. I can't understand half of it

0 Replies

· Add your reply
  • Sort: 

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

137 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 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

Changing mesh collider's mesh cause objects go into mesh. 1 Answer

[ECS] Create Entities from Job ( IJobForEachWithEntity) using an EntityCommandBuffer 1 Answer

Best way to get data from a Monobheaviour in a JobComponentSystem? 2 Answers

[ECS] DefaultWorldInitialization.Initialize take 50MB 1 Answer

How to serialize/deserialize entities at runtime -1 Answers


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