physicsDebris.cpp
Engine/source/T3D/physics/physicsDebris.cpp
Public Variables
bool
For frame signal.
Public Functions
ConsoleDocClass(PhysicsDebris , "@brief Represents one or more rigid bodies defined in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> with " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> limited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lifetime.\n\n</a>" "A <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object can be viewed as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single system capable of generating multiple " "@link <a href="/coding/class/classphysicsbody/">PhysicsBody</a> PhysicsBodies@endlink as debris when triggered. Vaguely similar <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> how " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> is capable of creating Particles, but isn '<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> particle in itself. " "After it 's lifetime has elapsed, the object will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> loads <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> standard .DAE or .DTS <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and creates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> rigid body <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "each defined collision <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "For collision nodes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> work correctly, they must be setup as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">follows:\n</a>" " - Visible mesh nodes are siblings of the collision node under <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> common parent dummy <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" " - <a href="/coding/class/structcollision/">Collision</a> node is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> child of its visible mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "Colmesh type nodes are NOT supported;physx and most standard rigid " "body simulations do not support arbitrary triangle meshs <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamics " "do <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the computational <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">expense.\n\n</a>" " Therefore, collision nodes must be one of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">following:\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colbox\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colsphere\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colcapsule\n</a>" " - Col(convex).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> should NOT be created on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" " @ingroup Physics" )
ConsoleDocClass(PhysicsDebrisData , "@brief Defines the properties of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsDebris.\n</a>" "@ingroup Physics" )
DefineEngineMethod(PhysicsDebrisData , preload , void , () , "@brief Loads some information <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have readily available at simulation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time.\n\n</a>" "Forces generation of shaders, materials , and other data used by the %<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object. " "This function should be used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> level is loading in order <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> shorten " "the amount of time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">game.\n\n</a>" )
Detailed Description
Public Variables
bool gEditingMission
For frame signal.
Public Functions
ConsoleDocClass(PhysicsDebris , "@brief Represents one or more rigid bodies defined in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> with " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> limited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lifetime.\n\n</a>" "A <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object can be viewed as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single system capable of generating multiple " "@link <a href="/coding/class/classphysicsbody/">PhysicsBody</a> PhysicsBodies@endlink as debris when triggered. Vaguely similar <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> how " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> is capable of creating Particles, but isn '<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> particle in itself. " "After it 's lifetime has elapsed, the object will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> loads <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> standard .DAE or .DTS <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and creates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> rigid body <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "each defined collision <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "For collision nodes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> work correctly, they must be setup as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">follows:\n</a>" " - Visible mesh nodes are siblings of the collision node under <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> common parent dummy <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" " - <a href="/coding/class/structcollision/">Collision</a> node is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> child of its visible mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "Colmesh type nodes are NOT supported;physx and most standard rigid " "body simulations do not support arbitrary triangle meshs <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamics " "do <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the computational <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">expense.\n\n</a>" " Therefore, collision nodes must be one of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">following:\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colbox\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colsphere\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colcapsule\n</a>" " - Col(convex).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> should NOT be created on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" " @ingroup Physics" )
ConsoleDocClass(PhysicsDebrisData , "@brief Defines the properties of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsDebris.\n</a>" "@ingroup Physics" )
DefineEngineMethod(PhysicsDebrisData , preload , void , () , "@brief Loads some information <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have readily available at simulation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time.\n\n</a>" "Forces generation of shaders, materials , and other data used by the %<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object. " "This function should be used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> level is loading in order <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> shorten " "the amount of time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">game.\n\n</a>" )
IMPLEMENT_CO_DATABLOCK_V1(PhysicsDebrisData )
IMPLEMENT_CO_NETOBJECT_V1(PhysicsDebris )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "T3D/physics/physicsDebris.h" 26 27#include "core/stream/bitStream.h" 28#include "math/mathUtils.h" 29#include "console/consoleTypes.h" 30#include "console/consoleObject.h" 31#include "console/engineAPI.h" 32#include "sim/netConnection.h" 33#include "scene/sceneRenderState.h" 34#include "scene/sceneManager.h" 35#include "ts/tsShapeInstance.h" 36#include "T3D/gameBase/gameProcess.h" 37#include "core/resourceManager.h" 38#include "gfx/gfxTransformSaver.h" 39#include "lighting/lightQuery.h" 40#include "T3D/physics/physicsBody.h" 41#include "T3D/physics/physicsCollision.h" 42#include "T3D/physics/physicsWorld.h" 43#include "collision/concretePolyList.h" 44#include "T3D/physics/physicsPlugin.h" 45#include "math/mathUtils.h" 46#include "gui/worldEditor/worldEditor.h" 47#include "T3D/containerQuery.h" 48 49 50F32 PhysicsDebris::smLifetimeScale = 1.0f; 51 52 53IMPLEMENT_CO_DATABLOCK_V1( PhysicsDebrisData ); 54 55ConsoleDocClass( PhysicsDebrisData, 56 57 "@brief Defines the properties of a PhysicsDebris object.\n\n" 58 "@see PhysicsDebris.\n" 59 "@ingroup Physics" 60); 61 62PhysicsDebrisData::PhysicsDebrisData() 63: mass( 1.0f ), 64 dynamicFriction( 0.0f ), 65 staticFriction( 0.0f ), 66 restitution( 0.0f ), 67 linearDamping( 0.0f ), 68 angularDamping( 0.0f ), 69 linearSleepThreshold( 1.0f ), 70 angularSleepThreshold( 1.0f ), 71 waterDampingScale( 1.0f ), 72 buoyancyDensity( 0.0f ), 73 castShadows( true ) 74{ 75 lifetime = 5.0f; 76 lifetimeVariance = 0.0f; 77 shapeName = NULL; 78} 79 80bool PhysicsDebrisData::onAdd() 81{ 82 if(!Parent::onAdd()) 83 return false; 84 85 return true; 86} 87 88bool PhysicsDebrisData::preload( bool server, String &errorStr ) 89{ 90 if ( Parent::preload( server, errorStr ) == false ) 91 return false; 92 93 if ( server ) return true; 94 95 if ( shapeName && shapeName[0] != '\0' && !bool(shape) ) 96 { 97 shape = ResourceManager::get().load( shapeName ); 98 if ( bool(shape) == false ) 99 { 100 errorStr = String::ToString( "PhysicsDebrisData::load: Couldn't load shape \"%s\"", shapeName ); 101 return false; 102 } 103 else 104 { 105 // Create a dummy shape to force the generation of shaders and materials 106 // during the level load and not during gameplay. 107 TSShapeInstance *pDummy = new TSShapeInstance( shape, !server ); 108 delete pDummy; 109 } 110 } 111 112 return true; 113} 114 115void PhysicsDebrisData::initPersistFields() 116{ 117 addGroup( "Display" ); 118 119 addField( "shapeFile", TypeShapeFilename, Offset( shapeName, PhysicsDebrisData ), 120 "@brief Path to the .DAE or .DTS file to use for this shape.\n\n" 121 "Compatable with Live-Asset Reloading."); 122 123 addField( "castShadows", TypeBool, Offset( castShadows, PhysicsDebrisData ), 124 "@brief Determines if the shape's shadow should be cast onto the environment.\n\n" ); 125 126 endGroup( "Display" ); 127 128 addGroup( "Physical Properties" ); 129 130 addField("lifetime", TypeF32, Offset( lifetime, PhysicsDebrisData ), 131 "@brief Base time, in seconds, that debris persists after time of creation.\n\n" 132 "@note A %PhysicsDebris' lifetime multiplied by it's $pref::PhysicsDebris::lifetimeScale " 133 "must be equal to or greater than 1.0.\n\n"); 134 135 addField("lifetimeVariance", TypeF32, Offset( lifetimeVariance, PhysicsDebrisData ), 136 "@brief Range of variation randomly applied to lifetime when debris is created.\n\n" 137 "Represents the maximum amount of seconds that will be added or subtracted to a shape's base lifetime. " 138 "A value of 0 will apply the same lifetime to each shape created.\n\n"); 139 140 addField( "mass", TypeF32, Offset( mass, PhysicsDebrisData ), 141 "@brief Value representing the mass of the shape.\n\n" 142 "A shape's mass influences the magnitude of any force applied to it. " 143 "@note All PhysicsDebris objects are dynamic."); 144 145 addField( "friction", TypeF32, Offset( dynamicFriction, PhysicsDebrisData ), 146 "@brief Coefficient of kinetic %friction to be applied to the shape.\n\n" 147 "Kinetic %friction reduces the velocity of a moving object while it is in contact with a surface. " 148 "A larger coefficient will result in a larger reduction in velocity. " 149 "A shape's friction should be smaller than it's staticFriction, but greater than 0.\n\n" 150 "@note This value is only applied while an object is in motion. For an object starting at rest, see PhysicsDebrisData::staticFriction"); 151 152 addField( "staticFriction", TypeF32, Offset( staticFriction, PhysicsDebrisData ), 153 "@brief Coefficient of static %friction to be applied to the shape.\n\n" 154 "Static %friction determines the force needed to start moving an at-rest object in contact with a surface. " 155 "If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. " 156 "A higher coefficient will require a larger force to start motion. " 157 "This value should be both greater than 0 and the PhysicsDebrisData::friction.\n\n" 158 "@note This value is only applied while an object is at rest. For an object in motion, see PhysicsDebrisData::friction"); 159 160 addField( "restitution", TypeF32, Offset( restitution, PhysicsDebrisData ), 161 "@brief Bounce coeffecient applied to the shape in response to a collision.\n\n" 162 "Restitution is a ratio of a shape's velocity before and after a collision. " 163 "A value of 0 will zero out a shape's post-collision velocity, making it stop on contact. " 164 "Larger values will remove less velocity after a collision, making it \'bounce\' with greater force. " 165 "Normal %restitution values range between 0 and 1.0." 166 "@note Values near or equaling 1.0 are likely to cause undesirable results in the physics simulation." 167 " Because of this, it is reccomended to avoid values close to 1.0"); 168 169 addField( "linearDamping", TypeF32, Offset( linearDamping, PhysicsDebrisData ), 170 "@brief Value that reduces an object's linear velocity over time.\n\n" 171 "Larger values will cause velocity to decay quicker.\n\n" ); 172 173 addField( "angularDamping", TypeF32, Offset( angularDamping, PhysicsDebrisData ), 174 "@brief Value that reduces an object's rotational velocity over time.\n\n" 175 "Larger values will cause velocity to decay quicker.\n\n" ); 176 177 addField( "linearSleepThreshold", TypeF32, Offset( linearSleepThreshold, PhysicsDebrisData ), 178 "@brief Minimum linear velocity before the shape can be put to sleep.\n\n" 179 "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n" 180 "@note The shape must be dynamic."); 181 182 addField( "angularSleepThreshold", TypeF32, Offset( angularSleepThreshold, PhysicsDebrisData ), 183 "@brief Minimum rotational velocity before the shape can be put to sleep.\n\n" 184 "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n" 185 "@note The shape must be dynamic."); 186 187 addField( "waterDampingScale", TypeF32, Offset( waterDampingScale, PhysicsDebrisData ), 188 "@brief Scale to apply to linear and angular dampening while underwater.\n\n " 189 "@see angularDamping linearDamping" ); 190 191 addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PhysicsDebrisData ), 192 "@brief The density of this shape for purposes of calculating buoyant forces.\n\n" 193 "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsDebris is within." 194 "@see WaterObject::density"); 195 196 endGroup( "Physical Properties" ); 197 198 Parent::initPersistFields(); 199} 200 201void PhysicsDebrisData::packData(BitStream* stream) 202{ 203 Parent::packData(stream); 204 205 stream->writeFlag( castShadows ); 206 stream->write( lifetime ); 207 stream->write( lifetimeVariance ); 208 stream->write( mass ); 209 stream->write( dynamicFriction ); 210 stream->write( staticFriction ); 211 stream->write( restitution ); 212 stream->write( linearDamping ); 213 stream->write( angularDamping ); 214 stream->write( linearSleepThreshold ); 215 stream->write( angularSleepThreshold ); 216 stream->write( waterDampingScale ); 217 stream->write( buoyancyDensity ); 218 stream->writeString( shapeName ); 219} 220 221void PhysicsDebrisData::unpackData(BitStream* stream) 222{ 223 Parent::unpackData(stream); 224 225 castShadows = stream->readFlag(); 226 stream->read( &lifetime ); 227 stream->read( &lifetimeVariance ); 228 stream->read( &mass ); 229 stream->read( &dynamicFriction ); 230 stream->read( &staticFriction ); 231 stream->read( &restitution ); 232 stream->read( &linearDamping ); 233 stream->read( &angularDamping ); 234 stream->read( &linearSleepThreshold ); 235 stream->read( &angularSleepThreshold ); 236 stream->read( &waterDampingScale ); 237 stream->read( &buoyancyDensity ); 238 239 shapeName = stream->readSTString(); 240} 241 242DefineEngineMethod( PhysicsDebrisData, preload, void, (), , 243 "@brief Loads some information to have readily available at simulation time.\n\n" 244 "Forces generation of shaders, materials, and other data used by the %PhysicsDebris object. " 245 "This function should be used while a level is loading in order to shorten " 246 "the amount of time to create a PhysicsDebris in game.\n\n") 247{ 248 String errorStr; 249 250 object->shape = NULL; 251 if( !object->preload( false, errorStr ) ) 252 Con::errorf( "PhsysicsDebrisData::preload - error: %s", errorStr.c_str() ); 253} 254 255 256IMPLEMENT_CO_NETOBJECT_V1( PhysicsDebris ); 257 258ConsoleDocClass( PhysicsDebris, 259 260 "@brief Represents one or more rigid bodies defined in a single mesh file with " 261 "a limited lifetime.\n\n" 262 263 "A PhysicsDebris object can be viewed as a single system capable of generating multiple " 264 "@link PhysicsBody PhysicsBodies@endlink as debris when triggered. Vaguely similar to how " 265 "a ParticleEmitter is capable of creating Particles, but isn't a particle in itself. " 266 267 "After it's lifetime has elapsed, the object will be deleted.\n\n" 268 269 "%PhysicsDebris loads a standard .DAE or .DTS file and creates a rigid body for " 270 "each defined collision node.\n\n" 271 272 "For collision nodes to work correctly, they must be setup as follows:\n" 273 " - Visible mesh nodes are siblings of the collision node under a common parent dummy node.\n" 274 " - Collision node is a child of its visible mesh node.\n\n" 275 276 "Colmesh type nodes are NOT supported; physx and most standard rigid " 277 "body simulations do not support arbitrary triangle meshs for dynamics " 278 "do to the computational expense.\n\n" 279 "Therefore, collision nodes must be one of the following:\n" 280 " - Colbox\n" 281 " - Colsphere\n" 282 " - Colcapsule\n" 283 " - Col (convex).\n\n" 284 285 "%PhysicsDebris should NOT be created on the server.\n\n" 286 287 "@ingroup Physics" 288); 289 290PhysicsDebris* PhysicsDebris::create( PhysicsDebrisData *datablock, 291 const MatrixF &transform, 292 const VectorF &linVel ) 293{ 294 // Skip out if we don't have a datablock or the 295 // global lifetime scale has it living less than 296 // a second. 297 if ( !datablock || 298 ( datablock->lifetime > 0.0f && 299 datablock->lifetime * smLifetimeScale < 1.0f ) ) 300 return NULL; 301 302 PhysicsDebris *debris = new PhysicsDebris(); 303 debris->setDataBlock( datablock ); 304 debris->setTransform( transform ); 305 debris->mInitialLinVel = linVel; 306 if ( !debris->registerObject() ) 307 { 308 delete debris; 309 return NULL; 310 } 311 312 return debris; 313} 314 315PhysicsDebris::PhysicsDebris() 316 : mLifetime( 0.0f ), 317 mInitialLinVel( Point3F::Zero ), 318 mDataBlock( NULL ), 319 mShapeInstance( NULL ), 320 mWorld( NULL ) 321{ 322 mTypeMask |= DebrisObjectType | DynamicShapeObjectType; 323 324 // Only allocated client side. 325 mNetFlags.set( IsGhost ); 326} 327 328PhysicsDebris::~PhysicsDebris() 329{ 330} 331 332void PhysicsDebris::initPersistFields() 333{ 334 Con::addVariable( "$pref::PhysicsDebris::lifetimeScale", TypeF32, &smLifetimeScale, 335 "@brief Scales how long %PhysicsDebris will live before being removed.\n" 336 "@note A value of 0 will disable PhysicsDebris entirely."); 337 338 Parent::initPersistFields(); 339} 340 341bool PhysicsDebris::onAdd() 342{ 343 AssertFatal( isClientObject(), "PhysicsDebris::onAdd - This shouldn't be added on the server!" ); 344 345 if ( !Parent::onAdd() ) 346 return false; 347 348 if( !mDataBlock ) 349 { 350 Con::errorf("PhysicsDebris::onAdd - Fail - No datablock"); 351 return false; 352 } 353 354 // If it has a fixed lifetime then calculate it. 355 if ( mDataBlock->lifetime > 0.0f ) 356 { 357 F32 lifeVar = (mDataBlock->lifetimeVariance * 2.0f * gRandGen.randF(-1.0,1.0)) - mDataBlock->lifetimeVariance; 358 mLifetime = mDataBlock->lifetime + lifeVar; 359 } 360 361 // Setup our bounding box 362 mObjBox = mDataBlock->shape->mBounds; 363 resetWorldBox(); 364 365 // Add it to the client scene. 366 addToScene(); 367 368 // We add the debris to the net connection so that 369 // it is cleaned up when the client disconnects. 370 NetConnection *conn = NetConnection::getConnectionToServer(); 371 AssertFatal( conn != NULL, "PhysicsDebris::onAdd - Got null net connection!"); 372 conn->addObject(this); 373 374 PhysicsPlugin::getPhysicsResetSignal().notify( this, &PhysicsDebris::_onPhysicsReset ); 375 _createFragments(); 376 377 return true; 378} 379 380bool PhysicsDebris::onNewDataBlock( GameBaseData *dptr, bool reload ) 381{ 382 if ( !dptr ) 383 return false; 384 385 mDataBlock = dynamic_cast< PhysicsDebrisData* >( dptr ); 386 if ( !mDataBlock ) 387 { 388 Con::errorf( ConsoleLogEntry::General, "PhysicsDebris::onNewDataBlock - datablock ( %i ) is not of type PhysicsDebrisData.", dptr->getId() ); 389 return false; 390 } 391 392 return true; 393} 394 395void PhysicsDebris::onRemove() 396{ 397 PhysicsPlugin::getPhysicsResetSignal().remove( this, &PhysicsDebris::_onPhysicsReset ); 398 399 _deleteFragments(); 400 401 removeFromScene(); 402 403 Parent::onRemove(); 404} 405 406void PhysicsDebris::processTick( const Move* ) 407{ 408 PROFILE_SCOPE( PhysicsDebris_processTick ); 409 410 // Delete the debris if our lifetime has expired. 411 if ( mDataBlock->lifetime > 0.0f && 412 mIsZero( mLifetime ) ) 413 { 414 deleteObject(); 415 return; 416 } 417 418 MatrixF mat; 419 mWorldBox = Box3F::Invalid; 420 Box3F bounds; 421 422 FragmentVector::iterator fragment = mFragments.begin(); 423 for ( ; fragment != mFragments.end(); fragment++ ) 424 { 425 // Store the last position. 426 fragment->lastPos = fragment->pos; 427 fragment->lastRot = fragment->rot; 428 429 // Get the new position. 430 fragment->body->getTransform( &mat ); 431 432 // Calculate the delta between the current 433 // global pose and the last global pose. 434 fragment->pos = mat.getPosition(); 435 fragment->rot.set( mat ); 436 437 // Update the bounds. 438 bounds = fragment->body->getWorldBounds(); 439 mWorldBox.intersect( bounds ); 440 441 // Apply forces for the next tick. 442 _updateForces( fragment->body, bounds ); 443 } 444 445 // Finish up the bounds update. 446 mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len(); 447 mObjBox = mWorldBox; 448 mWorldToObj.mul(mObjBox); 449 mRenderWorldBox = mWorldBox; 450 mRenderWorldSphere = mWorldSphere; 451} 452 453void PhysicsDebris::_updateForces( PhysicsBody *body, const Box3F &bounds ) 454{ 455 PROFILE_SCOPE( PhysicsDebris_updateForces ); 456 457 // If we're not simulating don't update forces. 458 if ( !mWorld->isEnabled() ) 459 return; 460 461 ContainerQueryInfo info; 462 info.box = bounds; 463 info.mass = mDataBlock->mass; 464 465 // Find and retreive physics info from intersecting WaterObject(s) 466 getContainer()->findObjects( bounds, WaterObjectType</a>|<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084a1af121084d5760a7eaef4bb8828ce1cf">PhysicalZoneObjectType, findRouter, &info ); 467 468 // Calculate buoyancy and drag 469 F32 angDrag = mDataBlock->angularDamping; 470 F32 linDrag = mDataBlock->linearDamping; 471 F32 buoyancy = 0.0f; 472 Point3F cmass = body->getCMassPosition(); 473 474 F32 density = mDataBlock->buoyancyDensity; 475 if ( density > 0.0f ) 476 { 477 if ( info.waterCoverage > 0.0f ) 478 { 479 F32 waterDragScale = info.waterViscosity * mDataBlock->waterDampingScale; 480 F32 powCoverage = mPow( info.waterCoverage, 0.25f ); 481 482 angDrag = mLerp( angDrag, angDrag * waterDragScale, powCoverage ); 483 linDrag = mLerp( linDrag, linDrag * waterDragScale, powCoverage ); 484 } 485 486 // A little hackery to prevent oscillation 487 // Based on this blog post: 488 // (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html) 489 490 buoyancy = ( info.waterDensity / density ) * mPow( info.waterCoverage, 2.0f ); 491 492 Point3F buoyancyForce = buoyancy * -mWorld->getGravity() * TickSec * mDataBlock->mass; 493 body->applyImpulse( cmass, buoyancyForce ); 494 } 495 496 // Update the dampening as the container might have changed. 497 body->setDamping( linDrag, angDrag ); 498 499 // Apply physical zone forces. 500 if ( !info.appliedForce.isZero() ) 501 body->applyImpulse( cmass, info.appliedForce ); 502} 503 504void PhysicsDebris::advanceTime( F32 dt ) 505{ 506 // Decrement the lifetime. 507 if ( smLifetimeScale > 0.0f ) 508 mLifetime = getMax( 0.0f, mLifetime - ( dt / smLifetimeScale ) ); 509 else 510 mLifetime = 0.0f; 511} 512 513void PhysicsDebris::interpolateTick( F32 dt ) 514{ 515 PROFILE_SCOPE( PhysicsDebris_interpolateTick ); 516 517 mShapeInstance->animate(); 518 if ( mShapeInstance->getCurrentDetail() < 0 ) 519 return; 520 521 const MatrixF &objectXfm = getRenderWorldTransform(); 522 Vector<MatrixF> &nodeXfms = mShapeInstance->mNodeTransforms; 523 524 MatrixF globalXfm; 525 MatrixF tempXfm; 526 QuatF newRot; 527 Point3F newPos; 528 529 FragmentVector::iterator fragment = mFragments.begin(); 530 for ( ; fragment != mFragments.end(); fragment++ ) 531 { 532 // Do the interpolation. 533 newRot.interpolate( fragment->rot, fragment->lastRot, dt ); 534 newRot.setMatrix( &globalXfm ); 535 newPos.interpolate( fragment->pos, fragment->lastPos, dt ); 536 globalXfm.setPosition( newPos ); 537 538 tempXfm = objectXfm * globalXfm; 539 540 for ( S32 i = 0; i < fragment->nodeIds.size(); i++ ) 541 { 542 S32 n = fragment->nodeIds[i]; 543 nodeXfms[n] = tempXfm; 544 } 545 } 546} 547 548void PhysicsDebris::prepRenderImage( SceneRenderState *state ) 549{ 550 if( !mShapeInstance ) 551 return; 552 553 // Skip shadow rendering if this debris doesn't support it. 554 if ( state->isShadowPass() && 555 !mDataBlock->castShadows ) 556 return; 557 558 // If the debris is completed LOD'd out then skip it. 559 if ( mShapeInstance->setDetailFromPosAndScale( state, getRenderPosition(), getScale() ) < 0 ) 560 return; 561 562 // Fade out the debris over the last second of its lifetime. 563 F32 alpha = 1.0; 564 if ( mDataBlock->lifetime > 0.0f ) 565 alpha = getMin( mLifetime * smLifetimeScale, 1.0f ); 566 567 // Set up our TS render state. 568 TSRenderState rdata; 569 rdata.setSceneState( state ); 570 rdata.setFadeOverride( alpha ); 571 572 // We might have some forward lit materials 573 // so pass down a query to gather lights. 574 LightQuery query; 575 query.init( getWorldSphere() ); 576 rdata.setLightQuery( &query ); 577 578 GFXTransformSaver saver; 579 580 MatrixF mat = getRenderTransform(); 581 mat.scale( getScale() ); 582 GFX->setWorldMatrix( mat ); 583 584 mShapeInstance->animate(); 585 mShapeInstance->render( rdata ); 586} 587 588void PhysicsDebris::applyImpulse( const Point3F &pos, const VectorF &vec ) 589{ 590 FragmentVector::iterator fragment = mFragments.begin(); 591 for ( ; fragment != mFragments.end(); fragment++ ) 592 fragment->body->applyImpulse( pos, vec ); 593} 594 595void PhysicsDebris::applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude ) 596{ 597 FragmentVector::iterator fragment = mFragments.begin(); 598 for ( ; fragment != mFragments.end(); fragment++ ) 599 { 600 PhysicsBody &body = *fragment->body; 601 602 Box3F bounds = body.getWorldBounds(); 603 604 VectorF force = bounds.getCenter() - origin; 605 F32 dist = force.magnitudeSafe(); 606 force.normalize(); 607 608 if ( dist == 0.0f ) 609 force *= magnitude; 610 else 611 force *= mClampF( radius / dist, 0.0f, 1.0f ) * magnitude; 612 613 body.applyImpulse( origin, force ); 614 } 615} 616 617void PhysicsDebris::_createFragments() 618{ 619 _deleteFragments(); 620 621 mWorld = PHYSICSMGR->getWorld( "client" ); 622 if ( !mWorld ) 623 return; 624 625 TSShape *shape = mDataBlock->shape; 626 627 mShapeInstance = new TSShapeInstance( shape, true ); 628 mShapeInstance->animate(); 629 630 Vector< CollisionShapeInfo> infoList; 631 shape->buildColShapes( false, Point3F::One, &infoList ); 632 633 mFragments.setSize( infoList.size() ); 634 dMemset( mFragments.address(), 0, mFragments.memSize() ); 635 636 const Point3F damageDir( 0, 0, 1 ); 637 638 MatrixF bodyMat( true ); 639 bodyMat = getTransform(); 640 641 const U32 bodyFlags = PhysicsBody::BF_DEBRIS; 642 mWorldBox = Box3F::Invalid; 643 644 for ( S32 i = 0; i < infoList.size(); i++ ) 645 { 646 const CollisionShapeInfo &info = infoList[i]; 647 648 Fragment &fragment = mFragments[i]; 649 650 if ( info.colNode == -1 ) 651 Con::errorf( "PhysicsDebris::_createFragments, Missing or couldnt find a colNode." ); 652 else 653 _findNodes( info.colNode, fragment.nodeIds ); 654 655 PhysicsBody *body = PHYSICSMGR->createBody(); 656 body->init( info.colShape, mDataBlock->mass, bodyFlags, this, mWorld ); 657 body->setMaterial( mDataBlock->restitution, mDataBlock->dynamicFriction, mDataBlock->staticFriction ); 658 body->setDamping( mDataBlock->linearDamping, mDataBlock->angularDamping ); 659 body->setSleepThreshold( mDataBlock->linearSleepThreshold, mDataBlock->angularSleepThreshold ); 660 body->setTransform( bodyMat ); 661 body->setLinVelocity( mInitialLinVel ); 662 fragment.body = body; 663 664 // Set the initial delta state. 665 fragment.pos = bodyMat.getPosition(); 666 fragment.rot.set( bodyMat ); 667 fragment.lastPos = fragment.pos; 668 fragment.lastRot = fragment.rot; 669 670 // Update the bounds. 671 mWorldBox.intersect( body->getWorldBounds() ); 672 } 673 674 // Finish up updating the bounds. 675 mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len(); 676 mObjBox = mWorldBox; 677 mWorldToObj.mul(mObjBox); 678 mRenderWorldBox = mWorldBox; 679 mRenderWorldSphere = mWorldSphere; 680} 681 682void PhysicsDebris::_deleteFragments() 683{ 684 FragmentVector::iterator fragment = mFragments.begin(); 685 for ( ; fragment != mFragments.end(); fragment++ ) 686 delete fragment->body; 687 688 mFragments.clear(); 689 690 SAFE_DELETE( mShapeInstance ); 691} 692 693void PhysicsDebris::_findNodes( U32 colNode, Vector<U32> &nodeIds ) 694{ 695 // Two possible cases: 696 // 1. Visible mesh nodes are siblings of the collision node under a common parent dummy node 697 // 2. Collision node is a child of its visible mesh node 698 699 TSShape *shape = mDataBlock->shape; 700 S32 itr = shape->nodes[colNode].parentIndex; 701 itr = shape->nodes[itr].firstChild; 702 703 while ( itr != -1 ) 704 { 705 if ( itr != colNode ) 706 nodeIds.push_back(itr); 707 itr = shape->nodes[itr].nextSibling; 708 } 709 710 // If we didn't find any siblings of the collision node we assume 711 // it is case #2 and the collision nodes direct parent is the visible mesh. 712 if ( nodeIds.size() == 0 && shape->nodes[colNode].parentIndex != -1 ) 713 nodeIds.push_back( shape->nodes[colNode].parentIndex ); 714} 715 716extern bool gEditingMission; 717 718void PhysicsDebris::_onPhysicsReset( PhysicsResetEvent reset ) 719{ 720 if ( gEditingMission ) 721 { 722 // Editing stuff, clean up the trash! 723 safeDeleteObject(); 724 } 725} 726