http://www.cnblogs.com/mumuliang/archive/2011/06/02/2068453.html


1 The SDK Object  
首先用全局函数PxCreatePhysics创建一个PxPhysics对象。
复制代码
#include "PxPhysicsAPI.h"

bool recordMemoryAllocations = true;

static PxDefaultErrorCallback gDefaultErrorCallback;
static PxDefaultAllocator gDefaultAllocatorCallback;

mSDK = PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, PxTolerancesScale(), recordMemoryAllocations );
if(!mSDK)
        fatalError("PxCreatePhysics failed!");
复制代码

这部分和SDK 2.x稍微有些不同,必须设置allocator callback和error callback. physx3的extensions提供了一组默认的PxDefaultAllocatorPxDefaultErrorCallback

倒数第二个参数,PxTolerancesScale, 是创建场景中的物体的默认Tolerances。


最后一个bool,true表示可以 memory usage debugging 。

 

 2 The Allocator Callback    
The allocator callback是需要自己实现的动态内存管理的接口类,PxAllocatorCallback。physx实现了一个,PxDefaultAllocator
复制代码
#include <malloc.h>
class PxDefaultAllocator : public PxAllocatorCallback
{
        void* allocate(size_t size, const char*, const char*, int)
        {
                return _aligned_malloc(size, 16);
        }

        void deallocate(void* ptr)
        {
                _aligned_free(ptr);
        }
};
复制代码

Note 与2.x不同的是,3.要求分配的内存是16位对齐(We now require that the memory that is returned be 16-byte aligned! )。windows上可以用 _aligned_malloc. 控制台系统(console systems)上的malloc()返回的已经是16位对其的空间,因此不许特别处理。


If you want to track the SDK’s use of dynamic memory, you can put your own custom instrumentation code into the allocate and deallocate functions.

If you are curious about the three unused parameters of allocate, you can refer to PxAllocatorCallback::allocate to find out more about them. Basically, we support a system of named allocations which let us identify types of memory allocation so that you can allocate them from special heaps. The last two parameters are the __FILE__ and __LINE__ inside the SDK code where the allocation was made.

 3 The Error Callback   
the error callback也是要自己实现的一个接口PxErrorCallback。这个接口类只需要实现一个方法,reportError. physx3也已经实现了一个。
复制代码
class PxDefaultErrorCallback : public PxErrorCallback
{
public:
        PxDefaultErrorCallback();
        ~PxDefaultErrorCallback();

        virtual void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line);
};

void PxDefaultErrorCallback::reportError(PxErrorCode::Enum e, const char* message, const char* file, int line)
{
        const char* errorCode = NULL;

        switch (e)
        {
        case PxErrorCode::eINVALID_PARAMETER:
                errorCode = "invalid parameter";
                break;
        case PxErrorCode::eINVALID_OPERATION:
                errorCode = "invalid operation";
                break;
        case PxErrorCode::eOUT_OF_MEMORY:
                errorCode = "out of memory";
                break;
        case PxErrorCode::eDEBUG_INFO:
                errorCode = "info";
                break;
        case PxErrorCode::eDEBUG_WARNING:
                errorCode = "warning";
                break;
        default:
                errorCode = "unknown error";
                break;
        }

        printf("%s (%d) :", file, line);
        printf("%s", errorCode);
        printf(" : %s\n", message);
}
复制代码

 4 Cooking and Extensions  
PhysX有俩可选库供使用:extensions 和 cooking. 应该在创建了SDK(也就是PxPhysics)对象后要首先初始化他们。他俩都需要一个东东,SDK的foundation对象。
if (!PxInitExtensions(*mSDK))
        fatalError("PxInitExtensions failed!");

mCooking = PxCreateCooking(PX_PHYSICS_VERSION, &mSDK->getFoundation(), PxCookingParams());
if (!mCooking)
        fatalError("PxCreateCooking failed!");
PxCreateCooking的第三个参数是可以设置的, 为了省事儿这儿也有默认值。

 5 The Scene  
PxScene是PhysX的体现. 这个必须有。
复制代码
static PxDefaultSimulationFilterShader gDefaultFilterShader;
PxScene* mScene;

PxSceneDesc sceneDesc(mSDK->getTolerancesScale());
sceneDesc.gravity = PxVec3(0.0f, -9.81f0.0f);
customizeSceneDesc(sceneDesc);

if(!sceneDesc.cpuDispatcher)
{
        mCpuDispatcher = PxDefaultCpuDispatcherCreate(mNbThreads);
        if(!mCpuDispatcher)
                fatalError("PxDefaultCpuDispatcherCreate failed!");
        sceneDesc.cpuDispatcher = mCpuDispatcher;
}
if(!sceneDesc.filterShader)
        sceneDesc.filterShader  = &gDefaultFilterShader;

#ifdef PX_WINDOWS
if(!sceneDesc.gpuDispatcher && mCudaContextManager)
{
        sceneDesc.gpuDispatcher = mCudaContextManager->getGpuDispatcher();
}
#endif
mScene = mSDK->createScene(sceneDesc);
if (!mScene)
        fatalError("createScene failed!");
复制代码

PxScene的属性在创建时设置,创建后不能修改,PxSceneDesc就是描述其属性的结构体. 

PxDefaultCpuDispatcherCreate 返回一个默认的CpuDispatcher对象. 线程数俺们设成1。当然这个CpuDispatcher也是可以自己去实现的。

PxDefaultSimulationFilterShader ,又一个physx3的默认对象,实现接口PxSimulationFilterShader.

 6 Basic Actors  

空场景有了,接下来添加物体。所有物体都必须有材质,因此俺们先造个材质PxMeterial
PxMaterial*     mMaterial;

mMaterial = mSDK->createMaterial(0.5f0.5f0.1f);     //static friction, dynamic friction, restitution
if(!mMaterial)
        fatalError("createMaterial failed!");
材质定义了物体的摩擦力和惯性系数(friction and restitution coefficients )。

然后就可以用这个材质创建个最简单的static geometry,地面。 

复制代码
PxReal d = 0.0f;
PxU32 axis = 1;
PxTransform pose;

if(axis == 0)
        pose = PxTransform(PxVec3(d, 0.0f0.0f));
else if(axis == 1)
        pose = PxTransform(PxVec3(0.0f, d, 0.0f),PxQuat(PxHalfPi, PxVec3(0.0f0.0f1.0f)));
else if(axis == 2)
        pose = PxTransform(PxVec3(0.0f0.0f, d), PxQuat(-PxHalfPi, PxVec3(0.0f1.0f0.0f)));

PxRigidStatic* plane = mSDK->createRigidStatic(pose);
if (!plane)
        fatalError("create plane failed!");
PxShape* shape = plane->createShape(PxPlaneGeometry(), *mMaterial);
if (!shape)
        fatalError("create shape failed!");
mScene->addActor(*plane);
复制代码
axis的部分给出了分别设置x、y、z方向为竖直方向的做法。(Physx默认姿态?是,X正方向。)

第一个PxRigidStatic actor就酱(sdk调用createRigidStatic())创建了, 然后往里扔了一个平面shape, 这个shape使用了前边儿创建的material。最后,把这个static actor添加到场景中。 

再使用extensions中的全局函数PxCreateDynamic()创建一个盒子. 这个函数会把shape和actor一并创建,并根据传入的密度density计算其质量mass和惯性inertia。
复制代码
PxReal density = 1.0f;
PxTransform(PxVec3(0.0f5.0f0.0f), PxQuat::createIdentity());
PxVec3 dimensions(1.0f1.0f1.0f);
PxBoxGeometry geometry(dimensions);

PxRigidDynamic *actor = PxCreateDynamic(*mSDK, transform, geometry, *mMaterial, density);
if (!actor)
        fatalError("create actor failed!");
mScene->addActor(*actor);
复制代码

这儿还是用的那个材质。最后表忘了mScene->addActor()。

 7 The Simulation Loop  
场景和其中的物体都创建好了,要让他们动起来,需要在仿真循环中往前推进一个时间段。blabla...

一个最简单的仿真循环:
复制代码
mAccumulator = 0.0f;
mStepSize = 1.0f / 60.0f;

virtual bool advance(PxReal dt)
{
        mAccumulator  += dt;
        if(mAccumulator < mStepSize)
                return false;

        mAccumulator -= mStepSize;

        mScene->simulate(mStepSize);
        return true;
}
复制代码

mScene->simulate()的参数是往前推进的时间长度。这个函数极有可能是异步调用的。因此在return的时候可能还没有算完。

假使这回想在某个图形引擎中使用PhysX,抓取物体的位置和朝向 (positions and orientations) 以刷新图形引擎中对应的数据,可以使用PxShapeExt下的getGlobalPose。
PxTransform newPose = PxShapeExt::getGlobalPose(*mPhysicsShape);

图形引擎run的时候PhysX的也在run,因此应该询问simulate有否完成。
mScene->fetchResults(true);

true表示如果还没完成就block直到完成。在调用fetchResults之前使用getGlobalPose() (或其他获取状态的函数) 获取actor或其他对象的数据,得到的是上一次simulate完成后的数据。

fetchResults, 会调用所有已定义的event callback。参考 ref:callbacks章节。

 8 Shutting Down  
PhysX不用了以后,可以手动release。凡是形如 PxCreate... 创建的对象都有release方法,用来销毁相关的数据。关闭整个场景的话,也同(调用PxPhysicx的release)。
mSDK->release();

 9 PhysX Visual Debugger Support  
PVD (PhysX Visual Debugger) 可直观的查看仿真场景中的情形。

PhysX一次只能连接?一个debugger,PvdConnectionFactoryManager管理这些连接. 

有几种方式连接debugger. 最简单的方法是使用a network stream. extensions提供了一个功能函数PxExtensionVisualDebugger::connect. 调用是要确保debugger已经运行. 

另一种可能更高效的方式把debug信息写到一个文件,然后用debugger打开。PvdConnectionFactoryManager 类提供了一个完成该功能的函数。

 

略 



PhysX3 User Guide 02 - Shape

Posted on 2011-06-02 16:07 mumuliang 阅读(1658) 评论(4) 编辑 收藏
Shape是PxGeometry的体现。一个Shape包括:PxGeometry, PxMetarial,和shape相对它所属的actor的pose(orientation and positionActor),肯定是这个PxActor创建的。多个shape可以凑成一组(成为一个Compound)在同一个Actor中。
和PhysX 2.x类似, 创建Shape是需定义一个PxGeometry. 也就是说每一个Shape都有它自己的PxGeometry类型. PhysX既有的PxGeometry如下.

1)for static and dynamic Actors:Spheres, Capsules, Boxes, ConvexMeshes

2)for static Actors only: Planes, HeightFields, TriangleMeshes

 (although TriangleMeshes can be used as kinematics in scene queries)

创建 simulation object or Shape 的步骤:

  1. 用SDK对象创建一个Actor,  (要给出它的pose (orientation and position))。
  2. 创建Shape需要的Geometry
  3. Actor创建Shape,们。(别忘了材质和shape的相对pose)
  4. 更新mass、inertia 等属性。 (PhysX Extensions中有相关函数)
  5. 向Scene添加Actor。

 1 Spheres  

在某位置以某初始化速度扔出一个球体。
首先,俺们需要一个dynamic的actor
PxRigidDynamic* aSphereActor = thePhysics->createRigidDynamic(PxTransform(position));

然后是一个shape。描述sphere的geomety只需要半径足够了,第二个材质是必须要的。

PxShape* aSphereShape = aSphereActor->createShape(PxSphereGeometry(radius), aMaterial);

Actor加完所有的shape以后,就计算mass和inertia。

PxRigidBodyExt::updateMassAndInertia(*aSphereActor, sphereDensity); 

用Shape设置初始速度,这是个linear velocity vector:

aSphereShape->setLinearVelocity(velocity);

将Actor加到场景中。
aScene->addActor(aSphereActor);

 2 Capsules  

和Sphere相比, Capsule还需要一个height.  注意,初始化Capsule设置的是half height。创建Shape和Actor的方式同Sphere,略。
PxTransform pose;
pose.q = PxQuat(PxHalfPi, PxVec(0,0,1));
PxShape* aCapsuleShape = aCapsuleActor->createShape(PxCapsuleGeometry(radius, halfHeight), aMaterial, pose);

capsule的height默认是y方向的,要让Capsule沿X方向延伸,将其绕Z轴旋转90度。

 3 Boxes  


描述一个Box的只需要3个参数。
PxShape* aBoxShape = aBoxActor->createShape(PxBoxGeometry(a/2, b/2, c/2), aMaterial);

a, b , c代表其边长。

 4 Convex Meshes  


使用顶点vertex来描述Convex Mesh。创建一个金字塔形试试看.
首先定义其边缘的顶点(extreme verteices)。
static const PxVec3 convexVerts[] = {PxVec3(0,1,0),PxVec3(1,0,0),PxVec3(-1,0,0),PxVec3(0,0,1),PxVec3(0,0,-1)};

然后描述面上的点:

PxConvexMeshDesc convexDesc;
convexDesc.points.count = 5;
convexDesc.points.stride = sizeof(PxVec3);
convexDesc.points.data = convexVerts;
convexDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX;

有了这些点PhysX SDK就可以计算出其余相关的数据。俺们把这个过程叫做cooking。接下来叫你如何用PhysX cook a Convex Mesh,and it is done through a Stream objects。

PxCooking* cooking = PxCreateCooking(PX_PHYSICS_VERSION, thePhysics->getFoundation(), PxCookingParams());
MemoryWriteBuffer buf;
bool status = cooking->cookConvexMesh(convexDesc, buf);
PxConvexMesh* convexMesh = thePhysics->createConvexMesh(MemoryReadBuffer(buf.data));
cooking->release();

现在有了ConvexMesh,就可以用它创建一个Convex的Shape了。

PxShape* aConvexShape = aConvexActor->createShape(PxConvexMeshGeometry(convexMesh, PxMeshScale()), aMaterial, aTransform);
PxConvexMeshGeometry的第二个参数用以控制ConvexMesh的缩放。

 5 Planes  


Plane把空间分成以上和以下。凡是低于plane物体就会和它碰撞. 俺们常用它来创建地面或者模拟的世界的边界。Plane这种Geometry根本不需要参数.只要把它放到某处就可以了。它是static的。当然是static。
PxRigidStatic* aPlaneActor = thePhysics->createRigidStatic(pose);
PxShape* aPlaneShape = aPlaneActor->createShape(PxPlaneGeometry(), aMaterial);

 6 Heightfields  

如名, 地形就可以用方形网格采样的高度值描述。
PxHeightFieldSample* samples = (PxHeightFieldSample*)alloc(sizeof(PxHeightFieldSample)*(numRows*numCols));

每个样本(方格子)都有一个16位的整数值和2个材质(一个方格划分成2个三角面)。这是一种特殊的已经定义了的材质,PxHeightFieldMaterial::eHOLE. 如果你用float型描述高度(也木有关系?),there is the possibility to set the used scale later on with the Geometry. Since there are two ways to split a rectangle into two triangles, the split diagonal can be selected with the tesselation flag.

当然,还要知道每个方向有多少样本高度。
PxHeightFieldDesc hfDesc;
hfDesc.format = PxHeightFieldFormat::eS16_TM;
hfDesc.nbColumns = numCols;
hfDesc.nbRows = numRows;
hfDesc.samples.data = samples;
hfDesc.samples.stride = sizeof(PxHeightFieldSample);

目前只支持提及的格式。eS16_TM?

Heightfields不需要cooking, 但也有一个内部对象需要初始化:
PxHeightField* aHeightField = thePhysics->createHeightField(hfDesc);

接下来就可以用Geometry创建shape:

PxHeightFieldGeometry hfGeom(aHeightField, PxMeshGeometryFlags(), heightScale, rowScale, colScale);

Heightfield也是static的.

PxRigidStatic* aHeightFieldActor = mSDK->createRigidStatic(pose);
PxShape* aHeightFieldShape = aHeightFieldActor->createShape(hfGeom, aMaterial);

如果是 multi-material的heightfields, 需用另一个函数来create Shape

PxShape* aHeightFieldShape = aHeightFieldActor->createShape(hfGeom, aMaterialArray, nbMaterials);

 7 Triangle Meshes  


也是要先有三角面的顶点vertices,然后像convexes一样,需要cooking。

复制代码
PxTriangleMeshDesc meshDesc;
meshDesc.points.count = nbVerts;
meshDesc.triangles.count = nbFaces;
meshDesc.points.stride = 4*3;
meshDesc.triangles.stride = 4*3;
meshDesc.points.data = verts;
meshDesc.triangles.data = indices;
PxCooking* cooking = PxCreateCooking(PX_PHYSICS_VERSION, thePhysics->getFoundation(), PxCookingParams());
MemoryWriteBuffer buf;
bool status = cooking->cookTriangleMesh(meshDesc, buf);
PxTriangleMesh* triangleMesh = thePhysics->createTriangleMesh(MemoryReadBuffer(buf.data));
cooking->release();
复制代码

 

strides表示points和triangle都是3个一组的4字节长的数据。 

Triangle meshe是static. 但是可以用作kinematics。(譬如水面?)

PxRigidStatic* aTriMeshActor = thePhysics->createRigidStatic(pose);
PxShape* aTriMeshShape = aTriMeshActor->createShape(PxTriangleMeshGeometry(triangleMesh), aMaterial);

Triangle meshe也可以缩放. 

索引可能是32bit也可以是16bit,视mesh的三角数目而定。用PxTriangleMesh::has16BitTriangleIndices()可以查看其具体情况.

 

 8 Compound Shapes 

Compound组合了多个Shape到一个Actor中. 要创建一个Compound Shap只需多次调用PxRigidActor::createShape()即可。只是不要忘记最后要计算mash和intertia什么的。
在North Pole Sample中的雪人就是compound对象. compound到一起的shape之间有些是可以分离的。

例如雪人中,有些会被雪球砸中分开。这需要设置一个PxSimulationFilterShaderpairFlags. 然后在可分离的shape被击中后在simulation filter function中做如下工作:

if (needsContactReport(filterData0, filterData1))
{
pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
}

needsContactReport 是一个用来在每个shape的simulationFilterData中测试flags的工具函数helper function. 这些flags是一早在创建Shape时用setDetachable和setSnowball设置的。Contact notification is requested if one of the Shapes is detachable and the other is marked as a snowball. (迷惑 =“=)

That way, the pair will be passed to the PxSimulationEventCallback::onContact() function which is implemented in the Sample. All we want to do here is to remember which detachable Shapes were touched in this frame so far.
After simulation, we can iterate over that list again and actually detach the according Shapes from their respective Actor. Note that the Shape has a local (in Actor space) pose and the Actor has a world pose. Furthermore, a PxShape cannot exist on its own, it is always bound to an Actor.
That means, that when you detach a Shape you have to provide a new Actor for it to continue to exist. The new Actor will have the global pose of the old Shape (in the Compound Actor) and the new local pose is identity. There is a helper extension to calculate the global pose of a Shape. The Geometry and Material needed to create the copy of the Shape in the new Actor can be retreived from the detaching Shape.
复制代码
PxShape* shape = <theDetachingShapeYouKnow>
PxTransform pose = PxShapeExt::getGlobalPose(*shape);
PxRigidDynamic* newActor = mSDK->createRigidDynamic(pose);
PxMaterial* mat;
shape->getMaterials(&mat,1);
PxConvexMeshGeometry convexGeom;
if(shape->getConvexMeshGeometry(convexGeom))
{
PxShape* newShape = newActor->createShape(convexGeom,*mat);
PxRigidBodyExt::updateMassAndInertia(*newActor,1);
aScene->addActor(*newActor));
newActor->addForce(PxVec3(0,.1,0),PxForceMode::eFORCE);
shape->release();
}
复制代码

Obviously, you need several PxGeometry types and a selection code if you don’t know in advance which kind of Shape you are going to detach. As usual the mass properties need to be set after adding Shapes to an Actor. And eventually you can release the old detaching Shape completely.

Note here that you can only change dynamic properties of an Actor after it has been added to a Scene. Kinematic properties like velocities can be set before that though.

 

 9 Mass Computation  

恩,看出来了,actor的mass是需要计算的。用它,PxRigidBodyExt::updateMassAndInertia().
它会计算和设置
  1. actor的mass
  2. 重心,center of mass
  3. 最大静摩擦力? the principal moments of inertia
To illustrate different mass properties we will look at the Wobbly Snowmen in the North Pole Sample. The principle of a roly-poly toy is the low center of mass, moving the object back in upright position after it has been tilted. Usually, most of the body is just an empty shell, and the bottom is filled with some heavy material.
The Wobbly Snowmen come in different flavors, depending on how the mass properties are set:
The first Snowman is basically mass-less. There is just a little sphere with a relatively high mass at the bottom of the Actor. This results in a quite rapid movement due to the small resulting moments of inertia. The Snowman feels light.
The second example uses the mass of the bottom snowball only, resulting in a bigger inertia. Later on, the center of mass is moved to the bottom of the actor. This is by no means physically correct, but we only approximate things here. The resulting Snowman feels a bit more filled.
The third and fourth example use all basic shapes to calculate the mass. The difference is that one calculates the moments of inertia first (from the real center of mass) and then the center of mass is moved to the bottom. The other calculates the moments of inertia about the low center of mass that we pass to the calculation routine. Note how much slower the wobbling is for the second case although both have the same mass. This is because the head accounts for much more in the moment of inertia (the distance from the center of mass squared).
The last Snowmans mass properties are set up manually. After constructing the compound, we set the mass and center of mass. For the moments of inertia, which tell us ‘how much resistance there is to change the orientation about an axis’, we use rough values which create the desired behavior (of course, for real you would integrate the moments properly!). The Snowman shall wobble back and forth only, which is around the X axis in this case. The resulting tensor diagonal values will have a small value in X, and high values in Y and Z: There is small resistance to rotate about X, but a high resistance to rotate about Y and Z.

 



PhysX3 User Guide 03 - Joint

Posted on 2011-06-02 16:28 mumuliang 阅读(1798) 评论(1) 编辑 收藏
 1 Joint Creation  
Joint提供了一种联系俩Actor的途径。典型的例子如门上的合页,人物的肩膀。.

创建Joint的方法:
PxRevoluteJointCreate(PxPhysics& physics,
                      PxRigidActor* actor0, const PxTransform& localFrame0,
                      PxRigidActor* actor1, const PxTransform& localFrame1);

必须有一个Actor可以动,是PxRigidDynamic,要不就是PxArticulationLink. 另一个Actor无所谓。

localFrame参数表示Actor的相对PxTransform,包括位置和姿态,position and orientation. 上面的例子是一个revolute joint,localFrame须指定原点和旋转轴。

PhysX提供了6中Joint:
    1. 固定。不能相对运动。a fixed joint locks the orientations and origins rigidly together 
    2. 距离。Actor之间像栓了绳子。a distance joint keeps the origins within a certain distance range 
    3. 球体。原点重合,姿态自由。a spherical joint (sometimes known as as a ball-and-socket) keeps the origins together, but allows the orientations to vary freely. 
    4. 开阖。门的合页那样的。a revolute joint (often referred to as a hinge) keeps the origins and x-axes of the frames together, and allows free rotation around this common axis. 
    5. 截面。移门那样的。a prismatic joint keeps the orientations identical, but allows the origin of one actor to slide freely along the line defined by the origin and x-axis of the other. This kind of joint models a sliding door. 
    6. D6。高度自定义的一类,可以高度自由也可以高度固定。a D6 joint is a highly configurable joint that allows specification of individual degrees of freedom either to move freely or be locked together. It can be used to implement a wide variety of mechanical and anatomical joints, but is somewhat less intuitive to configure than the other joint types. 
    应用程序可以添加向框架添加新的Joint扩展现有类型。

    Note: PhysX中的角度是以弧度为单位。

     2 Beyond the Basics  

     

      Visualization  
    所有PhysX的标准joints都支持debug visualization.因此..

    但 joint本身是不可见的. 为使其可见, 要将设置其constraint flag为visualization,并改变场景的visualization parameters:
    scene->setVisualizationParameter(PxVisualizationParameter::eJOINT_FRAMES, 1.0f);
    scene->setVisualizationParameter(PxVisualizationParameter::eJOINT_LIMITS, 1.0f);

    ...

    joint->setConstraintFlag(PxConstraintFlag::eVISUALIZATION)

      Force Reporting  
    Jonit连接的Actor每帧都要保存连接它俩的force的信息。通过设置reporting constraint flag启用该功能,然后就可以用Joint对象的getForce方法获得force信息。
    joint->setConstraintFlag(PxConstraintFlag::eREPORTING)
    ...

    scene->fetchResults(...)
    joint->getForce(force, torque);

    The force is resolved at the origin of actor1’s joint frame.

      Breakage  
    PhysX的标准joint都是可以被掰开的breakable. 可以定义这个临界force和torgue。 joint被掰开会引发一个simulate event(参看PxSimulationEventCallback::onJointBreak), 这个joint尽管可能仍然存在与场景中,但也不再参与运算。

    但joint默认是不可掰开的。开启该属性,方法如下,首先设置一个临界force和torgue,然后设置breakable constraint flag为true。
    joint->setBreakForce(100.0f100.0f);
    joint->setConstraintFlag(PxConstraintFlag::eBREAKABLE, true);

      Projection  
    Under stressful conditions, PhysX’ dynamics solver may not be able to accurately enforce the constraints specified by the joint. For joints where this is problematic you can enable kinematic projection, which tries to bring violated constraints back into alignment. Projection is not a physical process and doesn’t preserve momentum or respect collision geometry. It should be avoided where practical, but it can be useful in improving simulation quality where joint separation results in unacceptable artifacts.(这段很迷糊)

    在突发情况(有外力情况?)下,PhysX 的dynamics slover(dynamic物体的计算器?)可能会没办法正确操作joint定义的Actor之间约束关系。这显然不太妙。你可以启用kinematic projection(运动投影?),它会尝试纠正。但Projection并非物理过程,它不会遵守动量守恒也不会管图形是否碰撞。实际应用中应该避免使用projection,但它在改善什么什么效果时很有用。-_-b

    projection也是默认不可用的。启用方法如下,首先设置会引起joint被project的临界linear tolerance和angular tolerance,然后开启那啥constraint flag.

    joint->setProjectionLinearTolerance(0.1f);
    joint->setConstraintFlag(PxConstraintFlag::ePROJECTION, true);

    Very small tolerance values for projection may result in jittering around the joint.

      Limits  
    joint限制相关的Actor如何旋转或只能沿某方向平移,同时可进一步设置这种可旋转和可移动的范围。例如revolute joint,合页关节,默认是绕轴的任意角度的旋转,如果需要,你可以开启limit,然后定义个旋转的最大角度和最小角度。

    Limits可以看做collision碰撞的一种。stable limit需要定义最大最小距离,和一个tolerance。blabla..要说的是limit的模拟开销是很昂贵的。

    设置limit要配置limit的geometry,然后设置joint的limit flag为true。
    revolute->setLimit(PxJointLimitPair(-PxPi/4, PxPi/40.1f)); // upper, lower, tolerance
    revolute->setRevoluteJointFlag(PxRevoluteJointFlag::eLIMIT_ENABLED, true);

    Limit可硬可软。硬就是让joint的运动立刻停下来,如果这是limit被设置为non-zero restitution,会被弹回。软的就是有阻尼效果。默认的limit是不会回弹的hard。

    Note: Limits are not projected.

      Actuation  
    有些joint是被spring和motor驱动的。这种模拟的开销比简单用force驱动的要大,它要求有更多的 stable control ,更多细节参看D6和revolute joint的文档。

    Note: The force generated by actuation is not included in the force reported by the solver, nor does it contribute towards exceeding the joint’s breakage force threshold.

      3 Fixed Joint  
    image:: ../images/fixedJoint.png

    The fixed joint has no additional characteristics.

      4 Spherical Joint  
    image:: ../images/sphericalJoint.png

    A spherical joint constrains a point on each actor to be coincident.

    The spherical joint supports a cone limit, which constrains the direction of the x-axis of actor1’s constraint frame. The axis of the limit cone is the x-axis of actor0’s constraint frame, and the allowed limit values are the maximum rotation around the the y- and z- axes of that frame. Different values for the y- and z- axes may be specified, in which case the limit takes the form of an elliptical angular cone:
    joint->setLimitCone(PxJointLimitCone(PxPi/2, PxPi/60.01f);
    joint->setSphericalJointFlag(PxSphericalJointFlag::eLIMIT_ENABLED, true);

    Note that very small or highly elliptical limit cones may result in solver jitter.

    Note Visualization of the limit surface can help considerably in understanding its shape.

      5 Revolute Joint  
    image:: ../images/revoluteJoint.png

    A revolute joint removes all but a single rotational degree of freedom from two objects. The axis along which the two bodies may rotate is specified by the common origin of the joint frames and their common x-axis. In theory, all origin points along the axis of rotation are equivalent, but simulation stability is best in practice when the point is near where the bodies are closest.

    The joint supports a rotational limit with upper and lower extents. The angle is zero where the y- and z- axes of the joint frames are coincident, and increases moving from the y-axis towards the z-axis:
    joint->setLimit(PxJointLimitPair(-PxPi/4, PxPi/40.01f);
    joint->setRevoluteJointFlag(PxRevoluteJointFlag::eLIMIT_ENABLED, true);

    The joint also supports a motor which drives the relative angular velocity of the two actors towards a user-specified target velocity. The magnitude of the force applied by the motor may be limited to a specified maximum:
    joint->setDriveVelocity(10.0f);
    joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, true);

    By default, when the angular velocity at the joint exceeds the target velocity the motor acts as a brake; a freespin flag disables this braking behavior

      6 Prismatic Joint  
    image:: ../images/prismaticJoint.png

    A prismatic joint prevents all rotational motion, but allows the origin of actor1’s constraint frame to move freely along the x-axis of actor0’s constraint frame. The primatic joint supports a single limit with upper and lower bounds on the distance between the two constraint frames’ origin points:
    joint->setLimit(PxJointLimitPair(-10.0f20.0f0.01f);
    joint->setPrismaticJointFlag(PxPrismaticJointFlag::eLIMIT_ENABLED, true);

      7 Distance Joint  
    image:: ../images/distanceJoint.png

    The distance joint keeps the origins of the constraint frames within a certain range of distance. The range may have both upper and lower bounds, which are enabled separately by flags:
    joint->setMaxDistance(10.0f);
    joint->setDistanceJointFlag(eMAX_DISTANCE_ENABLED, true);

    In addition, when the joint reaches the limits of its range motion beyond this distance may either be entirely prevented by the solver, or pushed back towards its range with an implicit spring, for which spring and damping paramters may be specified.

      8 D6 Joint  
      Locking and Unlocking Axes  
    D6是最复杂的标准Joint. 它默认表现的像fixed Joint,两个物体像黏在一起一样运动。但使用Joint的setMotion方法,你可以设置允许旋转和平移。
    d6joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);

    如果设置了平移自由translational degrees of freedom,即允许actor1的原点沿着actor0的constraint frame定义的轴移动。

    旋转自由Rotational degrees of freedom分为两种:扭twist (around the x-axis of actor0’s constraint frame);和摆 swing (around the y- and z- axes.) 通过控制twist和swing参数的开关,可以得到很多效果:
    1. if just a single degree of angular freedom is unlocked, the result is always equivalent to a revolute joint. It is recommended that if just one angular freedom is unlocked, it should be the twist degree, because the joint has various configuration options and optimizations that are designed for this case. 
    2. if both swing degrees of freedom are unlocked but the twist degree remains locked, the result is a zero-twist joint. The x-axis of actor1 swings freely away from the x-axis of actor0 but twists to minimize the rotation required to align the two frames. This creates a kind of isotropic universal joint which avoids the problems of the usual ‘engineering style’ universal joint (see below) that is sometimes used as a kind of twist constraint. There is a nasty singularity at π radians (180 degrees) swing, so a swing limit should be used to avoid the singularity. 
    3. if one swing and one twist degree of freedom are unlocked but the remaining swing is kept locked, a zero-swing joint results (often also called a universal joint.) If for example the SWING1 (y-axis rotation) is unlocked, the x-axis of actor1 is constrained to remain orthogonal to the z-axis of actor0. In character applications, this joint can be used to model an elbow swing joint incorporating the twist freedom of the lower arm or a knee swing joint incorporating the twist freedom of the lower leg. In vehicle applications, these joints can be used as ‘steered wheel’ joints in which the child actor is the wheel, free to rotate about its twist axis, while the free swing axis in the parent acts as the steering axis. Care must be taken with this combination because of anisotropic behavior and singularities (beware the dreaded gimbal lock) at angles of π/2 radians (90 degrees), making the zero-twist joint a better behaved alternative for most use cases. 
    4. if all three angular degrees are unlocked, the result is equivalent to a spherical joint. 
      有三种PhysX2的joint在physX3已经木有了,但你可以酱来实现他们。

      • The cylindrical joint (with axis along the common x-axis of the two constraint frames) is given by the combination:
      d6joint->setMotion(PxD6Axis::eX,     PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
      • the point-on-plane joint (with plane axis along the x-axis of actor0’s constraint frame) is given by the combination:
      d6joint->setMotion(PxD6Axis::eY,      PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eZ,      PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eTWIST,  PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
      • the point-on-line joint (with axis along the x-axis of actor0’s constraint frame) is given by the combination:
      d6joint->setMotion(PxD6Axis::eX,      PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eTWIST,  PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);

        Limits  
      除了可以定义轴是自由还是锁定( axis is free or locked), 还可以定义其受限范围limit. D6有三种limit,并且可以组合使用。

      A single linear limit with only an upper bound is used to constrain any of the translational degrees of freedom. The limit constrains the distance between the origins of the constraint frames when projected onto these axes. For example, the combination:
      d6joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eY, PxD6Motion::eLIMITED);
      d6joint->setMotion(PxD6Axis::eZ, PxD6Motion::eLIMITED);
      d6joint->setLinearLimit(PxJointLimit(1.0f0.1f));

      constrains the y- and z- coordinates of actor1’s constraint frame to lie within the unit disc. Since the x-axis is unconstrained, the effect is to constrain the origin of actor1’s constraint frame to lie within a cylinder of radius 1 extending along the x-axis of actor0’s constraint frame.

      The twist degree of freedom is limited by a pair limit with upper and lower bounds, identical to the limit of the revolute joint.

      If both swing degrees of freedom are limited, a limit cone is generated, identical to the limit of the spherical joint. As with the spherical joint, very small or highly elliptical limit cones may result in solver jitter.

      If only one swing degree of freedom is limited, the corresponding angle from the cone limit is used to limit rotation. If the other swing degree is locked, the maximum value of the limit is π radians (180 degrees). If the other swing degree is free, the maximum value of the limit is π/2 radians (90 degrees.)

        Drives  
      D6有1个linear drive model, 和2个angular drive models. The drive is a proportional derivative drive, which applies a force as follows:

      force = spring * (targetPosition - position) + damping * (targetVelocity - velocity)

      The drive model 也可以代替force用来引起加速。Acceleration drive 调整比force drive要容易些。

      linear drive model 有如下参数: 
      • 目标位置,在actor0的constraint frame中定义。target position, specified in actor0’s constraint frame 
      • 目标速度,也定义在actor0的constraint frame中。target velocity, specified in actor0’s constraint frame 
      • 弹性?spring 
      • 阻尼。damping 
      • 能提供的最大力。forceLimit - the maximum force the drive can apply 
      • 加速标志。acceleration drive flag 
      它会以设置的阻尼和倔强系数stiffness?往目标位置运动。A physical lag due to the inertia of the driven body acting through the drive spring will occur; therefore, sudden step changes will result over a number of time steps. Physical lag can be reduced by stiffening the spring or supplying a velocity target.

      如果位置固定目标速度为0, a position drive will spring about that drive position with the specified springing/damping characteristics:
      复制代码
      // set all translational degrees free

      d6joint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eY, PxD6Motion::eFREE);
      d6joint->setMotion(PxD6Axis::eZ, PxD6Motion::eFREE);

      // set all translation degrees driven:

      PxD6Drive drive(10.0f, -20.0f, PX_MAX_F32, true);
      d6joint->setDrive(PxD6JointDrive::eX, drive);
      d6joint->setDrive(PxD6JointDrive::eY, drive);
      d6joint->setDrive(PxD6JointDrive::eZ, drive);

      //Drive the joint to the local(actor[0]) origin - since no angular dofs are free, the angular part of the transform is ignored

      d6joint->setDrivePosition(PxTransform::createIdentity());
      d6joint->setDriveVelocity(PxVec3::createZero());
      复制代码

      Angular drive和linear drive完全不同,angular drive木有一种简单直接的方式用以描述它相对于奇点(singularities)是怎么自由运动的, 因此D6 joint提供了两种angular drive models——扭摆 和 球面插值SLERP (Spherical Linear Interpolation).

      这俩angular drive model最大的区别在于他们使用四元数的方式。SLERP中直接使用四元数,扭摆模型里面会吧四元数分解成blabla. 扭摆模型多数情况下的行为都是比较一致的,但要注意180度的摆动,这时候actor并不会沿着两个角度之间的最短弧线运动(球体表面的最短路径). SLERP模型总是会让actor沿着最短对角弧运动。

      只有有任何一个方向的角度不能改变, SLERP drive 参数就会被忽略。当所有方向上都是角度自由,and parameters are set for multiple angular drives, the SLERP parameters will be used.

      The angular drive model has the following parameters:
      • 角速度,定义在actor0的constraint frame。An angular velocity target specified relative to actor0’s constraint frame 
      • 目标姿态。定义在同上。An orientation target specified relative to actor0’s constraint frame 
      • SLERP或扭摆drive的配置。drive specifications for SLERP (slerpDrive), swing (swingDrive) and twist (twistDrive): 
      • 弹性。spring - amount of torque needed to move the joint to its target orientation proportional to the angle from the target (not used for a velocity drive). 
      • 阻尼。damping - applied to the drive spring (used to smooth out oscillations about the drive target). 
      • 那啥。forceLimit - maximum torque applied when driving towards a velocity target (not used for an orientation drive) 
      • 那啥。acceleration drive flag 
      Best results will be achieved when the drive target inputs are consistent with the joint freedom and limit constraints. 


      PhysX3 User Guide 04 - Rigid Body Dynamics

      Posted on 2011-06-03 16:06 mumuliang 阅读(1349) 评论(0) 编辑 收藏
      本章涉及了了不少模拟刚体物体必须了解的点。

        Applying Forces and Torques     

      物理学上和物体交互的方式常是对其施以外力。在经典力学中,很多物体之间的交互都是采用力来求解。因为力遵守如下法则:

      f = m*a (force = mass * acceleration) 力= 质量*加速度 0-0

       

      力直接控制物体的加速度,间接影响其位置和速度。因此,如果你需要立刻获得反应的话,使用力Force可能不太方便。力的好处是无需考虑场景中受力物体Body的情况,模拟程序会计算定义所有的约束条件。重力就是这么干的。

      不幸的是,大量力会导致共振,使速度越来越大,最后系统solver因为无法maintain the joint constraints而崩溃。不像现实世界,joint break就是了。(joint的breakable打开也不行么?)

      同一模拟帧内的力可以累加的,下一帧会全部置零。你可以设置力和力矩torque。PxRigidBodyPxRigidBodyExt中的相关函数如下. 

       

      复制代码
      void PxRigidBody::addForce(const PxVec3& force, PxForceMode::Enum mode, bool autowake);
      void PxRigidBody::addTorque(const PxVec3& torque, PxForceMode::Enum mode, bool autowake);
      void PxRigidBodyExt::addForceAtPos(PxRigidBody& body, const PxVec3& force, const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);
      void PxRigidBodyExt::addForceAtLocalPos(PxRigidBody& body, const PxVec3& force, const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);
      void PxRigidBodyExt::addLocalForceAtPos(PxRigidBody& body, const PxVec3& force, const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);
      void PxRigidBodyExt::addLocalForceAtLocalPos(PxRigidBody& body, const PxVec3& force, const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);
      复制代码

       

      PxForceMode 默认为PxForceMode::eFORCE 。除此以外的可能值有:PxForceMode::eIMPULSEs, impulsive force. PxForceMode::eVELOCITY_CHANGE 会无视物体的质量...更多信息查看API手册中的PxForceMode章节.

        Gravity     

      重力是最常用的。如果需要在整个场景内都使用重力效果,使用PxScene类的setGravity()进行设置。

      使用米和秒为单位的话,重力值为9.8,方向为场景的竖直向下。

      某些效果可能要求一些dynamic actor暂时不受重力影响(真想不出是啥时候啥情况),你可以这么干:

      PxActor::setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true);

       

      Note: 改变重力效果的时候要严重当心。记得要手动恢复失重的物体,用PxRigidDynamic::wakeUp()。因为系统如果要自动唤醒失重物体的话,势必遍历场景中的所有物体,性能不佳。.

          Setting the Velocity     

      如果是想立刻让一个物体运动,给它初速度是最直接的。还有个更直接的办法是设动量momentum,如果你不知道物体的质量的话,这种方法可能更方便, 只是要知道速度的话还得要质量。


      场景中设了初速度的物体, 你可能会遇到在第一帧结束以后速度就没了的情况。这是因为如果这个初速度和其他什么constraint冲突的话,就会被simulation以其他的设置重写。例如,如果一个球静止在桌子上,同时给了它一个向下的初速度,那么这个初速度就会,变成0. 如果给链条上某链节一个初速度,这个链节上的初速度会减小,其他链节的初速度会增大,以保证所有链节仍然连接在一起.

      初速度的设置方法简单的说,如下:

       

      void PxRigidBody::setLinearVelocity(const PxVec3& linVel, bool autowake);
      void PxRigidBody::setAngularVelocity(const PxVec3& angVel, bool autowake);

         Kinematic Actors       

      dynamic Actor受力force影响,也受冲量impulse影响。通常俺们用PxRigidBody::addForce()PxRigidBody::addTorque()函数的时候,用这俩枚举量PxForceMode::eIMPULSE ,PxForceMode::eFORCE 对其设置. 但是这些都是在以二手或者三手方式在控制actor,不够灵活。例如当想要移动舞台和角色的时候,直接改变它们的Actor的位置Position是最直接的。kinematic Acotor就提供了这样一种一手方式.

      使用PxRigidDynamic::moveKinematic()可以尽情操作kinematic Actor. 除了这个函数Kinematic Actor对不管是力,重力,碰撞啥的,都不起反应。这条命令先被暂存起来,当内部的simulate完成后,它会计算出一个速度,然后在本帧内以该速度向目标位置移动,本帧内的这一步移动完成后,速度会被归零。因此需要在反复调用该函数才能完成沿着某路径运动的效果。也就是在移动过程中,kinematic actor表现得像是质量为无穷大,因此总是马上停下来.

      创建kinematic actor的方法只是在创建一个普通dynamic actor之后打开它的kinematic flag:
      PxRigidDynamic* rigidDynamic;
      rigidDynamic->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true);


      只要把这个kinematic flag关闭,actor就又变成一个普通的dynamic actor. 如果你向一堆dynamic中的一个kinematic增加mass时,其实mass并没有增加,因为这个mass被用在了kinematic上,相当于沧海一粟,这一堆dynamic的总mass也不会变化。

      附加说明:

      • 注意 PxRigidDynamic::moveKinematic() PxRigidBody::setGlobalPose() 的区别. setGlobalPose()也会将Actor移动到指定位置,但不会引起其他对象的变化。尤其是,它根本不会阻挡别的物体运动,而是会穿墙而过。但这个setGlobalPose()还是会被用到, 如果仅仅是想把某个东西移动到某个位置时。. 
      • kinematic actor是会推开别人的,如果有人挡道的话,但是其他物体不会反作用于kinematic物体。也就是说kinematic actor的出现,让其他dynamic actor表现为static actor或者kinematic actor. 譬如,一个dynamic豆腐会把冲过来的kinematic脑袋撞个坑?。
      • kinematic 和 static actor之间木有相互作用和碰撞。 

       

         Sleeping    

      actor若持续一段时间木有动作, 可以看做将来它也不会再动作,除非再受到了外力。因此在下一次受到外力之前,它都不必参与simulate.这种状态就是Sleeping. 查询一个物体是不是睡了可以酱:

       

      bool PxRigidDynamic::isSleeping();

      actor的动能kinematic energy低于某个值的话就会进入睡眠状态。这个门槛值可这样设置:

       

      void PxRigidDynamic::setSleepEnergyThreshold(PxReal threshold);
      PxReal PxRigidDynamic::getSleepEnergyThreshold() const;

      一个沉睡物体的醒来是因为有其他醒着的物体touch了它,或者它的什么属性发生了变化,睡还是没睡通常不应该是应用程序关心的问题,也不必。但如果非要人肉改变睡还是不睡,也不是没有办法:

       

      void PxRigidDynamic::wakeUp(PxReal wakeCounterValue=PX_SLEEP_INTERVAL);
      void PxRigidDynamic::putToSleep();

      但是,也有一些特殊情况要求用户必须手动唤醒Sleeping actor。哪些函数有这样的要求,API参考文档有详情。

          Solver Accuracy     

      求解器精确度。当刚体rigid body的运动受到关节jount或和其他物体的接触contract的约束时,约束求解器constraint solver就会自动运行。求解器为了满足所有的约束条件,会有限次遍历运动物体上的所有约束条件。这次数越大,求解的结果越精确越接近现实。默认是4个位置和1个速度的遍历(?!?!)。The solver iteration count defaults to 4 position iterations and 1 velocity iteration. 可以单独设置每个刚体物体的遍历次数:

       

      void PxRigidDynamic::setSolverIterationCounts(PxU32 minPositionIters, PxU32 minVelocityIters);

      眼目前俺们只发现了在一个关联了太多Joint并且这些joint的tolerance都很小的物体上才有必要把这个值设的比较大。如果该值需要设置到为30以上才能满足需求,基本上是整个模拟从根子上就有问题。

          Fast Rotation     

      像铅笔这样的长条形状的物体模拟起来比较有难度,因为它们绕短轴旋转时会存储大量能量,而后若绕长轴旋转会变成一个很大的角速度。这样会出问题,因为旋转运动中的某些线性逼近米有办法完成。因此PhysX SDK中限制了角速度的最大值。当然这个值也是可以修改的。

      void PxRigidDynamic::setMaxAngularVelocity(PxReal maxAngVel);


      PhysX3 User Guide 05 - Scene Queries

      Posted on 2011-06-04 16:26 mumuliang 阅读(1030) 评论(3) 编辑 收藏

      有两种方式查询场景中的碰撞collision:批处理batched和非批处理non-batched。非批处理查询又称single shot queries,使用PxScene类的接口,是PxScene的一项常规功能。批处理查询是使用PxBatchQuery对象,PS3上只有批处理查询一种方式。

       

          Raycast queries      



      查询中用户定义的射线ray会与整个场景相交intersected with the whole scene。PhysX有三种射线:

      • raycastAny
      • raycastSingle
      • raycastMultiple

       

      查询碰撞collision时,返回的最主要的信息是一个布尔是非值,表示碰没碰上,若需获取更多信息,比如射线是不是穿过了什么之类的,就可以用raycastAny。至于交点的确切信息、相交的是个啥形状,这些都不是raycastAny关心的内容,它只关心一件事,是不是有击中发生(there was a hit)。人工智能中的视线查询(line-of-sight queries)就是一个典型应用。

       

      raycastSingleraycastAny先进一些,通过它可以知道第一个被击中的是个嘛。譬如说子弹击中的情形。

       

      raycastMultiple是最高级的。ray会hit到的所有物体都可以得到。好比说穿甲子弹。

       

      注意:* solid物体(sphere, capsule, box, convex)是封闭的closed(即它们包括它们的边界boundaries)

              * plane是封闭的半空间 closed halfspace

              * heightfield也是封闭的,并且是solid物体。 

       

      射线投射在solid物体上,射线是有终点的。射线ray和solid物体的相交intersection会引发一个击中报告hit report。

       

      下表显示了不同物体对射线是否会产生hit report报告的反应是不同的。比如只要起点位于plane内部,即平面以下,无论射线终点在哪儿,也不会有plane被hit的report返回。

        

           Sweep Queries     


       

      Queries中Shape会以一指定的方向扫sweep过去,并报告是否与场景Scene有碰撞collision。也有三种sweep方式:

      • sweepAny
      • sweepSingle
      • sweepMultiple

       

       

      它们的区别也和3种ray之间的区别一样。 

      目前支持sweep的形状Shape有box, sphere和capsule。

       

          Overlap Queries     


       

      overlap query返回的是和场景发生碰撞的物体所接触到的其他物体。有两种overlap

      • overapAny 
      • overlapMultiple

       

       

      overlapAny 也叫placement API,特别适用于只知道场景的体积是不是空的情况。

       

      overlapMultiple并不会在第一次hit后停下来,而是会返回其后所有被碰到的物体。

       

      没有overlapSingle,因为没必要。overlap并没固定一个具体的方向,因此也就不能得到某个方向上的最近或最远,因此single木有存在的意义。(难道时间上也木有排序的意义么?)

       

      overlap接受box,sphere和capsule三种形状。

       

          Filtering     


       

      有几种方法可以把场景中不需要的Shape过滤掉。query与filter有关的参数有:

      • 结构体PxSceneQueryFilterData,包括PxSceneQueryFilterFlagsPxFilterData
      • PxSceneQueryFilterCallback选项

       

       

      这些灵活多变的filter机制允许用户锁心所欲的自定义过滤行为。俺们来看几个例子:

       

      首先PxSceneQueryFilterFlag::eSTATIC PxSceneQueryFilterFlag::eDYNAMIC 标志提供了第一层过滤。它们表示query是针对场景中的static还是dynamic对象。如果想query全部static或dynamic对象时,这显然比一个一个往filtering callback中加对象要方便。例如,爆炸效果可以球体的overlapMultiple来扫全场景中的dynamic对象(打开PxSceneQueryFilterFlag::eDYNAMIC标志),对static对象只需要给他们加个外力什么的就可以了。

       

      第二个层次上的过滤由PxFilterData提供,它是一个128位的掩码。query会拿shape的掩码跟自己比较,通过才将shape纳入本次query。shape通过的情况有两种:1,query的掩码为零;2,shape的掩码和query的掩码按位与的结果非零(其实非零即等于掩码,掩码通常是只有1位为1)。

       

      filter callback可以建立更灵活的过滤规则。filter callback需实现PxSceneQueryFilterCallback后传给query。然后场景查询可以在需要时调用其。调用时机可能是计算碰撞前也可能是其后,视实际情况。当然在计算之前就决定是不是要丢弃shape的开销是要小一些,但有时候计算以后的结果是你的判断条件之一。设置callback调用时机使用这俩filter标志:PxSceneQueryFilterFlag::ePREFILTERPxSceneQueryFilterFlag::ePOSTFILTER .

       

      filter callback会返回一个PxSceneQueryHitType 。该值可能为:

      • eNONE,表示shape不许参与后面的query处理。
      • eBLOCK,表示shape是hit最终结束在的物体blocking hit,凡是比该shape更远的shape都不必参与query。(从后文来看该shape并没有被过滤掉,仍然是参与query的。)
      • eTOUCH,表示shape是一个touching hit,参与query处理,除非后续filter callback给它过滤掉了。 

       

       

      eNONEeBLOCK比较简单。NONE就丢弃shape不参与query,BLOCK就将shape加入query。eTOUCH是新增加的值,为了处理像子弹穿过窗户(打碎窗户但继续向前)这样的情形。显而易见eTOUCH只对造成Multiple hits的query有效。

       

          Caching      


       

      PxSceneQueryCache 可以用来加速某些情况下的query,尤其是raycastAny, raycastSinglesweepSingle .它的工作方式是:在缓存中定义了一些shape,甚至三角面(三角面和shape都会被首先测试)。高度时序性的query会因此得到显著的效率提升。解决这类时序问题的一个好方法是将上一帧的query结果放在query缓存对象中。

       

      例如,人工智能的可见度query很可能连续几帧都返回同一个遮挡物blocking shape。那俺们就可以给到这个raycastAny(视线的query常用racycatAny,前面有讲)一个恰当的PxSceneQueryCache,然后呢,query会在检查其他shape之前就马上发现它hit了缓存中的这个shape,然后query就返回了。

       

      再譬如,在缓存中存放上一次的closest hit,这会大大提高query查找closest hit的效率。

       

       

          Batched Queries     


       

      批查询使用的是PxPatchQuery对象的接口。 顾名思义,就是可以把多个Query组合在一起,然后一次执行(调用PxBatchQuery::execute())。批查询基本上和非批查询是一样的。他俩的区别主要是:

      • PS3的SPUs只能跑批查询
      • 硬编码的过滤方程(hardcoded filtering equation) 不能用于批查询。取而代之的是两个filter shader:PxBatchQueryPreFilterShader 和 PxBatchQueryPostFilterShader

       

      查询结果先写入PxPatchQueryDesc中用户指定的缓冲区,后以同样的顺序输出到PxPatchQuery对象。



      PhysX3 User Guide 06 - Callbacks and Customization

      Posted on 2011-06-04 18:49 mumuliang 阅读(1235) 评论(1) 编辑 收藏
      本章俺们要看看SDK提供了哪些函数用来监听模拟事件和自定义部分模拟行为。回调函数需在用户使用的继承类中实现。这和第一章谈到的自定义分配操作allocator和错误提示error notification所使用的机制是一样的。

          Simulation Events     


      事件是最简单的模拟回调。程序可以只监听而不做反应。用户在callback中添加的代码只有一个问题:你未必能如愿修改SDK中的状态!(only one restriction? -_-b)后台进行物理模拟时,也可以进行写操作——这有点意外吧,因为SDK都是双缓冲形式的,新状态都是写入了非活动状态的后缓冲中。但是,event是在fetchResults()内部被调用的而不是在模拟线程simulation thread,这就有可能后缓冲中有些操作在模拟线程中已经做过了。将来的升级版本可能会基于单个事件在此问题上做一些改进,但目前还是只有先把需要作为事件结果返回的写操作缓存起来,并且在fetchResult()返回后执行。(糊里糊涂的#v#)


      fetchResults()内部,交换缓存(意味着物体的模拟结果API可见了)的动作并不是在最初或最后,而是在一系列操作的中间,也就是说事件回调被分成了发生在缓存交换之前和之后两种情况。在之前的有
      • onTrigger 
      • onContactNotify 
      • onConstraintBreak 
      收到这些事件event的时候 ,物体的形状Shape、角色Actor等仍然保持模拟simulate之前的状态。这样是对的。因为这些事件的检测本应在模拟之前。例如,一对引发了onContactNotify()的shape,即使在fetchResult()之后它们可能是被弹开了,但他们也的确那啥了。

       

      位于交换缓存之后的事件有:
      • onSleep 
      • onWake 
      Sleep information is updated after objects have been integrated, so that it makes sense to send these events after the swap.


      监听事件有两步:1,写一个继承于 PxSimulationEventCallback的子类,定义需要的回调函数。对Sleep/Wake事件或是约束破坏事件constraint break event, 这是唯一的一个步骤。 


      2,onContactNotify 和 onTrigger 事件,还需要在filter shader callback为需要接受该事件的物体设置一个标志。下一节collision filtering会细说。


      这是SampleSubmarine工程中的使用contact notify function的例子:

      复制代码
      void SampleSubmarine::onContactNotify(PxContactPair& pair, PxU32 events)
      {
              if(events & PxPairFlag::eNOTIFY_TOUCH_FOUND)
              {
                      if((pair.actors[0] == mSubmarineActor) || (pair.actors[1] == mSubmarineActor))
                      {
                              PxActor* otherActor = (mSubmarineActor == pair.actors[0]) ? pair.actors[1] : pair.actors[0];
                              Seamine* mine =  reinterpret_cast<Seamine*>(otherActor->userData);
                              // insert only once
                              if(std::find(mMinesToExplode.begin(), mMinesToExplode.end(), mine) == mMinesToExplode.end())
                                      mMinesToExplode.push_back(mine);
                      }
              }
      }
      复制代码

      SampleSubmarine 是 PxContactNotifyCallback 的子类. onContactNotify 方法接收一个contract pair的事件掩码. 上面的函数只处理了eNOTIFY_TOUCH_FOUND事件。事实上它只关心潜艇的这个事件. 然后它会假设第二个Actor是水雷(可能只激活了潜艇和地雷的contact report). 然后它把这个地雷添加到一组下一次会爆炸的地雷里面。

          Collision Filtering     


      几乎所有实际应用中,都需要设置不计算某些相互作用的物体,或者让SDK以某种特殊的方式进行冲突检测。在潜水艇的例程中,如上文说道的,需要在潜水艇touch到了一个水雷或水雷链的时候得到通知be notified,以便引爆它们。再有,钳爪AI也需要知道它是不碰touch到了heightfield。


      在理解例程是咋做的之前,有必要先了解一下SDK的filter系统能做啥。因为潜在的作用对的filtering操作发生在模拟引擎最deepest(深奥?难懂?深入?)的部分,并且会作用于所有相互靠近的对象对,因此它表现的尤其sensitive。最简单的一种实现方法所有潜在的作用对都调用一个回调函数,在回调函数中,应用程序采用自定义的逻辑(例如查询游戏数据)来判断是否发生了相互作用,不过这种方法在游戏世界很大的情况下会很慢。特别是当冲突检测是由一个远程处理器(像是GPU或其他矢量处理器)在处理的时候,处理器不得不先挂起它的并行计算,中断游戏运行游戏代码的主处理器,并在再次运行游戏代码之前执行callback。即使是在CPU上,它这样做的同时很可能是运行在多核心或超线程上,所有的序列化代码都必须到位以确保能同时访问共享数据。使用可以在远程处理器上执行的固定的函数逻辑是比较好的方法。2.x中就是这么做的,但这个基于将过滤规则简单分组的规则不够灵活不足以满足所有应用,因此3.0中,使用了shader(开发者使用矢量处理器支持的代码实现任意filter规则,但因此无法访问内存中的数据)这种比2.x的固定函数filtering更灵活的方式,同时也支持filter shader调用CPU callback函数的机制(它能访问所有应用程序数据,以牺牲性能为代价)。详情见PxSimulationFilterCallback。最好的是应用程序可以基于作用对设置要速度还是灵活度。

      首先俺们看看shader system,SampleSubmarine中实现了一个filter shader 

      复制代码
      PxFilterFlags SampleSubmarineFilterShader(
              PxFilterObjectAttributes attributes0, PxFilterData filterData0,
              PxFilterObjectAttributes attributes1, PxFilterData filterData1,
              PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
      {
              // let triggers through
              if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
              {
                      pairFlags = PxPairFlag::eTRIGGER_DEFAULT | PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
                      return PxFilterFlag::eDEFAULT;
              }
              // generate contacts for all that were not filtered above
              pairFlags = PxPairFlag::eCONTACT_DEFAULT;

              // trigger the contact callback for pairs (A,B) where
              
      // the filtermask of A contains the ID of B and vice versa.
              if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
                      pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;

              return PxFilterFlag::eDEFAULT;
      }
      复制代码

      SampleSubmarineFilterShader 的shader函数很简单,实现了PxFiltering.h中的PxSimulationFilterShader 原型。shader filter 函数, SampleSubmarineFilterShader ,可能不能引用任何内存,除了它的参数和本地栈变量(非new的局部变量),因为它可能是被编译了运行在远程处理器上。

      SampleSubmarineFilterShader() will be called for all pairs of shapes that come near each other – more precisely: for all pairs of shapes whose axis aligned bounding boxes in world space are found to intersect for the first time. All behavior beyond that is determined by the what SampleSubmarineFilterShader() returns.

      The arguments of SampleSubmarineFilterShader() include PxFilterObjectAttributes and PxFilterData for the two shapes, and a constant block of memory. Note that the pointers to the two shapes are NOT passed, because those pointers refer to the computer’s main memory, and that may, as we said, not be available to the shader, so the pointer would not be very useful, as dereferencing them would likely cause a crash. PxFilterObjectAttributes and PxFilterData are intended to contain all the useful information that one could quickly glean from the pointers. PxFilterObjectAttributes are 32 bits of data, that encode the type of object: For example eRIGID_STATIC, eRIGID_DYNAMIC, or even ePARTICLE_SYSTEM. Additionally, it lets you find out if the object is kinematic, or a trigger.

      Each PxShape shape in PhysX has a member variable of type PxFilterData. This is 128 bits of user defined data that can be used to store application specific information related to collision filtering. This is the other variable that is passed to SampleSubmarineFilterShader() for each shape.

      There is also the constant block. This is a chunk of per-scene global information that the application can give to the shader to operate on. You will want to use this to encode rules about what to filter and what not.

      Finall, SampleSubmarineFilterShader() also has a PxPairFlags parameter. This is an output, like the return value PxFilterFlags, though used slightly differently. PxFilterFlags tells the SDK if it should ignore the pair for good (eKILL), ignore the pair while it is overlapping, but ask again, when it starts to overlap again (eSUPPRESS), or call the low performance but more flexible CPU callback if the shader can’t decide (eCALLBACK).

      PxPairFlags specifies additional flags that stand for actions that the simulation should take in the future for this pair. For example, eNOTIFY_TOUCH_FOUND means notify the user when the pair really starts to touch, not just potentially.

      Let’s look at what the above shader does:
      // let triggers through
      if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
      {
              pairFlags = PxPairFlag::eTRIGGER_DEFAULT | PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
              return PxFilterFlag::eDEFAULT;
      }

      This means that if either object is a trigger, then perform default trigger behavior (notify the application while touching each frame), and otherwise perform ‘default’ collision detection between them. The next lines are:
      复制代码
      // generate contacts for all that were not filtered above
      pairFlags = PxPairFlag::eCONTACT_DEFAULT;

      // trigger the contact callback for pairs (A,B) where
      // the filtermask of A contains the ID of B and vice versa.
      if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
              pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;

      return PxFilterFlag::eDEFAULT;
      复制代码

      This says that for all other objects, perform ‘default’ collision handling. In addition, if there is a rule based on the filterDatas that determines particular pairs where we ask for touch notifications. To understand what this means, we need to know the special meaning that the sample gives to the filterDatas.

      The needs of the sample are very basic, so we will use a very simple scheme to take care of it. The sample first gives named codes to the different object types using a custom enumeration:
      复制代码
      struct FilterGroup
      {
              enum Enum
              {
                      eSUBMARINE              = (1 << 0),
                      eMINE_HEAD              = (1 << 1),
                      eMINE_LINK              = (1 << 2),
                      eCRAB                   = (1 << 3),
                      eHEIGHTFIELD    = (1 << 4),
              };
      };
      复制代码

      The sample identifies each shape’s type by assigning its PxFilterData::word0 to this FilterGroup type. Then, it puts a bit mask that specifies each type of object that should generate a report when touched by an object of type word0 into word1. This could be done in the samples whenever a shape is created, but because shape creation is a bit encapsulated in SampleBase, it is done after the fact, using this function:
      复制代码
      void setupFiltering(PxRigidActor* actor, PxU32 filterGroup, PxU32 filterMask)
      {
              PxFilterData filterData;
              filterData.word0 = filterGroup; // word0 = own ID
              filterData.word1 = filterMask;  // word1 = ID mask to filter pairs that trigger a contact callback;
              const PxU32 numShapes = actor->getNbShapes();
              PxShape** shapes = new PxShape*[numShapes];
              actor->getShapes(shapes, numShapes);
              for(PxU32 i = 0; i < numShapes; i++)
              {
                      PxShape* shape = shapes[i];
                      shape->setSimulationFilterData(filterData);
              }
              delete [] shapes;
      }
      复制代码

      This sets up the PxFilterDatas of each shape belonging to the passed actor. Here are some examples how this is used in SampleSubmarine:
      setupFiltering(mSubmarineActor, FilterGroup::eSUBMARINE, FilterGroup::eMINE_HEAD | FilterGroup::eMINE_LINK);
      setupFiltering(link, FilterGroup::eMINE_LINK, FilterGroup::eSUBMARINE);
      setupFiltering(mineHead, FilterGroup::eMINE_HEAD, FilterGroup::eSUBMARINE);

      setupFiltering(heightField, FilterGroup::eHEIGHTFIELD, FilterGroup::eCRAB);
      setupFiltering(mCrabBody, FilterGroup::eCRAB, FilterGroup::eHEIGHTFIELD);

      This scheme is probably too simplistic to use in a real game, but it shows the basic usage of the filter shader, and it will ensure that SampleSubmarine::onContactNotify() is called for all interesting pairs.

      An alteriative group based filtering mechanism is provided with source in the extensions function PxDefaultSimulationFilterShader. And, again, if this shader based system is too inflexible for your needs in general, consider using the callback approach provided with PxSimulationFilterCallback.

          Contact Modification     

      Sometimes users would like to have special contact behavior. Some examples to implement sticky contacts, give objects the appearance of floating or swimming inside eachother, or making objects go through apparent holes in walls. A simple approach to achieve such effects is to let the user change the properties of contacts after they have been generated by collision detection, but before the contact solver. Because both of these steps occur within the scene simulate() function, a callback must be used.

      The callback occurs for all pairs of colliding shapes for which the user has specified the pair flag PxPairFlag::eMODIFY_CONTACTS in the filter shader.

      To listen to these modify callbacks, the user must derive from the class PxContactModifyCallback:
      class MyContactModification : public PxContactModifyCallback
              {
              ...
              void onContactModify(PxContactModifyPair *const pairs, PxU32 count);
              };

      And then implement the function onContactModify of PxContactModifyCallback:
      复制代码
      void MyContactModification::onContactModify(PxContactModifyPair *const pairs, PxU32 count)
      {
              for(PxU32 i=0; i<count; i++)
              {
                      ...
              }
      }
      复制代码

      Basically, every pair of shapes comes with an array of contact points, that have a number of properties that can be modified, such as position, contact normal, and separation. For the time being, friction properties of the contacts cannot be modified. Perhaps we will make this possible in future releases. See PxContactPoint and PxContactPointAux for properties that can be modified.

      There are a couple of special requirements for the callback due to the fact that it is coming from deep inside the SDK. In particular, the callback should be thread safe and reentrant. In other words, the SDK may call onContactModify() from any thread and it may be called concurrently (i.e., asked to process sets of contact modification pairs simultaneously).

      The contact modification callback can be set using the contactModifyCallback member of PxSceneDesc or the setContactModifyCallback() method of PxScene.

          Custom Constraints     

      Constraints like contact filtering, also uses shaders, for the same reason: There is a requirement to inject performance sensitive custom code into the SDK. Constraint is a more general term for joints. While joints were native objects of the PhysX 2.x API, PhysX 3.0 only supports a fully customizeable constraint object in the core API, and all 2.x joint types are implemented using this mechanism as extensions. Let’s take a short look at how this works. Once the reader understands, he will be in a good position to create his own joint types. You should read the chapter on joints before you try to understand their workings, however.

      When you call PxJointCreate(), the extensions library first fills out a PxConstraintDesc object, which is a bunch of parameters for constraint creation. Here is the code for a spherical joint:
      复制代码
      PxConstraintDesc nxDesc;
      nxDesc.actor[0]                         = desc.actor[0];
      nxDesc.actor[1]                         = desc.actor[1];
      nxDesc.flags                            = desc.constraintFlags;
      nxDesc.linearBreakImpulse       = desc.breakForce;
      nxDesc.angularBreakImpulse      = desc.breakTorque;

      nxDesc.solverPrep                       = SphericalJointSolverPrep;
      nxDesc.project                          = SphericalJointProject;
      nxDesc.visualize                        = SphericalJointVisualize;

      nxDesc.dataSize                         = sizeof(SphericalJointData);
      nxDesc.connector                        = joint->getConnector();
      复制代码

      The first few settings are self explanatory ... like the actors to connect, when the joint should break, and so on. The next three are three callback functions – user defined shaders! (See the section on filter shaders to find out what shaders are, and the rules that apply to them.) They contain the code that mathematically defines the behavior of the joint. Every time the joint needs to be solved, the simulation will call these functions.

      Finally, the ‘connector’ is a class of additional user defined joint specific functionality that are not called from the solver directly, and are not shaders.

      Lastly, the filled out descriptor is used to create a the constraint object:

      PxConstraint* constraint = physics.createConstraint(nxDesc);





      查看全文
      如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

      相关文章

      1. 目标检测之选择性搜索-Selective Search

        在基于深度学习的目标检测算法的综述 那一节中我们提到基于区域提名的目标检测中广泛使用的选择性搜索算法。并且该算法后来被应用到了R-CNN,SPP-Net,Fast R-CNN中。因此我认为还是有研究的必要。 传统的目标检测算法大多数以图像识别为基础。一般可以在图片上使用穷举法或者滑…...

        2024/5/6 5:37:59
      2. 游戏引擎架构----物理部分

        1. 碰撞检测系统物理世界形状&#xff1a;相交、接触&#xff08;分离矢量&#xff0c;沿该矢量运动就能高效脱离碰撞妆容&#xff09;、凸&#xff08;由形状内发射的光线不会穿越形状两次以上&#xff09; 原型&#xff1a;球体、胶囊体、轴对其包围盒AABB、定向包围盒OBB、…...

        2024/4/25 12:32:25
      3. 《Mars说光场》系列文章整理

        [导语&#xff1a;国内对光场&#xff08;Light Field&#xff09;技术的中文介绍十分匮乏&#xff0c;《Mars说光场》系列文章旨在对光场技术及其应用的科普介绍。] 光场技术是目前最受追捧的下一代显示技术&#xff0c;谷歌、Facebook、Magic Leap等国内外大公司都在大力布局…...

        2024/5/6 5:56:50
      4. 大学计算机图形考试题,大学CAD考试复习试题2017「附答案」

        大学CAD考试复习试题2017「附答案」一、选择题1、当图形中只有一个视口时&#xff0c; 【重生成】的功能与( )相同。B(A) 窗口缩放(B) 全部重生成(C) 实时平移(D) 重画2、在“缩放”工具栏中&#xff0c;共有( )种缩放工具。C(A) 10(B) 6(C) 8(D) 93、可以通过下面哪个系统变量…...

        2024/5/2 10:34:07
      5. 四轴小知识

        转载 1、惯性测量单元IMU(InertialMeasurement Unit) 姿态航向参考系统AHRS(Attitude and Heading Reference System) 地磁角速度重力MARG(Magnetic, Angular Rate, and Gravity) 微机电系统MEMS(Micro Electrical Mechanical Systems) 自由度维数DOF(Dimension Of Freedom) 无…...

        2024/4/21 14:46:10
      6. 坐标系统的详解-gis

        sf2gis163.com 2014年10月23日 2014年11月2日添加EPSG南北分带UTM 2014年12月3日添加Guass-Kruger分带计算 2014年12月4日添加等角投影 1 目的 地球是一个不规则球体&#xff0c;大地测量就是为了精确测量此球体及其表面的点位信息。 2 原理 球面坐标使用一个球体模型&…...

        2024/5/6 11:53:29
      7. 无人驾驶工程师学习笔记(三)——Canny边缘检测

        Throughout this Nanodegree Program, we will be using Python with OpenCV for computer vision work. OpenCV stands for Open-Source Computer Vision. 主页&#xff1a;https://opencv.org/ canny算法 边缘检测&#xff1a;识别图像中物体的边界&#xff0c;是opencv中的…...

        2024/4/21 14:46:09
      8. Open CASCADE基础介绍(1)

        Open CASCADE基础介绍&#xff08;1&#xff09; 一直在用OCC作项目&#xff0c;但这方面的中文资料很少&#xff0c;看来OCC在中国还不是十分普及&#xff1b; 后来&#xff0c;项目中使用OCC和DirectX结合使用&#xff0c;取得了很好的效果&#xff1b; 随着OCC6.3版本的推出…...

        2024/4/28 16:57:12
      9. H.266/VVC技术学习:帧内预测之PDPC技术

        1、PDPC介绍 为了补偿以上较简单帧内预测模式在利用空间冗余度方面的不足&#xff0c;VVC 中引入了一种根据当前样本的位置及帧内预测模式的角度自适应选取反方向角度上的参考样本信息作为新的一个相对互补性的帧内预测&#xff0c;然后将它和原有角度的帧内预测做基于样本距离…...

        2024/4/21 14:46:06
      10. 基于opencv的一种快速有效椭圆检测方法

        本篇介绍的椭圆检测方法来自以下论文&#xff0c;论文作者提供了测试代码。本文主要是对这个方法做出详解。 参考论文&#xff1a;A fast and effective ellipse detector for embedded vision applications 代码链接&#xff1a;fast_ellipse_detector 一、调用及参数说明 Siz…...

        2024/5/1 12:59:29
      11. (A-Softmax loss)SphereFace: Deep Hypersphere Embedding for Face Recognition

        https://arxiv.org/abs/1704.08063 https://github.com/wy1iu/sphereface. 摘要 本文研究了开放集协议下的深度人脸识别问题&#xff0c;在合适的度量空间下&#xff0c;理想人脸特征的最大类内距离要小于最小类间距离。然而&#xff0c;现有的算法很少能有效地达到这一标准。…...

        2024/5/6 11:55:04
      12. OpenCASCADE 基础

        OpenCASCADE 基础 转载▼ 一直在用OCC作项目&#xff0c;但这方面的中文资料很少&#xff0c;看来OCC在中国还不是十分普及&#xff1b; 后来&#xff0c;项目中使用OCC和DirectX结合使用&#xff0c;取得了很好的效果&#xff1b; 随着OCC6.3版本的推出&#xff0c;Open CASCA…...

        2024/5/1 1:19:58
      13. 游戏开发中的物理介绍

        游戏开发中的物理介绍碰撞对象物理过程回调碰撞层和蒙版GUI示例代码示例Area2DStaticBody2DRigidBody2DKinematicBody2D在游戏开发中&#xff0c;您通常需要知道游戏中的两个对象何时相交或接触。这就是所谓的碰撞检测。当检测到碰撞时&#xff0c;您通常希望发生某些事情。这就…...

        2024/4/21 14:46:04
      14. Android OpenGL ES-Cube Map

        Cube Map&#xff0c;中文可以翻译成立方环境映射&#xff0c;下面是摘自维基百科的说明&#xff1a; 立方反射映射是用立方映射使得物体看起来如同在反射周围环境的一项技术。通常&#xff0c;这通常使用户外渲染中使用的 skybox 完成。尽管由于反射物周围的物体无法在结果中…...

        2024/5/2 11:29:26
      15. 纯前端表格控件SpreadJS:新增数据透视表插件等,完美呈现强大的Excel数据分析能力

        SpreadJS 是一款基于 HTML5 的纯前端电子表格控件&#xff0c;兼容 450 种以上的 Excel 公式&#xff0c;凭借其 “高性能、跨平台、与 Excel 高度兼容”的产品特性&#xff0c;备受以华为、苏宁易购、天弘基金等为代表的企业用户青睐。 下载spreadjs最新版 四大理由让Spread…...

        2024/4/21 14:46:00
      16. RevitAPI之快速创建尺寸标注

        对于尺寸标注的创建&#xff0c;Revit API提供了以下方法来创建线性尺寸标注和对齐尺寸标注。1)创建线性尺寸标注• Autodesk. Revit. Creation. Document. NewDimension (View view, Line line, ReferenceArray references)其中&#xff0c;参数view是尺寸标注所要创建在的视图…...

        2024/4/21 14:46:00
      17. CSS3中的 Background linear gradient()用法

        本文参考自css only muti-color background如有兴趣的同学可以去看看这篇文章 这篇文章主要通过几个例子看看linear-gradient()的具体用法对linear-gradient的基础知识不做过多的介绍如有兴趣的同学可以出门左拐到mdn查看具体用法。ok话不多说让我们来看看awesome linear-gradi…...

        2024/4/28 22:43:21
      18. opencascade基础

        返回主页 大师之路 千淘万漉虽辛苦&#xff0c;吹尽狂沙始到金。 博客园 首页 新随笔 联系 管理 订阅订阅 随笔- 139 文章- 0 评论- 6 OpenCASCADE 基础 OpenCASCADE 基础 转载▼ 一直在用OCC作项目&#xff0c;但这方面的中文资料很少&#xff0c;看来OCC在中国还不是十分普及…...

        2024/5/1 17:01:35
      19. neo4j 两个点创建关系_Neo4j:找到两个纬度/经度之间的中间点

        neo4j 两个点创建关系昨天我写了一篇博客文章&#xff0c;展示了如何使用Cypher查找两个纬度/经度之间的中点&#xff0c;这是第一次尝试填补缺失位置时的效果&#xff0c;但是我意识到我可以做得更好。 正如我在上一篇文章中提到的&#xff0c;当我找到一个缺少经纬度坐标的停…...

        2024/4/23 2:07:29
      20. 双眼皮恢复两边不一样

        ...

        2024/4/27 14:12:15

      最新文章

      1. PHP 在字符中找出重复次数最多的字符

        我们定义一个变量&#xff1a; $str aaaaaabbbccdddddddddddddefg; 把字符串转为数组&#xff1a; $arr str_split($str); 统计数组中所有元素出现的次数&#xff0c;返回一个数组&#xff1a; $arr array_count_values($arr); 根据出现的次数&#xff0c;从大到小对数…...

        2024/5/6 15:17:15
      2. 梯度消失和梯度爆炸的一些处理方法

        在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

        2024/5/6 9:38:23
      3. Ubuntu磁盘扩容

        使用 df -h命令查看系统磁盘控件的使用情况&#xff1a; [samspobosrv:~]$ df -h Filesystem Size Used Avail Use% Mounted on udev 7.8G 0 7.8G 0% /dev tmpfs 1.6G 1.7M 1.…...

        2024/5/5 4:50:46
      4. 17、Lua 文件 I-O

        Lua 文件 I/O Lua 文件 I/O简单模式完全模式 Lua 文件 I/O LuaI/O 库用于读取和处理文件。分为简单模式&#xff08;和C一样&#xff09;、完全模式。 简单模式&#xff08;simple model&#xff09;拥有一个当前输入文件和一个当前输出文件&#xff0c;并且提供针对这些文件…...

        2024/5/3 5:42:41
      5. 【外汇早评】美通胀数据走低,美元调整

        原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

        2024/5/4 23:54:56
      6. 【原油贵金属周评】原油多头拥挤,价格调整

        原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

        2024/5/4 23:54:56
      7. 【外汇周评】靓丽非农不及疲软通胀影响

        原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

        2024/5/4 23:54:56
      8. 【原油贵金属早评】库存继续增加,油价收跌

        原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

        2024/5/6 9:21:00
      9. 【外汇早评】日本央行会议纪要不改日元强势

        原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

        2024/5/4 23:54:56
      10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

        原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

        2024/5/4 23:55:05
      11. 【外汇早评】美欲与伊朗重谈协议

        原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

        2024/5/4 23:54:56
      12. 【原油贵金属早评】波动率飙升,市场情绪动荡

        原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

        2024/5/4 23:55:16
      13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

        原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

        2024/5/4 23:54:56
      14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

        原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

        2024/5/6 1:40:42
      15. 【外汇早评】美伊僵持,风险情绪继续升温

        原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

        2024/5/4 23:54:56
      16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

        原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

        2024/5/4 23:55:17
      17. 氧生福地 玩美北湖(上)——为时光守候两千年

        原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

        2024/5/4 23:55:06
      18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

        原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

        2024/5/4 23:54:56
      19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

        原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

        2024/5/4 23:55:06
      20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

        原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

        2024/5/5 8:13:33
      21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

        原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

        2024/5/4 23:55:16
      22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

        原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

        2024/5/4 23:54:58
      23. 广州械字号面膜生产厂家OEM/ODM4项须知!

        原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

        2024/5/4 23:55:01
      24. 械字号医用眼膜缓解用眼过度到底有无作用?

        原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

        2024/5/4 23:54:56
      25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

        解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

        2022/11/19 21:17:18
      26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

        %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

        2022/11/19 21:17:16
      27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

        win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

        2022/11/19 21:17:15
      28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

        有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

        2022/11/19 21:17:14
      29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

        置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

        2022/11/19 21:17:13
      30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

        Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

        2022/11/19 21:17:12
      31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

        有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

        2022/11/19 21:17:11
      32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

        今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

        2022/11/19 21:17:10
      33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

        只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

        2022/11/19 21:17:09
      34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

        原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

        2022/11/19 21:17:08
      35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

        关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

        2022/11/19 21:17:05
      36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

        钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

        2022/11/19 21:17:05
      37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

        前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

        2022/11/19 21:17:04
      38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

        本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

        2022/11/19 21:17:03
      39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

        许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

        2022/11/19 21:17:02
      40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

        配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

        2022/11/19 21:17:01
      41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

        不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

        2022/11/19 21:17:00
      42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

        当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

        2022/11/19 21:16:59
      43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

        我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

        2022/11/19 21:16:58
      44. 如何在iPhone上关闭“请勿打扰”

        Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

        2022/11/19 21:16:57