BGE: Add option to return UV coordinates aofthe hit point to KX_GameObject::rayCast(). Details in PyDoc.

This commit is contained in:
Benoit Bolsee 2009-12-04 11:27:40 +00:00
parent 1dcca75e04
commit 0b6873a776
10 changed files with 250 additions and 67 deletions

@ -828,7 +828,8 @@ btSoftBody* btSoftBodyHelpers::CreateFromTriMesh(btSoftBodyWorldInfo& worldInfo
#undef IDX
psb->appendFace(idx[0],idx[1],idx[2]);
}
psb->randomizeConstraints();
// don't randomize now, let's give a chance to the application to set face data
//psb->randomizeConstraints();
return(psb);
}

@ -2606,8 +2606,8 @@ static PyObject *none_tuple_4()
}
KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
"rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) of contact point with object within dist that matches prop.\n"
" If no hit, return (None,None,None) or (None,None,None,None).\n"
"rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n"
" If no hit, return (None,None,None) or (None,None,None,None) or (None,None,None,None,None).\n"
" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n"
" from = 3-tuple or object reference for origin of ray (if object, use center of object)\n"
" Can be None or omitted => start from self object center\n"
@ -2617,6 +2617,8 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
" xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n"
" poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n"
" which can be None if hit object has no mesh or if there is no hit\n"
" 2=>return value is a 5-tuple, the 4th element is the KX_PolyProxy object\n"
" and the 5th element is the vector of UV coordinates at the hit point of the None if there is no UV mapping\n"
" If 0 or omitted, return value is a 3-tuple\n"
"Note: The object on which you call this method matters: the ray will ignore it.\n"
" prop and xray option interact as follow:\n"
@ -2697,12 +2699,12 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
m_testPropName.SetLength(0);
m_xray = xray;
// to get the hit results
KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face);
KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face,(poly==2));
KX_RayCast::RayTest(pe, fromPoint, toPoint, callback);
if (m_pHitObject)
{
PyObject* returnValue = (poly) ? PyTuple_New(4) : PyTuple_New(3);
PyObject* returnValue = (poly==2) ? PyTuple_New(5) : (poly) ? PyTuple_New(4) : PyTuple_New(3);
if (returnValue) { // unlikely this would ever fail, if it does python sets an error
PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->GetProxy());
PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint));
@ -2715,11 +2717,25 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
RAS_Polygon* polygon = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon);
KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, polygon);
PyTuple_SET_ITEM(returnValue, 3, polyproxy->NewProxy(true));
if (poly == 2)
{
if (callback.m_hitUVOK)
PyTuple_SET_ITEM(returnValue, 4, PyObjectFrom(callback.m_hitUV));
else {
Py_INCREF(Py_None);
PyTuple_SET_ITEM(returnValue, 4, Py_None);
}
}
}
else
{
Py_INCREF(Py_None);
PyTuple_SET_ITEM(returnValue, 3, Py_None);
if (poly==2)
{
Py_INCREF(Py_None);
PyTuple_SET_ITEM(returnValue, 4, Py_None);
}
}
}
}

@ -40,8 +40,8 @@
#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)
KX_RayCast::KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal, bool faceUV)
:PHY_IRayCastFilterCallback(dynamic_cast<PHY_IPhysicsController*>(ignoreController), faceNormal, faceUV)
{
}
@ -50,6 +50,8 @@ 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_hitUVOK = result->m_hitUVOK;
m_hitUV.setValue((const float*)result->m_hitUV);
m_hitMesh = result->m_meshObject;
m_hitPolygon = result->m_polygon;
}

@ -32,6 +32,7 @@
#include "PHY_IPhysicsEnvironment.h"
#include "PHY_IPhysicsController.h"
#include "MT_Vector2.h"
#include "MT_Point3.h"
#include "MT_Vector3.h"
@ -59,8 +60,10 @@ public:
MT_Vector3 m_hitNormal;
const RAS_MeshObject* m_hitMesh;
int m_hitPolygon;
int m_hitUVOK; // !=0 if UV coordinate in m_hitUV is valid
MT_Vector2 m_hitUV;
KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal);
KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal, bool faceUV);
virtual ~KX_RayCast() {}
/**
@ -102,8 +105,8 @@ template<class T> class KX_RayCast::Callback : public KX_RayCast
T *self;
void *data;
public:
Callback(T *_self, KX_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false)
: KX_RayCast(controller, faceNormal),
Callback(T *_self, KX_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false, bool faceUV=false)
: KX_RayCast(controller, faceNormal, faceUV),
self(_self),
data(_data)
{

@ -214,6 +214,7 @@ bool CcdPhysicsController::CreateSoftbody()
}
} else
{
int numtris = 0;
if (m_cci.m_collisionShape->getShapeType() ==SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE)
{
btScaledBvhTriangleMeshShape* scaledtrimeshshape = (btScaledBvhTriangleMeshShape*) m_cci.m_collisionShape;
@ -228,7 +229,6 @@ bool CcdPhysicsController::CreateSoftbody()
int vertexstride;
unsigned char* indexbase;
int indexstride;
int numtris;
PHY_ScalarType indexType;
trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType);
@ -246,14 +246,21 @@ bool CcdPhysicsController::CreateSoftbody()
int vertexstride;
unsigned char* indexbase;
int indexstride;
int numtris;
PHY_ScalarType indexType;
trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType);
psb = btSoftBodyHelpers::CreateFromTriMesh(worldInfo,(const btScalar*)vertexBase,(const int*)indexbase,numtris);
}
}
// store face tag so that we can find our original face when doing ray casting
btSoftBody::Face* ft;
int i;
for (i=0, ft=&psb->m_faces[0]; i<numtris; ++i, ++ft)
{
// Hack!! use m_tag to store the face number, normally it is a pointer
// add 1 to make sure it is never 0
ft->m_tag = (void*)((uintptr_t)(i+1));
}
}
if (m_cci.m_margin > 0.f)
{
@ -1402,6 +1409,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
m_vertexArray.clear();
m_polygonIndexArray.clear();
m_triFaceArray.clear();
m_triFaceUVcoArray.clear();
return false;
}
@ -1415,6 +1423,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
numpolys = dm->getNumFaces(dm);
numverts = dm->getNumVerts(dm);
int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX);
MTFace *tface = (MTFace *)dm->getFaceDataArray(dm, CD_MTFACE);
m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH;
@ -1515,14 +1524,23 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
m_vertexArray.resize(tot_bt_verts*3);
m_polygonIndexArray.resize(tot_bt_tris);
m_triFaceArray.resize(tot_bt_tris*3);
btScalar *bt= &m_vertexArray[0];
int *poly_index_pt= &m_polygonIndexArray[0];
int *tri_pt= &m_triFaceArray[0];
UVco *uv_pt = NULL;
if (tface)
{
m_triFaceUVcoArray.resize(tot_bt_tris*3);
uv_pt = &m_triFaceUVcoArray[0];
}
else
m_triFaceUVcoArray.clear();
for (int p2=0; p2<numpolys; p2++)
{
MFace* mf = &mface[p2];
MTFace* tf = (tface) ? &tface[p2] : NULL;
RAS_Polygon* poly= meshobj->GetPolygon(index[p2]);
// only add polygons that have the collisionflag set
@ -1537,6 +1555,16 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
tri_pt[1]= vert_remap_array[mf->v2];
tri_pt[2]= vert_remap_array[mf->v3];
tri_pt= tri_pt+3;
if (tf)
{
uv_pt[0].uv[0] = tf->uv[0][0];
uv_pt[0].uv[1] = tf->uv[0][1];
uv_pt[1].uv[0] = tf->uv[1][0];
uv_pt[1].uv[1] = tf->uv[1][1];
uv_pt[2].uv[0] = tf->uv[2][0];
uv_pt[2].uv[1] = tf->uv[2][1];
uv_pt += 3;
}
// m_polygonIndexArray
*poly_index_pt= index[p2];
@ -1570,6 +1598,16 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
tri_pt[1]= vert_remap_array[mf->v3];
tri_pt[2]= vert_remap_array[mf->v4];
tri_pt= tri_pt+3;
if (tf)
{
uv_pt[0].uv[0] = tf->uv[0][0];
uv_pt[0].uv[1] = tf->uv[0][1];
uv_pt[1].uv[0] = tf->uv[2][0];
uv_pt[1].uv[1] = tf->uv[2][1];
uv_pt[2].uv[0] = tf->uv[3][0];
uv_pt[2].uv[1] = tf->uv[3][1];
uv_pt += 3;
}
// m_polygonIndexArray
*poly_index_pt= index[p2];
@ -1728,10 +1766,12 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
m_triFaceArray.resize(tot_bt_tris*3);
int *tri_pt= &m_triFaceArray[0];
m_triFaceUVcoArray.resize(tot_bt_tris*3);
UVco *uv_pt= &m_triFaceUVcoArray[0];
m_polygonIndexArray.resize(tot_bt_tris);
int *poly_index_pt= &m_polygonIndexArray[0];
for(mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++)
{
if(tf->mode & TF_DYNAMIC)
@ -1760,6 +1800,9 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
vert_tag_array[v_orig]= false;
}
*tri_pt++ = vert_remap_array[v_orig];
uv_pt->uv[0] = tf->uv[*fv_pt][0];
uv_pt->uv[1] = tf->uv[*fv_pt][1];
uv_pt++;
}
}
}
@ -1782,6 +1825,8 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
m_polygonIndexArray.resize(tot_bt_tris);
int *poly_index_pt= &m_polygonIndexArray[0];
m_triFaceUVcoArray.clear();
for(mv= mvert, i=0; i < numverts; mv++, i++) {
*bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2];
}

@ -52,12 +52,16 @@ class btCollisionShape;
#define CCD_BSB_COL_VF_SS 16 /* Vertex/Face based soft vs soft */
// Shape contructor
// It contains all the information needed to create a simple bullet shape at runtime
class CcdShapeConstructionInfo
{
public:
struct UVco
{
float uv[2];
};
static CcdShapeConstructionInfo* FindMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope, bool gimpact);
CcdShapeConstructionInfo() :
@ -103,7 +107,7 @@ public:
btTriangleMeshShape* GetMeshShape(void)
{
return m_unscaledShape;
return (m_unscaledShape);
}
CcdShapeConstructionInfo* GetChildShape(int i)
{
@ -174,6 +178,9 @@ public:
std::vector<int> m_triFaceArray; // Contains an array of triplets of face indicies
// quads turn into 2 tris
std::vector<UVco> m_triFaceUVcoArray; // Contains an array of pair of UV coordinate for each vertex of faces
// quads turn into 2 tris
void setVertexWeldingThreshold1(float threshold)
{
m_weldingThreshold1 = threshold*threshold;

@ -974,6 +974,7 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul
const btCollisionShape* m_hitTriangleShape;
int m_hitTriangleIndex;
FilterClosestRayResultCallback (PHY_IRayCastFilterCallback& phyRayFilter,const btVector3& rayFrom,const btVector3& rayTo)
: btCollisionWorld::ClosestRayResultCallback(rayFrom,rayTo),
m_phyRayFilter(phyRayFilter),
@ -1017,6 +1018,56 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul
};
static bool GetHitTriangle(btCollisionShape* shape, CcdShapeConstructionInfo* shapeInfo, int hitTriangleIndex, btVector3 triangle[])
{
// this code is copied from Bullet
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
btStridingMeshInterface* meshInterface = NULL;
btTriangleMeshShape* triangleShape = shapeInfo->GetMeshShape();
if (triangleShape)
meshInterface = triangleShape->getMeshInterface();
else
{
// other possibility is gImpact
if (shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE)
meshInterface = (static_cast<btGImpactMeshShape*>(shape))->getMeshInterface();
}
if (!meshInterface)
return false;
meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
0);
unsigned int* gfxbase = (unsigned int*)(indexbase+hitTriangleIndex*indexstride);
const btVector3& meshScaling = shape->getLocalScaling();
for (int j=2;j>=0;j--)
{
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j];
btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride);
triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
}
meshInterface->unLockReadOnlyVertexBase(0);
return true;
}
PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)
{
btVector3 rayFrom(fromX,fromY,fromZ);
@ -1069,64 +1120,98 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallbac
if (shape == rayCallback.m_hitTriangleShape &&
rayCallback.m_hitTriangleIndex < shapeInfo->m_polygonIndexArray.size())
{
result.m_meshObject = shapeInfo->GetMesh();
// note for softbody: this assumes that the softbody shape uses the same triangle numbering
// than the triangle mesh shape that was used to build it
result.m_polygon = shapeInfo->m_polygonIndexArray.at(rayCallback.m_hitTriangleIndex);
// save original collision shape triangle for soft body
int hitTriangleIndex = rayCallback.m_hitTriangleIndex;
result.m_meshObject = shapeInfo->GetMesh();
if (shape->isSoftBody())
{
// soft body using different face numbering because of randomization
// hopefully we have stored the original face number in m_tag
btSoftBody* softBody = static_cast<btSoftBody*>(rayCallback.m_collisionObject);
if (softBody->m_faces[hitTriangleIndex].m_tag != 0)
{
rayCallback.m_hitTriangleIndex = (int)((uintptr_t)(softBody->m_faces[hitTriangleIndex].m_tag)-1);
}
}
// retrieve the original mesh polygon (in case of quad->tri conversion)
result.m_polygon = shapeInfo->m_polygonIndexArray.at(rayCallback.m_hitTriangleIndex);
// hit triangle in world coordinate, for face normal and UV coordinate
btVector3 triangle[3];
bool triangleOK = false;
if (filterCallback.m_faceUV && (3*rayCallback.m_hitTriangleIndex) < shapeInfo->m_triFaceUVcoArray.size())
{
// interpolate the UV coordinate of the hit point
CcdShapeConstructionInfo::UVco* uvCo = &shapeInfo->m_triFaceUVcoArray[3*rayCallback.m_hitTriangleIndex];
// 1. get the 3 coordinate of the triangle in world space
btVector3 v1, v2, v3;
if (shape->isSoftBody())
{
// soft body give points directly in world coordinate
btSoftBody* softBody = static_cast<btSoftBody*>(rayCallback.m_collisionObject);
v1 = softBody->m_faces[hitTriangleIndex].m_n[0]->m_x;
v2 = softBody->m_faces[hitTriangleIndex].m_n[1]->m_x;
v3 = softBody->m_faces[hitTriangleIndex].m_n[2]->m_x;
} else
{
// for rigid body we must apply the world transform
triangleOK = GetHitTriangle(shape, shapeInfo, hitTriangleIndex, triangle);
if (!triangleOK)
// if we cannot get the triangle, no use to continue
goto SKIP_UV_NORMAL;
v1 = rayCallback.m_collisionObject->getWorldTransform()(triangle[0]);
v2 = rayCallback.m_collisionObject->getWorldTransform()(triangle[1]);
v3 = rayCallback.m_collisionObject->getWorldTransform()(triangle[2]);
}
// 2. compute barycentric coordinate of the hit point
btVector3 v = v2-v1;
btVector3 w = v3-v1;
btVector3 u = v.cross(w);
btScalar A = u.length();
v = v2-rayCallback.m_hitPointWorld;
w = v3-rayCallback.m_hitPointWorld;
u = v.cross(w);
btScalar A1 = u.length();
v = rayCallback.m_hitPointWorld-v1;
w = v3-v1;
u = v.cross(w);
btScalar A2 = u.length();
btVector3 baryCo;
baryCo.setX(A1/A);
baryCo.setY(A2/A);
baryCo.setZ(1.0f-baryCo.getX()-baryCo.getY());
// 3. compute UV coordinate
result.m_hitUV[0] = baryCo.getX()*uvCo[0].uv[0] + baryCo.getY()*uvCo[1].uv[0] + baryCo.getZ()*uvCo[2].uv[0];
result.m_hitUV[1] = baryCo.getX()*uvCo[0].uv[1] + baryCo.getY()*uvCo[1].uv[1] + baryCo.getZ()*uvCo[2].uv[1];
result.m_hitUVOK = 1;
}
// Bullet returns the normal from "outside".
// If the user requests the real normal, compute it now
if (filterCallback.m_faceNormal)
{
// mesh shapes are shared and stored in the shapeInfo
btTriangleMeshShape* triangleShape = shapeInfo->GetMeshShape();
if (shape->isSoftBody())
{
// we can get the real normal directly from the body
btSoftBody* softBody = static_cast<btSoftBody*>(rayCallback.m_collisionObject);
rayCallback.m_hitNormalWorld = softBody->m_faces[rayCallback.m_hitTriangleIndex].m_normal;
} else if (triangleShape)
rayCallback.m_hitNormalWorld = softBody->m_faces[hitTriangleIndex].m_normal;
} else
{
// this code is copied from Bullet
btVector3 triangle[3];
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
btStridingMeshInterface* meshInterface = triangleShape->getMeshInterface();
meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
0);
unsigned int* gfxbase = (unsigned int*)(indexbase+rayCallback.m_hitTriangleIndex*indexstride);
const btVector3& meshScaling = shape->getLocalScaling();
for (int j=2;j>=0;j--)
if (!triangleOK)
triangleOK = GetHitTriangle(shape, shapeInfo, hitTriangleIndex, triangle);
if (triangleOK)
{
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j];
btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride);
triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
btVector3 triangleNormal;
triangleNormal = (triangle[1]-triangle[0]).cross(triangle[2]-triangle[0]);
rayCallback.m_hitNormalWorld = rayCallback.m_collisionObject->getWorldTransform().getBasis()*triangleNormal;
}
meshInterface->unLockReadOnlyVertexBase(0);
btVector3 triangleNormal;
triangleNormal = (triangle[1]-triangle[0]).cross(triangle[2]-triangle[0]);
rayCallback.m_hitNormalWorld = rayCallback.m_collisionObject->getWorldTransform().getBasis()*triangleNormal;
}
}
SKIP_UV_NORMAL:
;
}
}
}

@ -22,6 +22,20 @@ subject to the following restrictions:
struct KX_ClientObjectInfo;
class PHY_Shape;
struct PHY__Vector2
{
float m_vec[2];
operator const float* () const
{
return &m_vec[0];
}
operator float* ()
{
return &m_vec[0];
}
};
struct PHY__Vector3
{
float m_vec[4];

@ -52,6 +52,8 @@ struct PHY_RayCastResult
const RAS_MeshObject* m_meshObject; // !=NULL for mesh object (only for Bullet controllers)
int m_polygon; // index of the polygon hit by the ray,
// only if m_meshObject != NULL
int m_hitUVOK; // !=0 if UV coordinate in m_hitUV is valid
PHY__Vector2 m_hitUV; // UV coordinates of hit point
};
/**
@ -64,6 +66,7 @@ class PHY_IRayCastFilterCallback
public:
PHY_IPhysicsController* m_ignoreController;
bool m_faceNormal;
bool m_faceUV;
virtual ~PHY_IRayCastFilterCallback()
{
@ -76,9 +79,10 @@ public:
virtual void reportHit(PHY_RayCastResult* result) = 0;
PHY_IRayCastFilterCallback(PHY_IPhysicsController* ignoreController, bool faceNormal=false)
PHY_IRayCastFilterCallback(PHY_IPhysicsController* ignoreController, bool faceNormal=false, bool faceUV=false)
:m_ignoreController(ignoreController),
m_faceNormal(faceNormal)
m_faceNormal(faceNormal),
m_faceUV(faceUV)
{
}

@ -1958,6 +1958,7 @@ class KX_GameObject(SCA_IObject):
Look from a point/object to another point/object and find first object hit within dist that matches prop.
if poly is 0, 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 L{KX_PolyProxy} as 4th element.
if poly is 2, returns a 5-tuple with in addition a 2D vector with the UV mapping of the hit point as 5th element.
Ex::
# shoot along the axis gun-gunAim (gunAim should be collision-free)
@ -1996,13 +1997,18 @@ class KX_GameObject(SCA_IObject):
@type face: int
@param xray: X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object
@type xray: int
@param poly: polygon option: 1=>return value is a 4-tuple and the 4th element is a L{KX_PolyProxy}
@param poly: polygon option: 0,1 or 2 to return a 3-, 4- or 5-tuple with information on the face hit
0 or omitted=> return value is a 3-tuple (object, hitpoint, hitnormal) or (None,None,None) if no hit
1=>return value is a 4-tuple and the 4th element is a L{KX_PolyProxy} or None if no hit or the object doesn't use a mesh collision shape.
2=>return value is a 5-tuple and the 5th element is a 2-tuple (u,v) with the UV mapping of the hit point or None if no hit, or the object doesn't use a mesh collision shape, or doesn't have a UV mapping.
@type poly: int
@rtype: 3-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz))
or 4-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz), L{KX_PolyProxy})
@return: (object,hitpoint,hitnormal) or (object,hitpoint,hitnormal,polygon)
If no hit, returns (None,None,None) or (None,None,None,None)
If the object hit is not a static mesh, polygon is None
or 5-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz), L{KX_PolyProxy}, 2-tuple (u,v))
@return: (object,hitpoint,hitnormal) or (object,hitpoint,hitnormal,polygon) or (object,hitpoint,hitnormal,polygon,hituv)
object, hitpoint and hitnormal are None if no hit.
polygon is valid only if the object is valid and is a static object, a dynamic object using mesh collision shape or a soft body object, otherwise it is None
hituv is valid only if polygon is valid and the object has a UV mapping, otherwise it is None
"""
def setCollisionMargin(margin):
"""