void GjkCollisionState::reset(const MatrixF& a2w, const MatrixF& b2w) { VectorF zero(0,0,0),sa,sb; a2w.mulP(a->support(zero),&sa); b2w.mulP(b->support(zero),&sb); v = sa - sb; dist = v.len(); }
void BoxConvex::emitEdge(S32 v1,S32 v2,const MatrixF& mat,ConvexFeature* cf) { S32 vc = cf->mVertexList.size(); cf->mVertexList.increment(2); Point3F *vp = cf->mVertexList.begin(); mat.mulP(getVertex(v1),&vp[vc]); mat.mulP(getVertex(v2),&vp[vc + 1]); cf->mEdgeList.increment(); ConvexFeature::Edge& edge = cf->mEdgeList.last(); edge.vertex[0] = vc; edge.vertex[1] = vc + 1; }
void GFXDrawUtil::_drawSolidCapsule( const GFXStateBlockDesc &desc, const Point3F ¢er, F32 radius, F32 height, const ColorI &color, const MatrixF *xfm ) { MatrixF mat; if ( xfm ) mat = *xfm; else mat = MatrixF::Identity; S32 numPoints = sizeof(circlePoints)/sizeof(Point2F); GFXVertexBufferHandle<GFXVertexPC> verts(mDevice, numPoints * 2 + 2, GFXBufferTypeVolatile); verts.lock(); for (S32 i=0; i<numPoints + 1; i++) { S32 imod = i % numPoints; verts[2 * i].point = Point3F( circlePoints[imod].x * radius, circlePoints[imod].y * radius, height ); verts[2 * i].color = color; verts[2 * i + 1].point = Point3F( circlePoints[imod].x * radius, circlePoints[imod].y * radius, -height ); verts[2 * i + 1].color = color; } S32 totalNumPnts = numPoints * 2 + 2; // Apply xfm if we were passed one. for ( U32 i = 0; i < totalNumPnts; i++ ) mat.mulP( verts[i].point ); // Apply position offset for ( U32 i = 0; i < totalNumPnts; i++ ) verts[i].point += center; verts.unlock(); mDevice->setStateBlockByDesc( desc ); mDevice->setVertexBuffer( verts ); mDevice->setupGenericShaders(); mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 * numPoints ); Point3F sphereCenter; MatrixF sphereMat; if ( xfm ) sphereMat = *xfm; else sphereMat = MatrixF::Identity; sphereCenter.set( 0, 0, 0.5f * height ); mat.mulV( sphereCenter ); sphereCenter += center; drawSphere( desc, radius, sphereCenter, color, true, false, &sphereMat ); sphereCenter.set( 0, 0, -0.5f * height ); mat.mulV( sphereCenter ); sphereCenter += center; drawSphere( desc, radius, sphereCenter, color, false, true, &sphereMat ); }
void BoxConvex::emitFace(S32 fi,const MatrixF& mat,ConvexFeature* cf) { Face& face = sFace[fi]; // Emit vertices S32 vc = cf->mVertexList.size(); cf->mVertexList.increment(4); Point3F *vp = cf->mVertexList.begin(); for (S32 v = 0; v < 4; v++) mat.mulP(getVertex(face.vertex[v]),&vp[vc + v]); // Emit edges cf->mEdgeList.increment(4); ConvexFeature::Edge* edge = cf->mEdgeList.end() - 4; for (S32 e = 0; e < 4; e++) { edge[e].vertex[0] = vc + e; edge[e].vertex[1] = vc + ((e + 1) & 3); } // Emit 2 triangle faces cf->mFaceList.increment(2); ConvexFeature::Face* ef = cf->mFaceList.end() - 2; mat.getColumn(face.axis,&ef->normal); if (face.flip) ef[0].normal.neg(); ef[1].normal = ef[0].normal; ef[1].vertex[0] = ef[0].vertex[0] = vc; ef[1].vertex[1] = ef[0].vertex[2] = vc + 2; ef[0].vertex[1] = vc + 1; ef[1].vertex[2] = vc + 3; }
void BtBody::applyImpulse( const Point3F &origin, const Point3F &force ) { AssertFatal( mActor, "BtBody::applyImpulse - The actor is null!" ); AssertFatal( isDynamic(), "BtBody::applyImpulse - This call is only for dynamics!" ); // Convert the world position to local MatrixF trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() ); trans.inverse(); Point3F localOrigin( origin ); trans.mulP( localOrigin ); if ( mCenterOfMass ) { Point3F relOrigin( localOrigin ); mCenterOfMass->mulP( relOrigin ); Point3F relForce( force ); mCenterOfMass->mulV( relForce ); mActor->applyImpulse( btCast<btVector3>( relForce ), btCast<btVector3>( relOrigin ) ); } else mActor->applyImpulse( btCast<btVector3>( force ), btCast<btVector3>( localOrigin ) ); if ( !mActor->isActive() ) mActor->activate(); }
//---------------------------------------------------------------------------- // Create ring //---------------------------------------------------------------------------- SplashRing Splash::createRing() { SplashRing ring; U32 numPoints = mDataBlock->numSegments + 1; Point3F ejectionAxis( 0.0, 0.0, 1.0 ); Point3F axisx; if (mFabs(ejectionAxis.z) < 0.999f) mCross(ejectionAxis, Point3F(0, 0, 1), &axisx); else mCross(ejectionAxis, Point3F(0, 1, 0), &axisx); axisx.normalize(); for( U32 i=0; i<numPoints; i++ ) { F32 t = F32(i) / F32(numPoints); AngAxisF thetaRot( axisx, mDataBlock->ejectionAngle * (M_PI / 180.0)); AngAxisF phiRot( ejectionAxis, t * (M_PI * 2.0)); Point3F pointAxis = ejectionAxis; MatrixF temp; thetaRot.setMatrix(&temp); temp.mulP(pointAxis); phiRot.setMatrix(&temp); temp.mulP(pointAxis); Point3F startOffset = axisx; temp.mulV( startOffset ); startOffset *= mDataBlock->startRadius; SplashRingPoint point; point.position = getPosition() + startOffset; point.velocity = pointAxis * mDataBlock->velocity; ring.points.push_back( point ); } ring.color = mDataBlock->colors[0]; ring.lifetime = mDataBlock->ringLifetime; ring.elapsedTime = 0.0; ring.v = mDataBlock->texFactor * mFmod( mElapsedTime, 1.0 ); return ring; }
bool GjkCollisionState::intersect(const MatrixF& a2w, const MatrixF& b2w) { num_iterations = 0; MatrixF w2a,w2b; w2a = a2w; w2b = b2w; w2a.inverse(); w2b.inverse(); reset(a2w,b2w); bits = 0; all_bits = 0; do { nextBit(); VectorF va,sa; w2a.mulV(-v,&va); p[last] = a->support(va); a2w.mulP(p[last],&sa); VectorF vb,sb; w2b.mulV(v,&vb); q[last] = b->support(vb); b2w.mulP(q[last],&sb); VectorF w = sa - sb; if (mDot(v,w) > 0) return false; if (degenerate(w)) { ++num_irregularities; return false; } y[last] = w; all_bits = bits | last_bit; ++num_iterations; if (!closest(v) || num_iterations > sIteration) { ++num_irregularities; return false; } } while (bits < 15 && v.lenSquared() > sEpsilon2); return true; }
void TerrainConvex::getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf) { U32 i; cf->material = 0; cf->object = mObject; // Plane is normal n + support point PlaneF plane; plane.set(support(n),n); S32 vertexCount = cf->mVertexList.size(); // Emit vertices on the plane S32* vertexListPointer; if (halfA) vertexListPointer = square ? sVertexList[(split45 << 1) | 1]: sVertexList[4]; else vertexListPointer = square ? sVertexList[(split45 << 1)] : sVertexList[4]; S32 pm = 0; S32 numVerts = *vertexListPointer; vertexListPointer += 1; for (i = 0; i < numVerts; i++) { Point3F& cp = point[vertexListPointer[i]]; cf->mVertexList.increment(); mat.mulP(cp,&cf->mVertexList.last()); pm |= 1 << vertexListPointer[i]; } // Emit Edges S32* ep = (square && halfA)? (split45 ? sEdgeList45A[pm]: sEdgeList135A[pm]): (split45 ? sEdgeList45[pm]: sEdgeList135[pm]); S32 numEdges = *ep; S32 edgeListStart = cf->mEdgeList.size(); cf->mEdgeList.increment(numEdges); ep += 1; for (i = 0; i < numEdges; i++) { cf->mEdgeList[edgeListStart + i].vertex[0] = vertexCount + ep[i * 2 + 0]; cf->mEdgeList[edgeListStart + i].vertex[1] = vertexCount + ep[i * 2 + 1]; } // Emit faces S32* fp = split45 ? sFaceList45[pm]: sFaceList135[pm]; S32 numFaces = *fp; fp += 1; S32 faceListStart = cf->mFaceList.size(); cf->mFaceList.increment(numFaces); for (i = 0; i < numFaces; i++) { cf->mFaceList[faceListStart + i].normal = normal[fp[i * 4 + 0]]; cf->mFaceList[faceListStart + i].vertex[0] = vertexCount + fp[i * 4 + 1]; cf->mFaceList[faceListStart + i].vertex[1] = vertexCount + fp[i * 4 + 2]; cf->mFaceList[faceListStart + i].vertex[2] = vertexCount + fp[i * 4 + 3]; } }
void GjkCollisionState::getCollisionInfo(const MatrixF& mat, Collision* info) { AssertFatal(false, "GjkCollisionState::getCollisionInfo() - There remain scaling problems here."); // This assumes that the shapes do not intersect Point3F pa,pb; if (bits) { getClosestPoints(pa,pb); mat.mulP(pa,&info->point); b->getTransform().mulP(pb,&pa); info->normal = info->point - pa; } else { mat.mulP(p[last],&info->point); info->normal = v; } info->normal.normalize(); info->object = b->getObject(); }
void ForestConvex::getFeatures( const MatrixF &mat, const VectorF &n, ConvexFeature *cf ) { cf->material = 0; cf->object = mObject; TSShapeInstance *si = mData->getShapeInstance(); TSShape::ConvexHullAccelerator* pAccel = si->getShape()->getAccelerator(mData->getCollisionDetails()[hullId]); AssertFatal(pAccel != NULL, "Error, no accel!"); F32 currMaxDP = mDot(pAccel->vertexList[0], n); U32 index = 0; U32 i; for (i = 1; i < pAccel->numVerts; i++) { F32 dp = mDot(pAccel->vertexList[i], n); if (dp > currMaxDP) { currMaxDP = dp; index = i; } } const U8* emitString = pAccel->emitStrings[index]; U32 currPos = 0; U32 numVerts = emitString[currPos++]; for (i = 0; i < numVerts; i++) { cf->mVertexList.increment(); U32 index = emitString[currPos++]; mat.mulP(pAccel->vertexList[index], &cf->mVertexList.last()); } U32 numEdges = emitString[currPos++]; for (i = 0; i < numEdges; i++) { U32 ev0 = emitString[currPos++]; U32 ev1 = emitString[currPos++]; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = ev0; cf->mEdgeList.last().vertex[1] = ev1; } U32 numFaces = emitString[currPos++]; for (i = 0; i < numFaces; i++) { cf->mFaceList.increment(); U32 plane = emitString[currPos++]; mat.mulV(pAccel->normalList[plane], &cf->mFaceList.last().normal); for (U32 j = 0; j < 3; j++) cf->mFaceList.last().vertex[j] = emitString[currPos++]; } }
//---------------------------------------------------------------------------- AwTextureTarget *AwShape::processAwesomiumHit (const Point3F &start, const Point3F &end) { if (!mTextureTarget) { return NULL; } Point3F localStart, localEnd; MatrixF mat = getTransform(); mat.scale (Point3F (getScale ())); mat.inverse (); mat.mulP (start, &localStart); mat.mulP (end, &localEnd); RayInfo info; info.generateTexCoord = true; if (!mShapeInstance || !mShapeInstance->castRayOpcode (0, localStart, localEnd, &info)) { return NULL; } if (info.texCoord.x != -1 && info.texCoord.y != -1 && info.material == mMatInstance) { Point2I pnt (info.texCoord.x * mTextureTarget->getResolution ().x, info.texCoord.y * mTextureTarget->getResolution ().y); AwManager::sCursor->setPosition (pnt); if (mIsMouseDown) { mTextureTarget->injectMouseDown (); } else { mTextureTarget->injectMouseUp (); } return mTextureTarget; } return NULL; }
MatrixF PlaneReflector::getFrustumClipProj( MatrixF &modelview ) { static MatrixF rotMat(EulerF( static_cast<F32>(M_PI / 2.f), 0.0, 0.0)); static MatrixF invRotMat(EulerF( -static_cast<F32>(M_PI / 2.f), 0.0, 0.0)); MatrixF revModelview = modelview; revModelview = rotMat * revModelview; // add rotation to modelview because it needs to be removed from projection // rotate clip plane into modelview space Point4F clipPlane; Point3F pnt = refplane * -(refplane.d + 0.0 ); Point3F norm = refplane; revModelview.mulP( pnt ); revModelview.mulV( norm ); norm.normalize(); clipPlane.set( norm.x, norm.y, norm.z, -mDot( pnt, norm ) ); // Manipulate projection matrix //------------------------------------------------------------------------ MatrixF proj = GFX->getProjectionMatrix(); proj.mul( invRotMat ); // reverse rotation imposed by Torque proj.transpose(); // switch to row-major order // Calculate the clip-space corner point opposite the clipping plane // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and // transform it into camera space by multiplying it // by the inverse of the projection matrix Vector4F q; q.x = sgn(clipPlane.x) / proj(0,0); q.y = sgn(clipPlane.y) / proj(1,1); q.z = -1.0F; q.w = ( 1.0F - proj(2,2) ) / proj(3,2); F32 a = 1.0 / (clipPlane.x * q.x + clipPlane.y * q.y + clipPlane.z * q.z + clipPlane.w * q.w); Vector4F c = clipPlane * a; // CodeReview [ags 1/23/08] Come up with a better way to deal with this. if(GFX->getAdapterType() == OpenGL) c.z += 1.0f; // Replace the third column of the projection matrix proj.setColumn( 2, c ); proj.transpose(); // convert back to column major order proj.mul( rotMat ); // restore Torque rotation return proj; }
void AppMesh::computeBounds(Box3F& bounds) { bounds = Box3F::Invalid; if ( isSkin() ) { // Need to skin the mesh before we can compute the bounds // Setup bone transforms Vector<MatrixF> boneTransforms; boneTransforms.setSize( nodeIndex.size() ); for (S32 iBone = 0; iBone < boneTransforms.size(); iBone++) { MatrixF nodeMat = bones[iBone]->getNodeTransform( TSShapeLoader::DefaultTime ); TSShapeLoader::zapScale(nodeMat); boneTransforms[iBone].mul( nodeMat, initialTransforms[iBone] ); } // Multiply verts by weighted bone transforms for (S32 iVert = 0; iVert < initialVerts.size(); iVert++) points[iVert].set( Point3F::Zero ); for (S32 iWeight = 0; iWeight < vertexIndex.size(); iWeight++) { const S32& vertIndex = vertexIndex[iWeight]; const MatrixF& deltaTransform = boneTransforms[ boneIndex[iWeight] ]; Point3F v; deltaTransform.mulP( initialVerts[vertIndex], &v ); v *= weight[iWeight]; points[vertIndex] += v; } // compute bounds for the skinned mesh for (S32 iVert = 0; iVert < initialVerts.size(); iVert++) bounds.extend( points[iVert] ); } else { MatrixF transform = getMeshTransform(TSShapeLoader::DefaultTime); TSShapeLoader::zapScale(transform); for (S32 iVert = 0; iVert < points.size(); iVert++) { Point3F p; transform.mulP(points[iVert], &p); bounds.extend(p); } } }
void OrientedBox3F::set( const MatrixF& transform, const Box3F& aabb ) { mCenter = aabb.getCenter(); transform.mulP( mCenter ); mAxes[ RightVector ] = transform.getRightVector(); mAxes[ ForwardVector ] = transform.getForwardVector(); mAxes[ UpVector ] = transform.getUpVector(); mHalfExtents[ 0 ] = aabb.len_x() / 2.f; mHalfExtents[ 1 ] = aabb.len_y() / 2.f; mHalfExtents[ 2 ] = aabb.len_z() / 2.f; _initPoints(); }
void BoxConvex::getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf) { cf->material = 0; cf->object = mObject; S32 v = 0; v += (n.x >= 0)? 1: 0; v += (n.y >= 0)? 2: 0; v += (n.z >= 0)? 4: 0; PlaneF plane; plane.set(getVertex(v),n); // Emit vertex and edge S32 mask = 0; Corner& corner = sCorner[v]; mask |= isOnPlane(getVertex(corner.a),plane)? 1: 0; mask |= isOnPlane(getVertex(corner.b),plane)? 2: 0; mask |= isOnPlane(getVertex(corner.c),plane)? 4: 0; switch(mask) { case 0: { cf->mVertexList.increment(); mat.mulP(getVertex(v),&cf->mVertexList.last()); break; } case 1: emitEdge(v,corner.a,mat,cf); break; case 2: emitEdge(v,corner.b,mat,cf); break; case 4: emitEdge(v,corner.c,mat,cf); break; case 1 | 2: emitFace(corner.ab,mat,cf); break; case 2 | 4: emitFace(corner.bc,mat,cf); break; case 1 | 4: emitFace(corner.ac,mat,cf); break; } }
bool TSMesh::getFeatures( S32 frame, const MatrixF& mat, const VectorF&, ConvexFeature* cf, U32& ) { S32 firstVert = vertsPerFrame * frame; S32 i; S32 base = cf->mVertexList.size(); for ( i = 0; i < vertsPerFrame; i++ ) { cf->mVertexList.increment(); mat.mulP( mVertexData[firstVert + i].vert(), &cf->mVertexList.last() ); } // add the polys... for ( i = 0; i < primitives.size(); i++ ) { TSDrawPrimitive & draw = primitives[i]; U32 start = draw.start; AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" ); // gonna depend on what kind of primitive it is... if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles) { for ( S32 j = 0; j < draw.numElements; j += 3 ) { PlaneF plane( cf->mVertexList[base + indices[start + j + 0]], cf->mVertexList[base + indices[start + j + 1]], cf->mVertexList[base + indices[start + j + 2]]); cf->mFaceList.increment(); cf->mFaceList.last().normal = plane; cf->mFaceList.last().vertex[0] = base + indices[start + j + 0]; cf->mFaceList.last().vertex[1] = base + indices[start + j + 1]; cf->mFaceList.last().vertex[2] = base + indices[start + j + 2]; for ( U32 l = 0; l < 3; l++ ) { U32 newEdge0, newEdge1; U32 zero = base + indices[start + j + l]; U32 one = base + indices[start + j + ((l+1)%3)]; newEdge0 = getMin( zero, one ); newEdge1 = getMax( zero, one ); bool found = false; for ( S32 k = 0; k < cf->mEdgeList.size(); k++
void ProcessedFFMaterial::_setSecondaryLightInfo(const MatrixF &_objTrans, LightInfo* light) { // set object transform MatrixF objTrans = _objTrans; objTrans.inverse(); // fill in secondary light //------------------------- GFXLightInfo xlatedLight; light->setGFXLight(&xlatedLight); Point3F lightPos = light->getPosition(); Point3F lightDir = light->getDirection(); objTrans.mulP(lightPos); objTrans.mulV(lightDir); xlatedLight.mPos = lightPos; xlatedLight.mDirection = lightDir; GFX->setLight(1, &xlatedLight); }
void ProcessedFFMaterial::_setPrimaryLightInfo(const MatrixF &_objTrans, LightInfo* light, U32 pass) { // Just in case GFX->setGlobalAmbientColor(ColorF(0.0f, 0.0f, 0.0f, 1.0f)); if ( light->getType() == LightInfo::Ambient ) { // Ambient light GFX->setGlobalAmbientColor( light->getAmbient() ); return; } GFX->setLight(0, NULL); GFX->setLight(1, NULL); // This is a quick hack that lets us use FF lights GFXLightMaterial lightMat; lightMat.ambient = ColorF(1.0f, 1.0f, 1.0f, 1.0f); lightMat.diffuse = ColorF(1.0f, 1.0f, 1.0f, 1.0f); lightMat.emissive = ColorF(0.0f, 0.0f, 0.0f, 0.0f); lightMat.specular = ColorF(0.0f, 0.0f, 0.0f, 0.0f); lightMat.shininess = 128.0f; GFX->setLightMaterial(lightMat); // set object transform MatrixF objTrans = _objTrans; objTrans.inverse(); // fill in primary light //------------------------- GFXLightInfo xlatedLight; light->setGFXLight(&xlatedLight); Point3F lightPos = light->getPosition(); Point3F lightDir = light->getDirection(); objTrans.mulP(lightPos); objTrans.mulV(lightDir); xlatedLight.mPos = lightPos; xlatedLight.mDirection = lightDir; GFX->setLight(0, &xlatedLight); }
void AITurretShape::_renderScanner( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) { GFXStateBlockDesc desc; desc.setBlend(false, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); desc.setZReadWrite(false,true); desc.fillMode = GFXFillWireframe; // Render the scan box GFX->getDrawUtil()->drawCube(desc, mTransformedScanBox.getExtents(), mTransformedScanBox.getCenter(), ColorI(255, 0, 0)); // Render a line from the scan node to the max scan distance MatrixF nodeMat; if (getNodeTransform(mDataBlock->scanNode, nodeMat)) { Point3F start; nodeMat.getColumn(3, &start); Point3F end(0.0f, mScanDistance, 0.0f); nodeMat.mulP(end); GFX->getDrawUtil()->drawLine(start, end, ColorI(255, 255, 0)); } }
void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState, const MatrixF &worldViewOnly ) { MaterialParameters *matParams = matInstance->getMaterialParameters(); // Set color in the right format, set alpha to the luminance value for the color. ColorF col = lightInfo->getColor(); // TODO: The specularity control of the light // is being scaled by the overall lumiance. // // Not sure if this may be the source of our // bad specularity results maybe? // const Point3F colorToLumiance( 0.3576f, 0.7152f, 0.1192f ); F32 lumiance = mDot(*((const Point3F *)&lightInfo->getColor()), colorToLumiance ); col.alpha *= lumiance; matParams->setSafe( lightColor, col ); matParams->setSafe( lightBrightness, lightInfo->getBrightness() ); switch( lightInfo->getType() ) { case LightInfo::Vector: { VectorF lightDir = lightInfo->getDirection(); worldViewOnly.mulV(lightDir); lightDir.normalize(); matParams->setSafe( lightDirection, lightDir ); // Set small number for alpha since it represents existing specular in // the vector light. This prevents a divide by zero. ColorF ambientColor = renderState->getAmbientLightColor(); ambientColor.alpha = 0.00001f; matParams->setSafe( lightAmbient, ambientColor ); // If no alt color is specified, set it to the average of // the ambient and main color to avoid artifacts. // // TODO: Trilight disabled until we properly implement it // in the light info! // //ColorF lightAlt = lightInfo->getAltColor(); ColorF lightAlt( ColorF::BLACK ); // = lightInfo->getAltColor(); if ( lightAlt.red == 0.0f && lightAlt.green == 0.0f && lightAlt.blue == 0.0f ) lightAlt = (lightInfo->getColor() + renderState->getAmbientLightColor()) / 2.0f; ColorF trilightColor = lightAlt; matParams->setSafe(lightTrilight, trilightColor); } break; case LightInfo::Spot: { const F32 outerCone = lightInfo->getOuterConeAngle(); const F32 innerCone = getMin( lightInfo->getInnerConeAngle(), outerCone ); const F32 outerCos = mCos( mDegToRad( outerCone / 2.0f ) ); const F32 innerCos = mCos( mDegToRad( innerCone / 2.0f ) ); Point4F spotParams( outerCos, innerCos - outerCos, mCos( mDegToRad( outerCone ) ), 0.0f ); matParams->setSafe( lightSpotParams, spotParams ); VectorF lightDir = lightInfo->getDirection(); worldViewOnly.mulV(lightDir); lightDir.normalize(); matParams->setSafe( lightDirection, lightDir ); } // Fall through case LightInfo::Point: { const F32 radius = lightInfo->getRange().x; matParams->setSafe( lightRange, radius ); Point3F lightPos; worldViewOnly.mulP(lightInfo->getPosition(), &lightPos); matParams->setSafe( lightPosition, lightPos ); // Get the attenuation falloff ratio and normalize it. Point3F attenRatio = lightInfo->getExtended<ShadowMapParams>()->attenuationRatio; F32 total = attenRatio.x + attenRatio.y + attenRatio.z; if ( total > 0.0f ) attenRatio /= total; Point2F attenParams( ( 1.0f / radius ) * attenRatio.y, ( 1.0f / ( radius * radius ) ) * attenRatio.z ); matParams->setSafe( lightAttenuation, attenParams ); break; } default: AssertFatal( false, "Bad light type!" ); break; } }
void FontRenderBatcher::render( F32 rot, const Point2F &offset ) { if( mLength == 0 ) return; GFX->setStateBlock(mFontSB); for(U32 i = 0; i < GFX->getNumSamplers(); i++) GFX->setTexture(i, NULL); MatrixF rotMatrix; bool doRotation = rot != 0.f; if(doRotation) rotMatrix.set( EulerF( 0.0, 0.0, mDegToRad( rot ) ) ); // Write verts out. U32 currentPt = 0; GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, mLength * 6, GFXBufferTypeVolatile); verts.lock(); for( S32 i = 0; i < mSheets.size(); i++ ) { // Do some early outs... if(!mSheets[i]) continue; if(!mSheets[i]->numChars) continue; mSheets[i]->startVertex = currentPt; const GFXTextureObject *tex = mFont->getTextureHandle(i); for( S32 j = 0; j < mSheets[i]->numChars; j++ ) { // Get some general info to proceed with... const CharMarker &m = mSheets[i]->charIndex[j]; const PlatformFont::CharInfo &ci = mFont->getCharInfo( m.c ); // Where are we drawing it? F32 drawY = offset.y + mFont->getBaseline() - ci.yOrigin * TEXT_MAG; F32 drawX = offset.x + m.x + ci.xOrigin; // Figure some values. const F32 texWidth = (F32)tex->getWidth(); const F32 texHeight = (F32)tex->getHeight(); const F32 texLeft = (F32)(ci.xOffset) / texWidth; const F32 texRight = (F32)(ci.xOffset + ci.width) / texWidth; const F32 texTop = (F32)(ci.yOffset) / texHeight; const F32 texBottom = (F32)(ci.yOffset + ci.height) / texHeight; const F32 fillConventionOffset = GFX->getFillConventionOffset(); const F32 screenLeft = drawX - fillConventionOffset; const F32 screenRight = drawX - fillConventionOffset + ci.width * TEXT_MAG; const F32 screenTop = drawY - fillConventionOffset; const F32 screenBottom = drawY - fillConventionOffset + ci.height * TEXT_MAG; // Build our vertices. We NEVER read back from the buffer, that's // incredibly slow, so for rotation do it into tmp. This code is // ugly as sin. Point3F tmp; tmp.set( screenLeft, screenTop, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texLeft, texTop ); currentPt++; tmp.set( screenLeft, screenBottom, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texLeft, texBottom ); currentPt++; tmp.set( screenRight, screenBottom, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texRight, texBottom ); currentPt++; tmp.set( screenRight, screenBottom, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texRight, texBottom ); currentPt++; tmp.set( screenRight, screenTop, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texRight, texTop ); currentPt++; tmp.set( screenLeft, screenTop, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texLeft, texTop ); currentPt++; } } verts->unlock(); AssertFatal(currentPt <= mLength * 6, "FontRenderBatcher::render - too many verts for length of string!"); GFX->setVertexBuffer(verts); GFX->setupGenericShaders( GFXDevice::GSAddColorTexture ); // Now do an optimal render! for( S32 i = 0; i < mSheets.size(); i++ ) { if(!mSheets[i]) continue; if(!mSheets[i]->numChars ) continue; GFX->setTexture( 0, mFont->getTextureHandle(i) ); GFX->drawPrimitive(GFXTriangleList, mSheets[i]->startVertex, mSheets[i]->numChars * 2); } }
//-------------------------------------- static void m_matF_x_scale_x_planeF_C(const F32* m, const F32* s, const F32* p, F32* presult) { // We take in a matrix, a scale factor, and a plane equation. We want to output // the resultant normal // We have T = m*s // To multiply the normal, we want Inv(Tr(m*s)) // Inv(Tr(ms)) = Inv(Tr(s) * Tr(m)) // = Inv(Tr(m)) * Inv(Tr(s)) // // Inv(Tr(s)) = Inv(s) = [ 1/x 0 0 0] // [ 0 1/y 0 0] // [ 0 0 1/z 0] // [ 0 0 0 1] // // Since m is an affine matrix, // Tr(m) = [ [ ] 0 ] // [ [ R ] 0 ] // [ [ ] 0 ] // [ [ x y z ] 1 ] // // Inv(Tr(m)) = [ [ -1 ] 0 ] // [ [ R ] 0 ] // [ [ ] 0 ] // [ [ A B C ] 1 ] // Where: // // P = (x, y, z) // A = -(Row(0, r) * P); // B = -(Row(1, r) * P); // C = -(Row(2, r) * P); MatrixF invScale(true); F32* pScaleElems = invScale; pScaleElems[MatrixF::idx(0, 0)] = 1.0f / s[0]; pScaleElems[MatrixF::idx(1, 1)] = 1.0f / s[1]; pScaleElems[MatrixF::idx(2, 2)] = 1.0f / s[2]; const Point3F shear( m[MatrixF::idx(3, 0)], m[MatrixF::idx(3, 1)], m[MatrixF::idx(3, 2)] ); const Point3F row0(m[MatrixF::idx(0, 0)], m[MatrixF::idx(0, 1)], m[MatrixF::idx(0, 2)]); const Point3F row1(m[MatrixF::idx(1, 0)], m[MatrixF::idx(1, 1)], m[MatrixF::idx(1, 2)]); const Point3F row2(m[MatrixF::idx(2, 0)], m[MatrixF::idx(2, 1)], m[MatrixF::idx(2, 2)]); const F32 A = -mDot(row0, shear); const F32 B = -mDot(row1, shear); const F32 C = -mDot(row2, shear); MatrixF invTrMatrix(true); F32* destMat = invTrMatrix; destMat[MatrixF::idx(0, 0)] = m[MatrixF::idx(0, 0)]; destMat[MatrixF::idx(1, 0)] = m[MatrixF::idx(1, 0)]; destMat[MatrixF::idx(2, 0)] = m[MatrixF::idx(2, 0)]; destMat[MatrixF::idx(0, 1)] = m[MatrixF::idx(0, 1)]; destMat[MatrixF::idx(1, 1)] = m[MatrixF::idx(1, 1)]; destMat[MatrixF::idx(2, 1)] = m[MatrixF::idx(2, 1)]; destMat[MatrixF::idx(0, 2)] = m[MatrixF::idx(0, 2)]; destMat[MatrixF::idx(1, 2)] = m[MatrixF::idx(1, 2)]; destMat[MatrixF::idx(2, 2)] = m[MatrixF::idx(2, 2)]; destMat[MatrixF::idx(0, 3)] = A; destMat[MatrixF::idx(1, 3)] = B; destMat[MatrixF::idx(2, 3)] = C; invTrMatrix.mul(invScale); Point3F norm(p[0], p[1], p[2]); Point3F point = norm * -p[3]; invTrMatrix.mulP(norm); norm.normalize(); MatrixF temp; memcpy(temp, m, sizeof(F32) * 16); point.x *= s[0]; point.y *= s[1]; point.z *= s[2]; temp.mulP(point); PlaneF resultPlane(point, norm); presult[0] = resultPlane.x; presult[1] = resultPlane.y; presult[2] = resultPlane.z; presult[3] = resultPlane.d; }
void TSStaticPolysoupConvex::getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf) { cf->material = 0; cf->object = mObject; // For a tetrahedron this is pretty easy... first // convert everything into world space. Point3F tverts[4]; mat.mulP(verts[0], &tverts[0]); mat.mulP(verts[1], &tverts[1]); mat.mulP(verts[2], &tverts[2]); mat.mulP(verts[3], &tverts[3]); // points... S32 firstVert = cf->mVertexList.size(); cf->mVertexList.increment(); cf->mVertexList.last() = tverts[0]; cf->mVertexList.increment(); cf->mVertexList.last() = tverts[1]; cf->mVertexList.increment(); cf->mVertexList.last() = tverts[2]; cf->mVertexList.increment(); cf->mVertexList.last() = tverts[3]; // edges... cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+0; cf->mEdgeList.last().vertex[1] = firstVert+1; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+1; cf->mEdgeList.last().vertex[1] = firstVert+2; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+2; cf->mEdgeList.last().vertex[1] = firstVert+0; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+3; cf->mEdgeList.last().vertex[1] = firstVert+0; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+3; cf->mEdgeList.last().vertex[1] = firstVert+1; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+3; cf->mEdgeList.last().vertex[1] = firstVert+2; // triangles... cf->mFaceList.increment(); cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[0]); cf->mFaceList.last().vertex[0] = firstVert+2; cf->mFaceList.last().vertex[1] = firstVert+1; cf->mFaceList.last().vertex[2] = firstVert+0; cf->mFaceList.increment(); cf->mFaceList.last().normal = PlaneF(tverts[1], tverts[0], tverts[3]); cf->mFaceList.last().vertex[0] = firstVert+1; cf->mFaceList.last().vertex[1] = firstVert+0; cf->mFaceList.last().vertex[2] = firstVert+3; cf->mFaceList.increment(); cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[3]); cf->mFaceList.last().vertex[0] = firstVert+2; cf->mFaceList.last().vertex[1] = firstVert+1; cf->mFaceList.last().vertex[2] = firstVert+3; cf->mFaceList.increment(); cf->mFaceList.last().normal = PlaneF(tverts[0], tverts[2], tverts[3]); cf->mFaceList.last().vertex[0] = firstVert+0; cf->mFaceList.last().vertex[1] = firstVert+2; cf->mFaceList.last().vertex[2] = firstVert+3; // All done! }
void FlyingVehicle::updateForces(F32 /*dt*/) { PROFILE_SCOPE( FlyingVehicle_UpdateForces ); MatrixF currPosMat; mRigid.getTransform(&currPosMat); mRigid.atRest = false; Point3F massCenter; currPosMat.mulP(mDataBlock->massCenter,&massCenter); Point3F xv,yv,zv; currPosMat.getColumn(0,&xv); currPosMat.getColumn(1,&yv); currPosMat.getColumn(2,&zv); F32 speed = mRigid.linVelocity.len(); Point3F force = Point3F(0, 0, sFlyingVehicleGravity * mRigid.mass * mGravityMod); Point3F torque = Point3F(0, 0, 0); // Drag at any speed force -= mRigid.linVelocity * mDataBlock->minDrag; torque -= mRigid.angMomentum * mDataBlock->rotationalDrag; // Auto-stop at low speeds if (speed < mDataBlock->maxAutoSpeed) { F32 autoScale = 1 - speed / mDataBlock->maxAutoSpeed; // Gyroscope F32 gf = mDataBlock->autoAngularForce * autoScale; torque -= xv * gf * mDot(yv,Point3F(0,0,1)); // Manuevering jets F32 sf = mDataBlock->autoLinearForce * autoScale; force -= yv * sf * mDot(yv, mRigid.linVelocity); force -= xv * sf * mDot(xv, mRigid.linVelocity); } // Hovering Jet F32 vf = -sFlyingVehicleGravity * mRigid.mass * mGravityMod; F32 h = getHeight(); if (h <= 1) { if (h > 0) { vf -= vf * h * 0.1; } else { vf += mDataBlock->jetForce * -h; } } force += zv * vf; // Damping "surfaces" force -= xv * mDot(xv,mRigid.linVelocity) * mDataBlock->horizontalSurfaceForce; force -= zv * mDot(zv,mRigid.linVelocity) * mDataBlock->verticalSurfaceForce; // Turbo Jet if (mJetting) { if (mThrustDirection == ThrustForward) force += yv * mDataBlock->jetForce * mCeilingFactor; else if (mThrustDirection == ThrustBackward) force -= yv * mDataBlock->jetForce * mCeilingFactor; else force += zv * mDataBlock->jetForce * mDataBlock->vertThrustMultiple * mCeilingFactor; } // Maneuvering jets force += yv * (mThrust.y * mDataBlock->maneuveringForce * mCeilingFactor); force += xv * (mThrust.x * mDataBlock->maneuveringForce * mCeilingFactor); // Steering Point2F steering; steering.x = mSteering.x / mDataBlock->maxSteeringAngle; steering.x *= mFabs(steering.x); steering.y = mSteering.y / mDataBlock->maxSteeringAngle; steering.y *= mFabs(steering.y); torque -= xv * steering.y * mDataBlock->steeringForce; torque -= zv * steering.x * mDataBlock->steeringForce; // Roll torque += yv * steering.x * mDataBlock->steeringRollForce; F32 ar = mDataBlock->autoAngularForce * mDot(xv,Point3F(0,0,1)); ar -= mDataBlock->rollForce * mDot(xv, mRigid.linVelocity); torque += yv * ar; // Add in force from physical zones... force += mAppliedForce; // Container buoyancy & drag force -= Point3F(0, 0, 1) * (mBuoyancy * sFlyingVehicleGravity * mRigid.mass * mGravityMod); force -= mRigid.linVelocity * mDrag; // mRigid.force = force; mRigid.torque = torque; }
void AITurretShape::_trackTarget(F32 dt) { // Only on server if (isClientObject()) return; // We can only track a target if we have one if (!mTarget.isValid()) return; Point3F targetPos = mTarget.target->getBoxCenter(); // Can we see the target? MatrixF aimMat; getAimTransform(aimMat); Point3F start; aimMat.getColumn(3, &start); RayInfo ri; Point3F sightPoint; disableCollision(); bool los = _testTargetLineOfSight(start, mTarget.target, sightPoint); enableCollision(); if (!los) { // Target is blocked. Should we try to track from its last // known position and velocity? SimTime curTime = Sim::getCurrentTime(); if ( (curTime - mTarget.lastSightTime) > (mDataBlock->trackLostTargetTime * 1000.0f) ) { // Time's up. Stop tracking. _cleanupTargetAndTurret(); return; } // Use last known information to attempt to // continue to track target for a while. targetPos = mTarget.lastPos + mTarget.lastVel * F32(curTime - mTarget.lastSightTime) / 1000.0f; } else { // Target is visible // We only track targets that are alive if (mTarget.target->getDamageState() != Enabled) { // We can't track any more _cleanupTargetAndTurret(); return; } targetPos = sightPoint; // Store latest target info mTarget.lastPos = targetPos; mTarget.lastVel = mTarget.target->getVelocity(); mTarget.lastSightTime = Sim::getCurrentTime(); } // Calculate angles to face the target, specifically the part that we can see VectorF toTarget; MatrixF mat; S32 node = mDataBlock->aimNode; if (node != -1) { // Get the current position of our node MatrixF* nodeTrans = &mShapeInstance->mNodeTransforms[node]; Point3F currentPos; nodeTrans->getColumn(3, ¤tPos); // Turn this into a matrix we can use to put the target // position into our space. MatrixF nodeMat(true); nodeMat.setColumn(3, currentPos); mat.mul(mObjToWorld, nodeMat); mat.affineInverse(); } else { mat = mWorldToObj; } mat.mulP(targetPos, &toTarget); // lead the target F32 timeToTargetSquared = (mWeaponLeadVelocitySquared > 0) ? toTarget.lenSquared() / mWeaponLeadVelocitySquared : 0; if (timeToTargetSquared > 1.0) { targetPos = targetPos + (mTarget.lastVel * mSqrt(timeToTargetSquared)); mat.mulP(targetPos, &toTarget); } F32 yaw, pitch; MathUtils::getAnglesFromVector(toTarget, yaw, pitch); if (yaw > M_PI_F) yaw = yaw - M_2PI_F; //if (pitch > M_PI_F) // pitch = -(pitch - M_2PI_F); Point3F rot(-pitch, 0.0f, yaw); // If we have a rotation rate make sure we follow it if (mHeadingRate > 0) { F32 rate = mHeadingRate * dt; F32 rateCheck = mFabs(rot.z - mRot.z); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.z = mClampF(rot.z, mRot.z-rate, mRot.z+rate); } } if (mPitchRate > 0) { F32 rate = mPitchRate * dt; F32 rateCheck = mFabs(rot.x - mRot.x); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.x = mClampF(rot.x, mRot.x-rate, mRot.x+rate); } } // Test if the rotation to the target is outside of our limits if (_outsideLimits(rot)) { // We can't track any more _cleanupTargetAndTurret(); return; } // Test if the target is out of weapons range if (toTarget.lenSquared() > mWeaponRangeSquared) { // We can't track any more _cleanupTargetAndTurret(); return; } mRot = rot; _setRotation( mRot ); setMaskBits(TurretUpdateMask); }
void AtlasConvex::getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf) { cf->material = 0; cf->object = mObject; // For a tetrahedron this is pretty easy. // points... S32 firstVert = cf->mVertexList.size(); cf->mVertexList.increment(); mat.mulP(point[0], &cf->mVertexList.last()); cf->mVertexList.increment(); mat.mulP(point[1], &cf->mVertexList.last()); cf->mVertexList.increment(); mat.mulP(point[2], &cf->mVertexList.last()); cf->mVertexList.increment(); mat.mulP(point[3], &cf->mVertexList.last()); // edges... cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+0; cf->mEdgeList.last().vertex[1] = firstVert+1; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+1; cf->mEdgeList.last().vertex[1] = firstVert+2; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+2; cf->mEdgeList.last().vertex[1] = firstVert+0; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+3; cf->mEdgeList.last().vertex[1] = firstVert+0; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+3; cf->mEdgeList.last().vertex[1] = firstVert+1; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = firstVert+3; cf->mEdgeList.last().vertex[1] = firstVert+2; // triangles... cf->mFaceList.increment(); cf->mFaceList.last().normal; mat.mulV(normal, &cf->mFaceList.last().normal); cf->mFaceList.last().vertex[0] = firstVert+0; cf->mFaceList.last().vertex[1] = firstVert+1; cf->mFaceList.last().vertex[2] = firstVert+2; cf->mFaceList.increment(); mat.mulV(PlaneF(point[0], point[1], point[3]), &cf->mFaceList.last().normal); cf->mFaceList.last().vertex[0] = firstVert+3; cf->mFaceList.last().vertex[1] = firstVert+0; cf->mFaceList.last().vertex[2] = firstVert+1; cf->mFaceList.increment(); mat.mulV(PlaneF(point[1], point[2], point[3]), &cf->mFaceList.last().normal); cf->mFaceList.last().vertex[0] = firstVert+3; cf->mFaceList.last().vertex[1] = firstVert+1; cf->mFaceList.last().vertex[2] = firstVert+2; cf->mFaceList.increment(); mat.mulV(PlaneF(point[2], point[0], point[3]), &cf->mFaceList.last().normal); cf->mFaceList.last().vertex[0] = firstVert+3; cf->mFaceList.last().vertex[1] = firstVert+0; cf->mFaceList.last().vertex[2] = firstVert+2; // All done! }
void Polytope::buildBox(const MatrixF& transform,const Box3F& box) { // Box is assumed to be axis aligned in the source space. // Transform into geometry space Point3F xvec,yvec,zvec,min; transform.getColumn(0,&xvec); xvec *= box.len_x(); transform.getColumn(1,&yvec); yvec *= box.len_y(); transform.getColumn(2,&zvec); zvec *= box.len_z(); transform.mulP(box.minExtents,&min); // Initial vertices mVertexList.setSize(8); mVertexList[0].point = min; mVertexList[1].point = min + yvec; mVertexList[2].point = min + xvec + yvec; mVertexList[3].point = min + xvec; mVertexList[4].point = mVertexList[0].point + zvec; mVertexList[5].point = mVertexList[1].point + zvec; mVertexList[6].point = mVertexList[2].point + zvec; mVertexList[7].point = mVertexList[3].point + zvec; S32 i; for (i = 0; i < 8; i++) mVertexList[i].side = 0; // Initial faces mFaceList.setSize(6); for (S32 f = 0; f < 6; f++) { Face& face = mFaceList[f]; face.original = true; face.vertex = 0; } mFaceList[0].plane.set(mVertexList[0].point,xvec); mFaceList[0].plane.invert(); mFaceList[1].plane.set(mVertexList[2].point,yvec); mFaceList[2].plane.set(mVertexList[2].point,xvec); mFaceList[3].plane.set(mVertexList[0].point,yvec); mFaceList[3].plane.invert(); mFaceList[4].plane.set(mVertexList[0].point,zvec); mFaceList[4].plane.invert(); mFaceList[5].plane.set(mVertexList[4].point,zvec); // Initial edges mEdgeList.setSize(12); Edge* edge = mEdgeList.begin(); S32 nextEdge = 0; for (i = 0; i < 4; i++) { S32 n = (i == 3)? 0: i + 1; S32 p = (i == 0)? 3: i - 1; edge->vertex[0] = i; edge->vertex[1] = n; edge->face[0] = i; edge->face[1] = 4; edge->next = ++nextEdge; edge++; edge->vertex[0] = 4 + i; edge->vertex[1] = 4 + n; edge->face[0] = i; edge->face[1] = 5; edge->next = ++nextEdge; edge++; edge->vertex[0] = i; edge->vertex[1] = 4 + i; edge->face[0] = i; edge->face[1] = p; edge->next = ++nextEdge; edge++; } edge[-1].next = -1; // Volume mVolumeList.setSize(1); Volume& volume = mVolumeList.last(); volume.edgeList = 0; volume.material = -1; volume.object = 0; sideCount = 0; }
bool SceneCullingState::isOccludedByTerrain( SceneObject* object ) const { PROFILE_SCOPE( SceneCullingState_isOccludedByTerrain ); // Don't try to occlude globally bounded objects. if( object->isGlobalBounds() ) return false; const Vector< SceneObject* >& terrains = getSceneManager()->getContainer()->getTerrains(); const U32 numTerrains = terrains.size(); for( U32 terrainIdx = 0; terrainIdx < numTerrains; ++ terrainIdx ) { TerrainBlock* terrain = dynamic_cast< TerrainBlock* >( terrains[ terrainIdx ] ); if( !terrain ) continue; MatrixF terrWorldTransform = terrain->getWorldTransform(); Point3F localCamPos = getCameraState().getViewPosition(); terrWorldTransform.mulP(localCamPos); F32 height; terrain->getHeight( Point2F( localCamPos.x, localCamPos.y ), &height ); bool aboveTerrain = ( height <= localCamPos.z ); // Don't occlude if we're below the terrain. This prevents problems when // looking out from underground bases... if( !aboveTerrain ) continue; const Box3F& oBox = object->getObjBox(); F32 minSide = getMin(oBox.len_x(), oBox.len_y()); if (minSide > 85.0f) continue; const Box3F& rBox = object->getWorldBox(); Point3F ul(rBox.minExtents.x, rBox.minExtents.y, rBox.maxExtents.z); Point3F ur(rBox.minExtents.x, rBox.maxExtents.y, rBox.maxExtents.z); Point3F ll(rBox.maxExtents.x, rBox.minExtents.y, rBox.maxExtents.z); Point3F lr(rBox.maxExtents.x, rBox.maxExtents.y, rBox.maxExtents.z); terrWorldTransform.mulP(ul); terrWorldTransform.mulP(ur); terrWorldTransform.mulP(ll); terrWorldTransform.mulP(lr); Point3F xBaseL0_s = ul - localCamPos; Point3F xBaseL0_e = lr - localCamPos; Point3F xBaseL1_s = ur - localCamPos; Point3F xBaseL1_e = ll - localCamPos; static F32 checkPoints[3] = {0.75, 0.5, 0.25}; RayInfo rinfo; for( U32 i = 0; i < 3; i ++ ) { Point3F start = (xBaseL0_s * checkPoints[i]) + localCamPos; Point3F end = (xBaseL0_e * checkPoints[i]) + localCamPos; if (terrain->castRay(start, end, &rinfo)) continue; terrain->getHeight(Point2F(start.x, start.y), &height); if ((height <= start.z) == aboveTerrain) continue; start = (xBaseL1_s * checkPoints[i]) + localCamPos; end = (xBaseL1_e * checkPoints[i]) + localCamPos; if (terrain->castRay(start, end, &rinfo)) continue; Point3F test = (start + end) * 0.5; if (terrain->castRay(localCamPos, test, &rinfo) == false) continue; return true; } } return false; }
F32 GjkCollisionState::distance(const MatrixF& a2w, const MatrixF& b2w, const F32 dontCareDist, const MatrixF* _w2a, const MatrixF* _w2b) { num_iterations = 0; MatrixF w2a,w2b; if (_w2a == NULL || _w2b == NULL) { w2a = a2w; w2b = b2w; w2a.inverse(); w2b.inverse(); } else { w2a = *_w2a; w2b = *_w2b; } reset(a2w,b2w); bits = 0; all_bits = 0; F32 mu = 0; do { nextBit(); VectorF va,sa; w2a.mulV(-v,&va); p[last] = a->support(va); a2w.mulP(p[last],&sa); VectorF vb,sb; w2b.mulV(v,&vb); q[last] = b->support(vb); b2w.mulP(q[last],&sb); VectorF w = sa - sb; F32 nm = mDot(v, w) / dist; if (nm > mu) mu = nm; if (mu > dontCareDist) return mu; if (mFabs(dist - mu) <= dist * rel_error) return dist; ++num_iterations; if (degenerate(w) || num_iterations > sIteration) { ++num_irregularities; return dist; } y[last] = w; all_bits = bits | last_bit; if (!closest(v)) { ++num_irregularities; return dist; } dist = v.len(); } while (bits < 15 && dist > sTolerance) ; if (bits == 15 && mu <= 0) dist = 0; return dist; }
bool ForestItem::castRay( const Point3F &start, const Point3F &end, RayInfo *outInfo, bool rendered ) const { if ( !mWorldBox.collideLine( start, end ) ) return false; Point3F s, e; MatrixF mat = getTransform(); mat.scale( Point3F(mScale) ); mat.inverse(); mat.mulP( start, &s ); mat.mulP( end, &e ); TSForestItemData *data = (TSForestItemData*)mDataBlock; TSShapeInstance *si = data->getShapeInstance(); if ( !si ) return false; if ( rendered ) { // Always raycast against detail level zero // because it makes lots of things easier. if ( !si->castRayRendered( s, e, outInfo, 0 ) ) return false; if ( outInfo->userData != NULL ) *(ForestItem*)(outInfo->userData) = *this; return true; } RayInfo shortest; shortest.t = 1e8; bool gotMatch = false; S32 detail; const Vector<S32> &details = data->getLOSDetails(); for (U32 i = 0; i < details.size(); i++) { detail = details[i]; if (detail != -1) { //si->animate(data->mLOSDetails[i]); if ( si->castRayOpcode( detail, s, e, outInfo ) ) { if (outInfo->t < shortest.t) { gotMatch = true; shortest = *outInfo; } } } } if ( !gotMatch ) return false; // Copy out the shortest time... *outInfo = shortest; if ( outInfo->userData != NULL ) *(ForestItem*)(outInfo->userData) = *this; return true; }