Archive 17/01/2023.

How to direct a character parallel to the ground?

1vanK

I try

if (RaycastDown(hitPos, hitDrawable, normal))
{
    node.rotation = Quaternion(normal.x, node.rotation.yaw, normal.z);
}

but it does not work. Please help me :slight_smile:

Source: github.com/1vanK/Habr/blob/mast … oScript.as

1vanK

Do I understand correctly that normal is not calculated really ?

void Drawable::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
{
    float distance = query.ray_.HitDistance(GetWorldBoundingBox());
    if (distance < query.maxDistance_)
    {
        RayQueryResult result;
        result.position_ = query.ray_.origin_ + distance * query.ray_.direction_;
        result.normal_ = -query.ray_.direction_;  // <------------------------------------------------------------
        result.distance_ = distance;
        result.drawable_ = this;
        result.node_ = GetNode();
        result.subObject_ = M_MAX_UNSIGNED;
        results.Push(result);
    }
}
cadaver

That is in the base class, which doesn’t actually understand the geometry. E.g. StaticModel raycast should return the normal correctly.

rasteron

If I’m not mistaken, there’s already a snippet from Vehicle or Water Demo which demonstrates actual placement (or something similar) of objects (mushrooms) parallel from Terrain. Maybe you could derive something from that example…

1vanK

Oh, thanks. It works

if (RaycastDown(hitPos, hitDrawable, normal))
{
    Quaternion grndTilt = Quaternion(Vector3(0.0f, 1.0f, 0.0f), normal);
    node.rotation = grndTilt * Quaternion(0.0f, node.rotation.yaw, 0.0f);
}
1vanK

Another method from answers.unity3d.com/questions/16 … ormal.html
It gives smoother results.

        Vector3 corner1 = node.position + Vector3(-1.0f, 0.0f, -1.0f);
        Vector3 corner2 = node.position + Vector3(1.0f, 0.0f, -1.0f);
        Vector3 corner3 = node.position + Vector3(1.0f, 0.0f, 1.0f);
        Vector3 corner4 = node.position + Vector3(-1.0f, 0.0f, 1.0f);
        
        Vector3 hit1, hit2, hit3, hit4;
        
        bool b1 = RaycastDown(corner1, hit1, hitDrawable);
        bool b2 = RaycastDown(corner2, hit2, hitDrawable);
        bool b3 = RaycastDown(corner3, hit3, hitDrawable);
        bool b4 = RaycastDown(corner4, hit4, hitDrawable);
        
        if (!b1) log.Warning("b1");
        if (!b2) log.Warning("b2");
        if (!b3) log.Warning("b3");
        if (!b4) log.Warning("b4"); // fix it case

       
        Vector3 normal = hit1.CrossProduct(hit2) + hit2.CrossProduct(hit3) +
                         hit3.CrossProduct(hit4) + hit4.CrossProduct(hit1);
        normal.Normalize();
        normal = -normal;

        Quaternion grndTilt = Quaternion(Vector3(0.0f, 1.0f, 0.0f), normal);
        node.rotation = grndTilt * Quaternion(0.0f, node.rotation.yaw, 0.0f);

...

    bool RaycastDown(Vector3 from, Vector3& hitPos, Drawable@& hitDrawable)
    {
        hitDrawable = null;
        Ray ray(from + Vector3(0.0f, 1.0f, 0.0f), Vector3(0.0f, -1.0f, 0.0f));
        RayQueryResult result = scene.octree.RaycastSingle(ray, RAY_TRIANGLE, 1000, DRAWABLE_GEOMETRY, 1);

        if (result.drawable is null)
            return false;

        hitPos = result.position;
        hitDrawable = result.drawable;
        return true;
    }