- Home /
Rotating an object toward target AND with terrain?
Hi everyone, I feel like I've just been looking at this too long and haven't come up with the solution but I don't think the question is that bad. I've seen questions about rotating an object toward a target (so be facing the correct direction of where it's walking), and others about rotating an object to the normals of a terrain. I'm trying to make an object slowly look at a target while also having its rotation follow the terrain. Anyone have hints about what I should be doing in the commented line to make this work?
I've tried some basic adding and multiplying of the lookRotation/groundRotation variables but it seems to be super wonky so I know I'm missing something silly.
//some code figuring out how char controller should move is above here updates a "moveDirection" variable
RaycastHit hit;
Physics.Raycast(transform.position, -Vector3.up, out hit);
_direction = (target.position - transform.position).normalized;
_direction+=new Vector3(hit.normal.x, 0, hit.normal.z);
_lookRotation = Quaternion.LookRotation(_direction*-1);
Quaternion groundRotation = Quaternion.FromToRotation (Vector3.up, hit.normal);
//do something with _lookRotation and groundRotation
transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime * speed);
//after being rotated, the char controller is then moved by "moveDirection"
If more code is needed for contextual purposes, let me know and I'll provide. Thanks so much for your help!
Answer by robertbu · Oct 25, 2014 at 04:49 PM
If I understand your question correctly, the problem can be split into two parts. Aligning with the normal of the surface, and given some alignment with the ground, point in the direction of the target by rotating on the local 'y' axis. In essence you have a tank with a turret where the gun on the turret cannot be raised or lowered. So here is a bit of untested code to solve that problem:
Quaternion qTo = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
transform.rotation = Quaternion.Slerp (transform.rotation, qTo, alignmentSpeed * Time.deltaTime);
Vector3 targetPos = ProjectPointOnPlane(transform.up, transform.position, target.position);
qTo = Quaternion.LookRotation(targetPos - transform.position, transform.up);
transform.rotation = Quaternion.Slerp (transform.rotation, qTo, rotationSpeed * Time.deltaTime);
Vector3 ProjectPointOnPlane(Vector3 planeNormal, Vector3 planePoint, Vector3 point) {
planeNormal.Normalize();
var distance = -Vector3.Dot(planeNormal, (point - planePoint));
return point + planeNormal * distance;
}
The code inside the dashes goes in your Update() or coroutine. 'alignmentSpeed' and 'rotationSpeed' are variables you define. Start with a value of 3.5f for each.
Hi @robertu,
This is exactly what I had in $$anonymous$$d in terms of functionality. I had a few questions and comments.
Comments
I was able to easily export it into my game, everything worked fine. The only change I made to make the objects face frontward to the target ins$$anonymous$$d of backward was:
qTo = Quaternion.LookRotation((targetPos - transform.position)*-1, transform.up);
//the " (...)*-1 " is what I added
You've got some rad skills to just freecode that ha ha. Regardless of my comically $$anonymous$$or change, I'm marking this as solved. Thanks again!
Question
Is it possible to condense the code into one influence on rotation? If not, that's fine. I was just curious. I figure it might be better in the long run to influence the transform's rotation just once ins$$anonymous$$d of twice per frame (lines 2 and 5 of your Update() code). I was trying to brainstorm ways to do it. $$anonymous$$y initial idea is to just store another variable, but I was wondering if you had any thoughts on the matter.
It is possible to avoid two assignments to transform.rotation, but I'm not sure it is worth it. The problem is that you need the up vector from the terrain alignment step before you can do the rotation step. The rotation step depends on knowing the axis of rotation as well as the normal for the plane used in ProjectPointOnPlane(). This can be done by independently rotating an transform.up and using the result as the vector and then combining the two rotations when assigning to transform.rotation.
Great! This really helped me out. Less the Slerp transitions, I needed exactly what your solution gave. Thanks a lot @robertbu
Your answer
![](https://koobas.hobune.stream/wayback/20220613165926im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Is there a better way to tilt terrain at runtime? 1 Answer
Quaternions- how to leave out Y rotations... 1 Answer
Camera rotation around player while following. 6 Answers
How do I transfer the image a camera takes in to a box or plane?/create a portal 1 Answer
Rotating a turret body and head 1 Answer