Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411432 Posts in 69363 Topics- by 58417 Members - Latest Member: gigig987

April 20, 2024, 05:46:19 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)relative cam on arbitrary angled surfaces - take two
Pages: [1]
Print
Author Topic: relative cam on arbitrary angled surfaces - take two  (Read 1688 times)
gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« on: March 14, 2013, 12:11:43 AM »

https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine.html

I had digested difficulties and advices in the old thread, broke down things, solve some on my own and finally tossed everything to start again but focused on relevant aspect.

There is two problem:

1. relative cam
a - I should be able to make the camera turn around the local up vector of the avatar. This at any angle this up vector might be.
b - I should be able to keep the relative camera direction constant when the character move on a sphere (arbitrary surface angles) but not dependent of the character direction (local XZ plane).
c - I should be able to turn the independent character direction in the direction of the input based on local XZ plane of the camera.

2. air ground transition:
I will not get into this just yet but it's kinda related. Let's solve one thing at a time.


Now 1.a should not be a problem at all, I use a specific algorithm i just need to apply it to the camera, instead of picking the ground normal I need to pick the character up vector to align to, BRILLIANT, I thought ... except the camera stay hopelessly flat for unknown reason that drive me made (see the link above). Point b and c depend on solving a.

In short, how the hell I get the camera orbiting the main character at any angle this character is, but in relative cam control (not 3PS always behind cam)?

Wait this small unity indie game does it, how is that I can't?


Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #1 on: March 14, 2013, 08:15:01 PM »

Here are the reduce code:

This one if for movement, magic happen in the updateOrientation() methods, anything else is fairly conventional strafe/forward code with raycast detection. In this sample the rotation code has been deleted has i'm simply trying to get the camroot to align itself with the character up with no success at all!
Code:
using UnityEngine;
using System.Collections;

public class MovementController : MonoBehaviour
{
public float
deadZoneValue = 0.1f,
acceleration  = 50.0f;


//--------------------------------------------------------------------------------------------
void OnGUI()
{
GUILayout.Label( "transform.rotation : " + transform.rotation );
GUILayout.Label( "transform.position : " + transform.position );
}

void FixedUpdate ()
{

Ray
ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up );
RaycastHit
raycast_result;
Rigidbody
rigid_body = gameObject.rigidbody;

if ( Physics.Raycast( ground_check_ray, out raycast_result ) )
{
Vector3
next_position;

UpdateOrientation( gameObject.transform.forward, raycast_result.normal );
next_position = GetNextPosition( raycast_result.point );
rigid_body.MovePosition( next_position );
}
}
//--------------------------------------------------------------------------------------------


private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

private Vector3 GetNextPosition( Vector3 current_ground_position )
{
float
input_vertical_movement = Input.GetAxisRaw( "Vertical" ),
input_horizontal_movement = Input.GetAxisRaw( "Horizontal" );

Vector3
camera_forward = this.transform.forward,
camera_right = this.transform.right,
next_position;

next_position =
current_ground_position +
gameObject.transform.up * 0.5f;

if( Mathf.Abs( input_vertical_movement ) > deadZoneValue )
{
next_position +=
camera_forward *
acceleration *
input_vertical_movement *
Time.deltaTime;
}
if( Mathf.Abs( input_horizontal_movement ) > deadZoneValue )
{
next_position +=
camera_right *
acceleration *
input_horizontal_movement *
Time.deltaTime;
}

return next_position;
}

}


Here is the camera code, the faulty nasty beast who refuse to submit, I have try different things and result are always faulty, I'll try to redo the variation and compile playable.
Basically this code run on camera, it takes as parameter a root object where a pivot (camera hook) and a target are parented (where the camera look). The idea was to place the root object at the character position and rotate it, the camera position itself on the pivot.

Code:
using UnityEngine;
using System.Collections;

public class CameraDrive : MonoBehaviour
{
public GameObject
targetObject;

public Transform
camPivot,
camTarget,
camRoot;

float
rot = 0;
//----------------------------------------------------------------------------------------------------------
void Start()
{
this.transform.position = targetObject.transform.position;
this.transform.rotation = targetObject.transform.rotation;
}

void FixedUpdate()
{
//the pivot system
camRoot.position = targetObject.transform.position;

//input on pivot orientation
float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); //
rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); //
wrapAngle( rot ); //

//align camroot with target object up



camRoot.rotation.SetLookRotation(targetObject.transform.forward,targetObject.transform.up);



//this camera
this.transform.position = camPivot.position; //set the camera to the pivot
this.transform.LookAt( camTarget.position ); //
}
//----------------------------------------------------------------------------------------------------------
public float wrapAngle ( float Degree )
{
while (Degree < 0.0f)
{
Degree = Degree + 360.0f;
}
while (Degree >= 360.0f)
{
Degree = Degree - 360.0f;
}
return Degree;
}

private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

float GetOffsetAngle( float targetAngle, float DestAngle )
{
return ((targetAngle - DestAngle + 180)% 360)  - 180;
}
//----------------------------------------------------------------------------------------------------------
void OnDrawGizmos()
{
Gizmos.DrawCube(
camPivot.transform.position,
new Vector3(1,1,1)
);

Gizmos.DrawCube(
camTarget.transform.position,
new Vector3(1,5,1)
);

Gizmos.DrawCube(
camRoot.transform.position,
new Vector3(1,1,1)
);
}

void OnGUI()
{
GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString());
GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString());

}
}

Now let's look at different implementation and effects of the part where it should have work:

Code:
camRoot.rotation.SetLookRotation(targetObject.transform.forward,targetObject.transform.up);

Okay fine, transform.forward/up might be local so let's do better:

Code:
		camRoot.rotation.SetLookRotation(
this.transform.TransformDirection(targetObject.transform.forward),
this.transform.TransformDirection(targetObject.transform.up)
);

Still not working, let's try to go random:
Code:
		camRoot.rotation.SetLookRotation(
this.transform.InverseTransformDirection(targetObject.transform.forward),
this.transform.InverseTransformDirection(targetObject.transform.up)
);

Duh, the result is just the same, let's try the secret sauce which allow perfect movement on a sphere:

      
Code:
UpdateOrientation(targetObject.transform.forward,targetObject.transform.up);

Result ... result never change ... It's totally non sense and bullshit any kind of way I slice it. I know I get data from targetObject.transform, position is out rightfully, something should happen anything, broken thing, but no, just nothing, it sit down upright and do nothing!
« Last Edit: March 14, 2013, 08:43:42 PM by Gimym TILBERT » Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #2 on: March 15, 2013, 08:25:37 PM »

I change the UpdateOrientation code and now problem a is solved
Code:
private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

Turns out the mistake was a silly mistake:
I applied the orientation to transform.rotation instead of camRoot.transform.rotation since the camera hold the code but apply it to the root of the cam setup.

The reason I have the camera and a separate setup is that it allow me to free the camera for more contextual code from the character itself. The camera can now pick any target. It also allow to decouple camera reference from character reference, as the camera is free I don't need to express the character in term of camera, I express the character direction relative to the setup. The camera is not always align to the character but the setup is, therefore sharing the same reference. My previous mistake was to try to lower the number of DOF in the code, I should have increase it which is what I'm doing now.

Since the camera is now aligning correctly I had simple support for camera rotation.
Code:
	void FixedUpdate()
{
//the pivot system
camRoot.position = targetObject.transform.position;

//input on pivot orientation
float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); //
rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); //
wrapAngle( rot ); //

//when the target object rotate, it rotate too, this should not happen


UpdateOrientation(targetObject.transform.forward,targetObject.transform.up);

camRoot.transform.RotateAround(camRoot.transform.up,rot);


//this camera
this.transform.position = camPivot.position; //set the camera to the pivot
this.transform.LookAt( camTarget.position ); //
}

Simply adding camRoot.transform.RotateAround(camRoot.transform.up,rot); after the orientation update since I was already computing the rotation according to input. Works pretty good ^^ .

here is the new build:
https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine2.html

arrow to move/strafe, mice to rotate around the character.

Now point c should be a formality, I have to express input relative to local camroot and then compare it to actual character direction, then slowly normalize lerp the too.

Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #3 on: March 18, 2013, 08:47:45 PM »

Instead of trying to implement relative movement I have done a visualization first:

First I made this function which is trivial relative cam:
Code:
Vector3 RelativeCamDirection()
{

float
input_vertical_movement = Input.GetAxisRaw( "Vertical" ),
input_horizontal_movement = Input.GetAxisRaw( "Horizontal" );

Vector3
relative_forward = camRoot.transform.forward,
relative_right = camRoot.transform.right,

relative_direction =
( relative_forward * input_vertical_movement )
+
( relative_right * input_horizontal_movement );

return relative_direction.normalized;
}

Then I added this with a new public transform ( a huge cylinder showing where the direction point at):
Code:
//debug the relcam dir
relcamdirDebug.transform.localPosition = RelativeCamDirection()*6;

and here is the build:

https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine3.html

And oups it's all wrong I feel stupid, it's wrong even on flat surface Huh? not sure what's wrong!
I'm stupid, I'm going to fix it asap.
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #4 on: March 22, 2013, 11:01:28 PM »

So I have a bit of burnout and even simple code was flying over my head, I took a rest and came back.
As soon as my eyes land on this, I could see what was wrong.
Code:
		Vector3
relative_forward = camRoot.transform.forward,
relative_right = camRoot.transform.right,

The correct way to do it is that!

Code:
		Vector3
relative_forward = Vector3.forward,
relative_right = Vector3.right,

I don't even need to check to know it works:

https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine4.html

Okay now let's effectively put it in with motion...
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #5 on: April 05, 2013, 10:06:25 PM »

I'm still failing at the same point Sad
That is I have the correct input, I have the correct translation in the camera direction ... but whenever I attempt to slowly lerp the direction of the character in direction of the input, all I get is wild spin!
Sad

Also discovered that strafing to the right has major singularity trapping on the equator!!
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #6 on: April 05, 2013, 10:14:05 PM »

The lastest working code:

Movement code

Code:
using UnityEngine;
using System.Collections;

public class MovementController : MonoBehaviour
{
public float
deadZoneValue = 0.1f,
angle,
acceleration  = 50.0f;
public Vector3
motion ;

//--------------------------------------------------------------------------------------------
void OnGUI()
{
GUILayout.Label( "transform.rotation : " + transform.rotation );
GUILayout.Label( "transform.position : " + transform.position );
GUILayout.Label( "angle : " + angle );
}

void FixedUpdate ()
{

Ray
ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up );
RaycastHit
raycast_result;
Rigidbody
rigid_body = gameObject.rigidbody;

if ( Physics.Raycast( ground_check_ray, out raycast_result ) )
{
Vector3
next_position;

//UpdateOrientation( gameObject.transform.forward, raycast_result.normal );
UpdateOrientation( gameObject.transform.forward, raycast_result.normal );
next_position = GetNextPosition( raycast_result.point );
rigid_body.MovePosition( next_position );
}
}
//--------------------------------------------------------------------------------------------


private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

private Vector3 GetNextPosition( Vector3 current_ground_position )
{
Vector3
next_position;

// //--------------------------------------------------------------------
// angle = 0;
// Vector3 dir = this.transform.InverseTransformDirection(motion);
// angle = Vector3.Angle(Vector3.forward, dir);// * 1f * Time.fixedDeltaTime;
//
// if(angle > 0) this.transform.Rotate(0,angle,0);
// //--------------------------------------------------------------------


next_position =
current_ground_position +
gameObject.transform.up * 0.5f
+ motion
;

return next_position;
}

}


camera code

Code:
using UnityEngine;
using System.Collections;

public class CameraDrive : MonoBehaviour
{
public GameObject
targetObject;

public Transform
camPivot,
camTarget,
camRoot,

relcamdirDebug;

float
rot = 0;
//----------------------------------------------------------------------------------------------------------
void Start()
{
this.transform.position = targetObject.transform.position;
this.transform.rotation = targetObject.transform.rotation;
}

void FixedUpdate()
{
//the pivot system
camRoot.position = targetObject.transform.position;

//input on pivot orientation
rot = 0;
float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); //
rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); //
wrapAngle( rot ); //

//when the target object rotate, it rotate too, this should not happen


UpdateOrientation(this.transform.forward,targetObject.transform.up);

camRoot.transform.RotateAround(camRoot.transform.up,rot);

//debug the relcam dir
RelativeCamDirection()
;

//this camera
this.transform.position = camPivot.position; //set the camera to the pivot
this.transform.LookAt( camTarget.position ); //
}
//----------------------------------------------------------------------------------------------------------
public float wrapAngle ( float Degree )
{
while (Degree < 0.0f)
{
Degree = Degree + 360.0f;
}
while (Degree >= 360.0f)
{
Degree = Degree - 360.0f;
}
return Degree;
}

private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

float GetOffsetAngle( float targetAngle, float DestAngle )
{
return ((targetAngle - DestAngle + 180)% 360)  - 180;
}
//----------------------------------------------------------------------------------------------------------
void OnDrawGizmos()
{
Gizmos.DrawCube(
camPivot.transform.position,
new Vector3(1,1,1)
);

Gizmos.DrawCube(
camTarget.transform.position,
new Vector3(1,5,1)
);

Gizmos.DrawCube(
camRoot.transform.position,
new Vector3(1,1,1)
);
}

void OnGUI()
{
GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString());
GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString());
GUI.Label(new Rect(0,100,1000,20*10), "rot : " + rot.ToString());

}
//----------------------------------------------------------------------------------------------------------
void RelativeCamDirection()
{

float
input_vertical_movement = Input.GetAxisRaw( "Vertical" ),
input_horizontal_movement = Input.GetAxisRaw( "Horizontal" );

Vector3
relative_forward = Vector3.forward,
relative_right = Vector3.right,

relative_direction =
( relative_forward * input_vertical_movement )
+
( relative_right * input_horizontal_movement )
;

MovementController MC = targetObject.GetComponent<MovementController>();

MC.motion = relative_direction.normalized * MC.acceleration * Time.fixedDeltaTime;

MC.motion = this.transform.TransformDirection( MC.motion );

//MC.transform.Rotate(Vector3.up, input_horizontal_movement * 10f * Time.fixedDeltaTime);
}
}
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #7 on: April 05, 2013, 10:33:33 PM »

Latest demo
https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine5.html
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #8 on: April 06, 2013, 01:36:29 PM »


I made a new demo, and it's totally broken ...
https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine5a.html

I have toss the problem at internet for 3 years, and it is still scratching is head.
So I asked the only person I knew who had solve the problem:

Quote from: Sophie Houlden
What's "the move"? is there some secret trick I don't know about? o__o
ah right, how I *coded* it, gotcha! well... it's been a while but I'll try to explain my hazy memory of the system!
raycast down to find the floor, whatever normal that ray hit then has, is "up"
convert (vector that is input*cam directions) relative to the plane determind by "up", move sarah along that plane...
then raycast again to find new 'up'. I realise the middle step is more or less voodoo, but that's where my memoryis hazy
IIRC things I tried were unity's own Plane class or some such, quite handy, and also making empty reference gameobjects
there was also some degree of rotating stuff in another thing's local space so that 'forward' and 'left' never jumped 180
otherwise you could get sarah to go jittery the moment you cross odd angles
ya, even with the right approach if you use the transformpoint when you want inverse or have a bad lookat it all breaks
can't remember how I used it, but I think it solved some problems http://docs.unity3d.com/Documentation/ScriptReference/Plane.html
...though it might have been for a different game entirely... sorry if that's the case, hazy memory really is hazy ^__^;

Now I need to parse the clue ...
Logged

moi
Level 10
*****


DILF SANTA


View Profile WWW
« Reply #9 on: April 06, 2013, 01:51:38 PM »

send me the unity source file, I'll fix it for you
Logged

subsystems   subsystems   subsystems
gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #10 on: April 06, 2013, 02:05:53 PM »

The goal was to make it open source anyway once solved


Zipped project
https://dl.dropbox.com/u/24530447/sonic%20engine/lite%20sonic%20engine.rar

Unitypackage
https://dl.dropbox.com/u/24530447/LiteSonicEngine5a.unitypackage
Logged

moi
Level 10
*****


DILF SANTA


View Profile WWW
« Reply #11 on: April 06, 2013, 02:17:01 PM »

I'll take a look
Logged

subsystems   subsystems   subsystems
gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #12 on: April 06, 2013, 03:41:58 PM »

Thanks
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #13 on: April 07, 2013, 05:22:50 PM »

Okay I got a little lost on the way.

First the original code in the op just works. So I have a character correctly moving on a sphere (arbitrary slopes angles).

The problem is that I try to have a vector from the camera "setup" (which share the alignment (same plane) of the character, except for the local Y rot) and then align the character to that vector ON THE SAME PLANE! Which is essentially a local problem and strictly 2D!

HOW DOES THE HELL THIS GO WRONG  Cry  WTF Huh?  Sad Shocked Angry  My Word!  Apoplectic Outraged Mock Anger Screamy Concerned Facepalm the jury is still out and confused
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #14 on: April 07, 2013, 07:39:36 PM »

Movement

Code:
using UnityEngine;
using System.Collections;

public class MovementController : MonoBehaviour
{
public float
deadZoneValue = 0.1f,
angle,
acceleration  = 50.0f;
public Vector3
motion ;

//--------------------------------------------------------------------------------------------
void OnGUI()
{
GUILayout.Label( "transform.rotation : " + transform.rotation );
GUILayout.Label( "transform.position : " + transform.position );
GUILayout.Label( "angle : " + angle );
}

void FixedUpdate ()
{

Ray
ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up );
RaycastHit
raycast_result;
Rigidbody
rigid_body = gameObject.rigidbody;

if ( Physics.Raycast( ground_check_ray, out raycast_result ) )
{
Vector3
next_position;

//UpdateOrientation( gameObject.transform.forward, raycast_result.normal );
UpdateOrientation( gameObject.transform.forward, raycast_result.normal );
next_position = GetNextPosition( raycast_result.point );
rigid_body.MovePosition( next_position );
}
}
//--------------------------------------------------------------------------------------------


private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

private Vector3 GetNextPosition( Vector3 current_ground_position )
{
Vector3
next_position;

// //--------------------------------------------------------------------
// angle = 0;
// Vector3 dir = this.transform.InverseTransformDirection(motion);
// angle = Vector3.Angle(Vector3.forward, dir);// * 1f * Time.fixedDeltaTime;
//
// if(angle > 0) this.transform.Rotate(0,angle,0);
// //--------------------------------------------------------------------


next_position =
current_ground_position +
gameObject.transform.up * 0.5f
+ motion
;

return next_position;
}

}

Camera

Code:
using UnityEngine;
using System.Collections;

public class CameraDrive : MonoBehaviour
{
public GameObject
targetObject;

public Transform
camPivot,
camTarget,
camRoot,

relcamdirDebug;

float
rot = 0;
//----------------------------------------------------------------------------------------------------------
void Start()
{
this.transform.position = targetObject.transform.position;
this.transform.rotation = targetObject.transform.rotation;
}

void FixedUpdate()
{
//the pivot system
camRoot.position = targetObject.transform.position;

//input on pivot orientation
rot = 0;
float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); //
rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); //
wrapAngle( rot ); //

//when the target object rotate, it rotate too, this should not happen


UpdateOrientation(this.transform.forward,targetObject.transform.up);

camRoot.transform.RotateAround(camRoot.transform.up,rot);

//debug the relcam dir
RelativeCamDirection()
;

//this camera
this.transform.position = camPivot.position; //set the camera to the pivot
this.transform.LookAt( camTarget.position ); //
}
//----------------------------------------------------------------------------------------------------------
public float wrapAngle ( float Degree )
{
while (Degree < 0.0f)
{
Degree = Degree + 360.0f;
}
while (Degree >= 360.0f)
{
Degree = Degree - 360.0f;
}
return Degree;
}

private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

float GetOffsetAngle( float targetAngle, float DestAngle )
{
return ((targetAngle - DestAngle + 180)% 360)  - 180;
}
//----------------------------------------------------------------------------------------------------------
void OnDrawGizmos()
{
Gizmos.DrawCube(
camPivot.transform.position,
new Vector3(1,1,1)
);

Gizmos.DrawCube(
camTarget.transform.position,
new Vector3(1,5,1)
);

Gizmos.DrawCube(
camRoot.transform.position,
new Vector3(1,1,1)
);
}

void OnGUI()
{
GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString());
GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString());
GUI.Label(new Rect(0,100,1000,20*10), "rot : " + rot.ToString());

}
//----------------------------------------------------------------------------------------------------------
void RelativeCamDirection()
{

float
input_vertical_movement = Input.GetAxisRaw( "Vertical" ),
input_horizontal_movement = Input.GetAxisRaw( "Horizontal" );

Vector3
relative_forward = Vector3.forward,
relative_right = Vector3.right,

relative_direction =
( relative_forward * input_vertical_movement )
+
( relative_right * input_horizontal_movement )
;

MovementController MC = targetObject.GetComponent<MovementController>();

MC.motion = relative_direction.normalized * MC.acceleration * Time.fixedDeltaTime;

MC.motion = this.transform.TransformDirection( MC.motion );

//MC.transform.Rotate(Vector3.up, input_horizontal_movement * 10f * Time.fixedDeltaTime);
if (MC.motion.sqrMagnitude > 0)
{
Quaternion target = Quaternion.LookRotation( relative_direction, MC.transform.up );
MC.transform.rotation = Quaternion.Slerp(MC.transform.rotation, target, 0.5f);
}
}
}

I didn't provide the modified code for the 5a version, only the camera was changed, 2 lines of code added
« Last Edit: April 07, 2013, 08:01:32 PM by Gimym TILBERT » Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #15 on: April 07, 2013, 09:17:24 PM »

Okay I'm norrowing the problem!

In movement code, I should project the motion vector, not the forward vector, this get the relative cam direction great!

However it seems there is a bug with motion itself, side input are not correctly projected along the curvature, Forward move bend, but side move does not ...
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #16 on: April 07, 2013, 09:47:42 PM »

Solved!

I was converting the motion to global space from local camera space instead of local camera "root" space. Silly error is silly!

https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine6.html
Arrow to move, mouse to turn the camera around ...

movement code

Code:
using UnityEngine;
using System.Collections;

public class MovementController : MonoBehaviour
{
public float
deadZoneValue = 0.1f,
angle,
acceleration  = 50.0f;
public Vector3
motion ;
public Vector3
ground_direction ;

//--------------------------------------------------------------------------------------------
void OnGUI()
{
GUILayout.Label( "transform.rotation : " + transform.rotation );
GUILayout.Label( "transform.position : " + transform.position );
GUILayout.Label( "angle : " + angle );
GUILayout.Label( "ground_direction : " + ground_direction );
GUILayout.Label( "motion : " + ground_direction );
}

void FixedUpdate ()
{

Ray
ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up );
RaycastHit
raycast_result;
Rigidbody
rigid_body = gameObject.rigidbody;

if ( Physics.Raycast( ground_check_ray, out raycast_result ) )
{
Vector3
next_position;

//UpdateOrientation( gameObject.transform.forward, raycast_result.normal );
UpdateOrientation( gameObject.transform.forward, raycast_result.normal );
next_position = GetNextPosition( raycast_result.point );
rigid_body.MovePosition( next_position );
ground_direction = raycast_result.normal;
}
}
//--------------------------------------------------------------------------------------------


private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_motion_to_normal_surface = motion - ( Vector3.Dot( motion, ground_normal ) ) * ground_normal;

Quaternion target;
    if (motion.sqrMagnitude > 0)
{
target = Quaternion.LookRotation( projected_motion_to_normal_surface, ground_direction );
}
else
{
target = Quaternion.LookRotation( transform.forward, ground_direction );
}
transform.rotation = target;//Quaternion.Slerp( transform.rotation, target, 0.1f );
//transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );

Debug.DrawRay(this.transform.position,motion*10,Color.yellow,0.0f,false);
}

private Vector3 GetNextPosition( Vector3 current_ground_position )
{
Vector3
next_position;

// //--------------------------------------------------------------------
// angle = 0;
// Vector3 dir = this.transform.InverseTransformDirection(motion);
// angle = Vector3.Angle(Vector3.forward, dir);// * 1f * Time.fixedDeltaTime;
//
// if(angle > 0) this.transform.Rotate(0,angle,0);
// //--------------------------------------------------------------------


next_position =
current_ground_position +
gameObject.transform.up * 0.5f
+ motion
;

return next_position;
}

}

camera code

Code:
using UnityEngine;
using System.Collections;

public class CameraDrive : MonoBehaviour
{
public GameObject
targetObject;

public Transform
camPivot,
camTarget,
camRoot,

relcamdirDebug;

float
rot = 0;
//----------------------------------------------------------------------------------------------------------
void Start()
{
this.transform.position = targetObject.transform.position;
this.transform.rotation = targetObject.transform.rotation;
}

void FixedUpdate()
{
//the pivot system
camRoot.position = targetObject.transform.position;

//input on pivot orientation
rot = 0;
float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); //
rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); //
wrapAngle( rot ); //

//when the target object rotate, it rotate too, this should not happen


UpdateOrientation(this.transform.forward,targetObject.transform.up);

camRoot.transform.RotateAround(camRoot.transform.up,rot);


//this camera
this.transform.position = camPivot.position;
//set the camera to the pivot
//Quaternion target = Quaternion.LookRotation(targetObject.transform.position - this.transform.position, targetObject.transform.up);

    //this.transform.rotation = Quaternion.Slerp(this.transform.rotation, target, 0.1f);

    //debug the relcam dir
   RelativeCamDirection();

    this.transform.LookAt( camTarget.position ); //
}
//----------------------------------------------------------------------------------------------------------
public float wrapAngle ( float Degree )
{
while (Degree < 0.0f)
{
Degree = Degree + 360.0f;
}
while (Degree >= 360.0f)
{
Degree = Degree - 360.0f;
}
return Degree;
}

private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal )
{
Vector3
projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal;

camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal );
}

float GetOffsetAngle( float targetAngle, float DestAngle )
{
return ((targetAngle - DestAngle + 180)% 360)  - 180;
}
//----------------------------------------------------------------------------------------------------------
void OnDrawGizmos()
{
Gizmos.DrawCube(
camPivot.transform.position,
new Vector3(1,1,1)
);

Gizmos.DrawCube(
camTarget.transform.position,
new Vector3(1,5,1)
);

Gizmos.DrawCube(
camRoot.transform.position,
new Vector3(1,1,1)
);
}

void OnGUI()
{
GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString());
GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString());
GUI.Label(new Rect(0,100,1000,20*10), "rot : " + rot.ToString());

}
//----------------------------------------------------------------------------------------------------------
void RelativeCamDirection()
{
Vector3
relative_direction =
( Vector3.forward * Input.GetAxisRaw( "Vertical" ) )
+
( Vector3.right * Input.GetAxisRaw( "Horizontal" ) )
;

MovementController MC = targetObject.GetComponent<MovementController>();

Vector3 direction = relative_direction.normalized * MC.acceleration * Time.fixedDeltaTime;

Vector3 abs_direction =  camRoot.transform.TransformDirection( direction );
MC.motion = abs_direction;

Debug.DrawRay (camRoot.position, camRoot.right,Color.red,0.0f,false);
Debug.DrawRay (camRoot.position, camRoot.up,Color.green,0.0f,false);
Debug.DrawRay (camRoot.position, camRoot.forward,Color.blue,0.0f,false);
//MC.transform.Rotate(Vector3.up, input_horizontal_movement * 10f * Time.fixedDeltaTime);

}
}


Okay now on:

1. adding momentum relative to surface
2. correct jump transition from ground and air (relative to gravity) with correct momentum conservation
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #17 on: April 07, 2013, 10:04:40 PM »

If you want to have fun yourself

Unity package
https://dl.dropbox.com/u/24530447/LiteSonicEngine6.unitypackage

Project folder
https://dl.dropbox.com/u/24530447/sonic%20engine/lite%20sonic%20engine%206.rar

One thing I should implement is a proper inputlock so when you go reverse and let the stick go, it change the input to the new reference. It's just a matter of storing a flag and the input direction when you cross the plane, once released or given a certain direction change threshold, modifying the input ref to the new input! Mostly for side input.
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #18 on: April 14, 2013, 08:49:50 PM »

Okay, I'm moving to coding momentum, I was doing a bit of paper testing, to see if there was any problem before diving on the code.

The routine should be:
1 - Accumulate all force in _momentum in global space
2 - convert it into local space and remove local Y component to obtain a tangent projection
3 - Apply the projection the body ...
4 - ...
5 - Profit?

Well duh not! Paper prototyping show that curvature would chip away a bit of the momentum which would dies completely off once the curvature accumulation got over 90° from the initial normal on which it was applied. It is a violation of the pseudo Newtonian physics I want to reproduce on arbitrary surface. I need to keep momentum constant in local space, therefore I must correct the momentum at each step to the new normal before applying new force.

Then I ran in a new problem, which magic would allow me to keep momentum constant in direction and strength when the reference are always shifting. The solution is to make it it's own reference! I will had a GO which would be oriented in the momentum direction and apply alignment correction like the body and camera and leave it independent.

So:
1 - Correct the current momentum GO alignment
2 - accumulate force in global space
3 - convert the global force to local and projecting it to tangent plane
4 - resolve the new momentum direction and strength
5 - apply the new momentum
6 - ...
7 - PROFIT!

Now let make it a reality
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic