blender/source/gameengine/Ketsji/KX_RayCast.cpp
Benoit Bolsee becd467be8 BGE patch: KX_GameObject::rayCast() improvements to have X-Ray option, return true face normal and hit polygon information.
rayCast(to,from,dist,prop,face,xray,poly):

The face paremeter determines the orientation of the normal: 
  0 or omitted => hit normal is always oriented towards the ray origin (as if you casted the ray from outside)
  1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect)
The ray has X-Ray capability if xray parameter is 1, otherwise the first object hit (other than self object) stops the ray.
The prop and xray parameters interact as follow:
    prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray.
    prop off, xray on : idem.
    prop on,  xray off: return closest hit if it matches prop, no hit otherwise.
    prop on,  xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray.
if poly is 0 or omitted, returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit.
if poly is 1, returns a 4-tuple with in addition a KX_PolyProxy as 4th element.

The KX_PolyProxy object holds information on the polygon hit by the ray: the index of the vertex forming the poylgon, material, etc.

Attributes (read-only):
 matname: The name of polygon material, empty if no material.
 material: The material of the polygon
 texture: The texture name of the polygon.
 matid: The material index of the polygon, use this to retrieve vertex proxy from mesh proxy
 v1: vertex index of the first vertex of the polygon, use this to retrieve vertex proxy from mesh proxy
 v2: vertex index of the second vertex of the polygon, use this to retrieve vertex proxy from mesh proxy
 v3: vertex index of the third vertex of the polygon, use this to retrieve vertex proxy from mesh proxy
 v4: vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex
     use this to retrieve vertex proxy from mesh proxy
 visible: visible state of the polygon: 1=visible, 0=invisible
 collide: collide state of the polygon: 1=receives collision, 0=collision free.
Methods:
 getMaterialName(): Returns the polygon material name with MA prefix
 getMaterial(): Returns the polygon material
 getTextureName(): Returns the polygon texture name
 getMaterialIndex(): Returns the material bucket index of the polygon. 
 getNumVertex(): Returns the number of vertex of the polygon.
 isVisible(): Returns whether the polygon is visible or not
 isCollider(): Returns whether the polygon is receives collision or not
 getVertexIndex(vertex): Returns the mesh vertex index of a polygon vertex
 getMesh(): Returns a mesh proxy

New methods of KX_MeshProxy have been implemented to retrieve KX_PolyProxy objects:
 getNumPolygons(): Returns the number of polygon in the mesh.
 getPolygon(index): Gets the specified polygon from the mesh.

More details in PyDoc.
2008-08-27 19:34:19 +00:00

115 lines
3.8 KiB
C++

/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
* KX_MouseFocusSensor determines mouse in/out/over events.
*/
#include <stdlib.h>
#include <stdio.h>
#include "KX_RayCast.h"
#include "MT_Point3.h"
#include "MT_Vector3.h"
#include "KX_IPhysicsController.h"
#include "PHY_IPhysicsEnvironment.h"
#include "PHY_IPhysicsController.h"
KX_RayCast::KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal)
:PHY_IRayCastFilterCallback(dynamic_cast<PHY_IPhysicsController*>(ignoreController), faceNormal)
{
}
void KX_RayCast::reportHit(PHY_RayCastResult* result)
{
m_hitFound = true;
m_hitPoint.setValue((const float*)result->m_hitPoint);
m_hitNormal.setValue((const float*)result->m_hitNormal);
m_hitMesh = result->m_meshObject;
m_hitPolygon = result->m_polygon;
}
bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback)
{
// Loops over all physics objects between frompoint and topoint,
// calling callback.RayHit for each one.
//
// callback.RayHit should return true to stop looking, or false to continue.
//
// returns true if an object was found, false if not.
MT_Point3 frompoint(_frompoint);
const MT_Vector3 todir( (topoint - frompoint).safe_normalized() );
MT_Point3 prevpoint(_frompoint+todir*(-1.f));
PHY_IPhysicsController* hit_controller;
while((hit_controller = physics_environment->rayTest(callback,
frompoint.x(),frompoint.y(),frompoint.z(),
topoint.x(),topoint.y(),topoint.z())) != NULL)
{
KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo());
if (!info)
{
printf("no info!\n");
MT_assert(info && "Physics controller with no client object info");
break;
}
// The biggest danger to to endless loop, prevent this by checking that the
// hit point always progresses along the ray direction..
prevpoint -= callback.m_hitPoint;
if (prevpoint.length2() < MT_EPSILON)
break;
if (callback.RayHit(info))
// caller may decide to stop the loop and still cancel the hit
return callback.m_hitFound;
// Skip past the object and keep tracing.
// Note that retrieving in a single shot multiple hit points would be possible
// but it would require some change in Bullet.
prevpoint = callback.m_hitPoint;
/* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */
MT_Scalar marg = 0.001 + hit_controller->GetMargin();
marg *= 2.f;
/* Calculate the other side of this object */
MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal));
if (h <= 0.01)
// the normal is almost orthogonal to the ray direction, cannot compute the other side
break;
marg /= h;
frompoint = callback.m_hitPoint + marg * todir;
// verify that we are not passed the to point
if ((topoint - frompoint).dot(todir) < 0.f)
break;
}
return false;
}