BGE: Add option to return UV coordinates aofthe hit point to KX_GameObject::rayCast(). Details in PyDoc.
This commit is contained in:
parent
1dcca75e04
commit
0b6873a776
@ -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):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user