| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 |
- // GraphicsTest rewrite from Urho3D 1.0
- const uint NUM_OBJECTS = 250;
- const uint NUM_LIGHTS = 20;
- const uint NUM_INSTANCENODES = 20;
- const uint NUM_INSTANCES = 50;
- const uint NUM_BILLBOARDNODES = 20;
- const uint NUM_BILLBOARDS = 15;
- Scene@ testScene;
- Node@ cameraNode;
- Camera@ camera;
- Node@ cameraLightNode;
- Light@ cameraLight;
- float yaw = 0.0;
- float pitch = 0.0;
- float objectangle = 0.0;
- bool paused = true;
- int drawDebug = 0;
- Array<Node@> animatingObjects;
- Array<Node@> billboards;
- Array<Node@> lights;
- Array<Node@> hitObjects;
- void Start()
- {
- if (engine.headless)
- {
- ErrorDialog("GraphicsTest", "Headless mode is not supported. The program will now exit.");
- engine.Exit();
- return;
- }
- InitConsole();
- InitScene();
- InitUI();
- CreateCamera();
- SubscribeToEvent("Update", "HandleUpdate");
- SubscribeToEvent("KeyDown", "HandleKeyDown");
- SubscribeToEvent("MouseMove", "HandleMouseMove");
- SubscribeToEvent("MouseButtonDown", "HandleMouseButtonDown");
- SubscribeToEvent("MouseButtonUp", "HandleMouseButtonUp");
- SubscribeToEvent("PostRenderUpdate", "HandlePostRenderUpdate");
- SubscribeToEvent("PhysicsCollision", "HandlePhysicsCollision");
- SubscribeToEvent("PhysicsPostStep", "HandlePhysicsPostStep");
- }
- void InitScene()
- {
- testScene = Scene("GraphicsTest");
- // Make the scene directly accessible from the console
- script.defaultScene = testScene;
- testScene.CreateComponent("Octree");
- testScene.CreateComponent("DebugRenderer");
- PhysicsWorld@ world = testScene.CreateComponent("PhysicsWorld");
- // Create the directional light
- Node@ sunNode = testScene.CreateChild();
- sunNode.direction = Vector3(0.5, -1, 0.5);
- Light@ sunLight = sunNode.CreateComponent("Light");
- sunLight.lightType = LIGHT_DIRECTIONAL;
- sunLight.color = Color(0.2, 0.2, 0.2);
- sunLight.specularIntensity = 1;
- // Create a zone to control the ambient lighting
- Node@ zoneNode = testScene.CreateChild();
- Zone@ zone = zoneNode.CreateComponent("Zone");
- zone.boundingBox = BoundingBox(-1000, 1000);
- zone.ambientColor = Color(0.1, 0.1, 0.1);
- // Create the "floor"
- for (int y = -5; y <= 5; y++)
- {
- for (int x = -5; x <= 5; x++)
- {
- Node@ newNode = testScene.CreateChild();
- newNode.position = Vector3(x * 20.5, -0.5, y * 20.5);
- newNode.scale = Vector3(20, 1, 20);
- RigidBody@ body = newNode.CreateComponent("RigidBody");
- CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
- shape.SetBox(Vector3(1, 1, 1));
- StaticModel@ object = newNode.CreateComponent("StaticModel");
- object.model = cache.GetResource("Model", "Models/Box.mdl");
- object.material = cache.GetResource("Material", "Materials/Stone.xml");
- }
- }
- // Create 2 occluder walls
- for (int x = 0; x < 2; x++)
- {
- Node@ newNode = testScene.CreateChild();
- newNode.position = Vector3(0, 5, 0);
- newNode.rotation = Quaternion(x * 90, Vector3(0, 1, 0));
- newNode.scale = Vector3(224, 10, 1);
- RigidBody@ body = newNode.CreateComponent("RigidBody");
- CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
- shape.SetBox(Vector3(1, 1, 1));
- StaticModel@ object = newNode.CreateComponent("StaticModel");
- object.model = cache.GetResource("Model", "Models/Box.mdl");
- object.material = cache.GetResource("Material", "Materials/StoneTiledH.xml");
- object.castShadows = true;
- object.occluder = true;
- }
- // Create static mushroom with physics
- {
- Node@ newNode = testScene.CreateChild();
- newNode.position = Vector3(50, 0, 50);
- newNode.SetScale(10);
- RigidBody@ body = newNode.CreateComponent("RigidBody");
- CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
- shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0);
- StaticModel@ object = newNode.CreateComponent("StaticModel");
- object.model = cache.GetResource("Model", "Models/Mushroom.mdl");
- object.material = cache.GetResource("Material", "Materials/Mushroom.xml");
- object.castShadows = true;
- object.occluder = true;
- }
- // Create mushroom groups
- for (uint i = 0; i < NUM_INSTANCENODES; ++i)
- {
- Node@ newNode = testScene.CreateChild();
- newNode.position = Vector3(Random() * 160 - 80, 0, Random() * 160 - 80);
- for (uint j = 0; j < NUM_INSTANCES; ++j)
- {
- Vector3 position = Vector3(Random() * 20 - 10, 0, Random() * 20 - 10);
- float angle = Random() * 360;
- float size = 1 + Random() * 2;
- Node@ instance = newNode.CreateChild();
- instance.position = position;
- instance.rotation = Quaternion(angle, Vector3(0, 1, 0));
- instance.SetScale(size);
- StaticModel@ object = instance.CreateComponent("StaticModel");
- object.model = cache.GetResource("Model", "Models/Mushroom.mdl");
- object.material = cache.GetResource("Material", "Materials/Mushroom.xml");
- object.castShadows = true;
- }
- }
- // Create animated models
- for (uint i = 0; i < NUM_OBJECTS; ++i)
- {
- Node@ newNode = testScene.CreateChild("Jack");
- newNode.position = Vector3(Random() * 180 - 90, 0, Random() * 180 - 90);
- newNode.rotation = Quaternion(Random() * 360, Vector3(0, 1, 0));
- newNode.SetScale(1 + Random() * 0.25);
- AnimatedModel@ object = newNode.CreateComponent("AnimatedModel");
- object.model = cache.GetResource("Model", "Models/Jack.mdl");
- object.material = cache.GetResource("Material", "Materials/Jack.xml");
- object.drawDistance = 300;
- object.castShadows = true;
- object.maxLights = 2;
- // Because there are many animated models in the scene, test reducing animation LOD for less CPU use
- object.animationLodBias = 0.75;
- // Create a capsule shape for detecting collisions
- RigidBody@ body = newNode.CreateComponent("RigidBody");
- body.phantom = true;
- CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
- shape.SetCapsule(0.7, 1.8, Vector3(0.0, 0.9, 0.0));
- AnimationState@ anim = object.AddAnimationState(cache.GetResource("Animation", "Models/Jack_Walk.ani"));
- anim.looped = true;
- anim.weight = 1.0;
- animatingObjects.Push(newNode);
- }
- // Create floating smoke clouds
- for (uint i = 0; i < NUM_BILLBOARDNODES; ++i)
- {
- Node@ newNode = testScene.CreateChild("Smoke");
- newNode.position = Vector3(Random() * 200 - 100, Random() * 15 + 5, Random() * 200 - 100);
- BillboardSet@ billboard = newNode.CreateComponent("BillboardSet");
- billboard.numBillboards = NUM_BILLBOARDS;
- billboard.material = cache.GetResource("Material", "Materials/LitSmoke.xml");
- billboard.sorted = true;
- for (uint j = 0; j < NUM_BILLBOARDS; ++j)
- {
- Billboard@ bb = billboard.billboards[j];
- bb.position = Vector3(Random() * 15 - 7.5, Random() * 8 - 4, Random() * 15 - 7.5);
- bb.size = Vector2(Random() * 2 + 3, Random() * 2 + 3);
- bb.rotation = Random() * 360;
- bb.enabled = true;
- }
- billboard.Updated();
- billboards.Push(newNode);
- }
- // Create lights
- for (uint i = 0; i < NUM_LIGHTS; ++i)
- {
- Node@ newNode = testScene.CreateChild("Light");
- Light@ light = newNode.CreateComponent("Light");
- Vector3 position(
- Random() * 150 - 75,
- Random() * 30 + 30,
- Random() * 150 - 75
- );
- Color color((RandomInt() & 1) * 0.5 + 0.5, (RandomInt() & 1) * 0.5 + 0.5, (RandomInt() & 1) * 0.5 + 0.5);
- if (color.r == 0.5 && color.g == 0.5 && color.b == 0.5)
- color = Color(1, 1, 1);
- float angle = Random() * 360;
- newNode.position = position;
- newNode.direction = Vector3(Sin(angle), -1, Cos(angle));
- light.lightType = LIGHT_SPOT;
- light.range = 75;
- light.rampTexture = cache.GetResource("Texture2D", "Textures/RampExtreme.png");
- light.fov = 15;
- light.color = color;
- light.specularIntensity = 1;
- light.castShadows = true;
- light.shadowBias = BiasParameters(0.00002, 0.0);
- light.shadowDistance = 200;
- light.shadowFadeDistance = 150;
- light.shadowResolution = 0.5;
- // The spot lights will not have anything near them, so move the near plane of the shadow camera farther
- // for better shadow depth resolution
- light.shadowNearFarRatio = 0.01;
- // Store the original rotation as a node property
- newNode.vars["rotation"] = newNode.rotation;
- lights.Push(newNode);
- }
- }
- void AnimateScene(float timeStep)
- {
- objectangle += 10 * timeStep;
- for (uint i = 0; i < lights.length; ++i)
- lights[i].rotation = Quaternion(0, objectangle * 2, 0) * lights[i].vars["rotation"].GetQuaternion();
- for (uint i = 0; i < animatingObjects.length; ++i)
- {
- AnimatedModel@ model = animatingObjects[i].GetComponent("AnimatedModel");
- model.animationStates["Walk"].AddTime(timeStep);
- }
- for (uint i = 0; i < billboards.length; ++i)
- {
- BillboardSet@ billboard = billboards[i].GetComponent("BillboardSet");
- for (uint j = 0; j < billboard.numBillboards; ++j)
- billboard.billboards[j].rotation += 50 * timeStep;
- billboard.Updated();
- }
- }
- void InitConsole()
- {
- XMLFile@ uiStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
- Console@ console = engine.CreateConsole();
- console.style = uiStyle;
- console.numRows = 16;
- DebugHud@ hud = engine.CreateDebugHud();
- debugHud.style = uiStyle;
- debugHud.mode = DEBUGHUD_SHOW_ALL;
- }
- void InitUI()
- {
- XMLFile@ uiStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
- Cursor@ cursor = Cursor("Cursor");
- cursor.style = uiStyle;
- cursor.position = IntVector2(graphics.width / 2, graphics.height / 2);
- ui.cursor = cursor;
- if (GetPlatform() == "Android")
- ui.cursor.visible = false;
- }
- void CreateCamera()
- {
- cameraNode = testScene.CreateChild("Camera");
- camera = cameraNode.CreateComponent("Camera");
- cameraNode.position = Vector3(-50, 2, -50);
- cameraLightNode = cameraNode.CreateChild("CameraLight");
- cameraLight = cameraLightNode.CreateComponent("Light");
- cameraLight.lightType = LIGHT_SPOT;
- cameraLight.range = 50;
- cameraLight.color = Color(2, 2, 2);
- cameraLight.specularIntensity = 2;
- cameraLight.castShadows = true;
- cameraLight.shadowDistance = 200;
- cameraLight.shadowFadeDistance = 150;
- cameraLight.shadowResolution = 0.5;
- cameraLight.rampTexture = cache.GetResource("Texture2D", "Textures/RampWide.png");
- cameraLight.shapeTexture = cache.GetResource("Texture2D", "Textures/SpotWide.png");
- if (!engine.headless)
- {
- renderer.viewports[0] = Viewport(testScene, camera);
-
- // Add bloom & FXAA effects to the renderpath. Clone the default renderpath so that we don't affect it
- RenderPath@ newRenderPath = renderer.viewports[0].renderPath.Clone();
- newRenderPath.Append(cache.GetResource("XMLFile", "PostProcess/Bloom.xml"));
- newRenderPath.Append(cache.GetResource("XMLFile", "PostProcess/EdgeFilter.xml"));
- newRenderPath.SetActive("Bloom", false);
- newRenderPath.SetActive("EdgeFilter", false);
- renderer.viewports[0].renderPath = newRenderPath;
- audio.listener = cameraNode.CreateComponent("SoundListener");
- }
- }
- void HandleUpdate(StringHash eventType, VariantMap& eventData)
- {
- float timeStep = eventData["TimeStep"].GetFloat();
- if (!paused)
- AnimateScene(timeStep);
- if (ui.focusElement is null)
- {
- float speedMultiplier = 1.0;
- if (input.keyDown[KEY_LSHIFT])
- speedMultiplier = 5.0;
- if (input.keyDown[KEY_LCTRL])
- speedMultiplier = 0.1;
- if (input.keyDown['W'])
- cameraNode.TranslateRelative(Vector3(0, 0, 10) * timeStep * speedMultiplier);
- if (input.keyDown['S'])
- cameraNode.TranslateRelative(Vector3(0, 0, -10) * timeStep * speedMultiplier);
- if (input.keyDown['A'])
- cameraNode.TranslateRelative(Vector3(-10, 0, 0) * timeStep * speedMultiplier);
- if (input.keyDown['D'])
- cameraNode.TranslateRelative(Vector3(10, 0, 0) * timeStep * speedMultiplier);
- }
- }
- void HandleKeyDown(StringHash eventType, VariantMap& eventData)
- {
- int key = eventData["Key"].GetInt();
- if (key == KEY_ESC)
- {
- if (ui.focusElement is null)
- engine.Exit();
- else
- console.visible = false;
- }
- if (key == KEY_F1)
- console.Toggle();
- if (ui.focusElement is null)
- {
- if (key == '1')
- {
- int quality = renderer.textureQuality;
- ++quality;
- if (quality > 2)
- quality = 0;
- renderer.textureQuality = quality;
- }
- if (key == '2')
- {
- int quality = renderer.materialQuality;
- ++quality;
- if (quality > 2)
- quality = 0;
- renderer.materialQuality = quality;
- }
- if (key == '3')
- renderer.specularLighting = !renderer.specularLighting;
- if (key == '4')
- renderer.drawShadows = !renderer.drawShadows;
- if (key == '5')
- {
- int size = renderer.shadowMapSize;
- size *= 2;
- if (size > 2048)
- size = 512;
- renderer.shadowMapSize = size;
- }
- if (key == '6')
- renderer.shadowQuality = renderer.shadowQuality + 1;
- if (key == '7')
- {
- bool occlusion = renderer.maxOccluderTriangles > 0;
- occlusion = !occlusion;
- renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
- }
- if (key == '8')
- renderer.dynamicInstancing = !renderer.dynamicInstancing;
- if (key == ' ')
- {
- drawDebug++;
- if (drawDebug > 2)
- drawDebug = 0;
- }
- if (key == 'P')
- paused = !paused;
- if (key == 'L')
- {
- if (cameraLightNode.parent is testScene)
- {
- cameraLightNode.parent = cameraNode;
- cameraLightNode.position = Vector3(0, 0, 0);
- cameraLightNode.rotation = Quaternion();
- }
- else
- cameraLightNode.parent = testScene;
- }
- if (key == 'B')
- renderer.viewports[0].renderPath.ToggleActive("Bloom");
- if (key == 'F')
- renderer.viewports[0].renderPath.ToggleActive("EdgeFilter");
- if (key == 'O')
- camera.orthographic = !camera.orthographic;
- if (key == 'T')
- debugHud.Toggle(DEBUGHUD_SHOW_PROFILER);
- if (key == KEY_F5)
- {
- File@ xmlFile = File("Data/Scenes/TestSceneOld.xml", FILE_WRITE);
- testScene.SaveXML(xmlFile);
- }
- if (key == KEY_F7)
- {
- File@ xmlFile = File("Data/Scenes/TestSceneOld.xml", FILE_READ);
- if (xmlFile.open)
- {
- testScene.LoadXML(xmlFile);
- // Reacquire camera, as it is part of the scene
- cameraNode = testScene.GetChild("Camera", true);
- camera = cameraNode.GetComponent("Camera");
- cameraLightNode = cameraNode.GetChild("CameraLight");
- renderer.viewports[0] = Viewport(testScene, camera);
- audio.listener = cameraNode.GetComponent("SoundListener");
- // Reacquire animating objects
- animatingObjects.Clear();
- billboards.Clear();
- lights.Clear();
- for (uint i = 0; i < testScene.numChildren; ++i)
- {
- Node@ node = testScene.children[i];
- if (node.name == "Jack")
- animatingObjects.Push(node);
- else if (node.name == "Smoke")
- billboards.Push(node);
- else if (node.name == "Light")
- lights.Push(node);
- }
- }
- }
- }
- }
- void HandleMouseMove(StringHash eventType, VariantMap& eventData)
- {
- if (eventData["Buttons"].GetInt() & MOUSEB_RIGHT != 0)
- {
- int mousedx = eventData["DX"].GetInt();
- int mousedy = eventData["DY"].GetInt();
- yaw += mousedx / 10.0;
- pitch += mousedy / 10.0;
- if (pitch < -90.0)
- pitch = -90.0;
- if (pitch > 90.0)
- pitch = 90.0;
- cameraNode.rotation = Quaternion(pitch, yaw, 0);
- }
- }
- void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
- {
- int button = eventData["Button"].GetInt();
- if (button == MOUSEB_RIGHT)
- ui.cursor.visible = false;
- // Test either creating a new physics object or painting a decal (SHIFT down)
- if (button == MOUSEB_LEFT && ui.GetElementAt(ui.cursorPosition, true) is null && ui.focusElement is null)
- {
- if (!input.qualifierDown[QUAL_SHIFT])
- {
- Node@ newNode = testScene.CreateChild();
- newNode.position = cameraNode.position;
- newNode.rotation = cameraNode.rotation;
- newNode.SetScale(0.2);
- RigidBody@ body = newNode.CreateComponent("RigidBody");
- body.mass = 1.0;
- body.friction = 1.0;
- body.linearVelocity = cameraNode.rotation * Vector3(0.0, 1.0, 10.0);
- CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
- shape.SetBox(Vector3(1, 1, 1));
- StaticModel@ object = newNode.CreateComponent("StaticModel");
- object.model = cache.GetResource("Model", "Models/Box.mdl");
- object.material = cache.GetResource("Material", "Materials/StoneSmall.xml");
- object.castShadows = true;
- object.shadowDistance = 150.0;
- object.drawDistance = 200.0;
- }
- else
- {
- IntVector2 pos = ui.cursorPosition;
- if (ui.GetElementAt(pos, true) is null && testScene.octree !is null)
- {
- Ray cameraRay = camera.GetScreenRay(float(pos.x) / graphics.width, float(pos.y) / graphics.height);
- RayQueryResult result = testScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, 250.0, DRAWABLE_GEOMETRY);
- if (result.drawable !is null)
- {
- Vector3 rayHitPos = cameraRay.origin + cameraRay.direction * result.distance;
- DecalSet@ decal = result.drawable.node.GetComponent("DecalSet");
- if (decal is null)
- {
- decal = result.drawable.node.CreateComponent("DecalSet");
- decal.material = cache.GetResource("Material", "Materials/UrhoDecal.xml");
- // Increase max. vertices/indices if the target is skinned
- if (result.drawable.typeName == "AnimatedModel")
- {
- decal.maxVertices = 2048;
- decal.maxIndices = 4096;
- }
- }
- decal.AddDecal(result.drawable, rayHitPos, cameraNode.worldRotation, 0.5, 1.0, 1.0, Vector2(0, 0),
- Vector2(1, 1));
- }
- }
- }
- }
- }
- void HandleMouseButtonUp(StringHash eventType, VariantMap& eventData)
- {
- if (eventData["Button"].GetInt() == MOUSEB_RIGHT)
- ui.cursor.visible = true;
- }
- void HandlePostRenderUpdate()
- {
- if (engine.headless)
- return;
- // Draw rendering debug geometry without depth test to see the effect of occlusion
- if (drawDebug == 1)
- renderer.DrawDebugGeometry(false);
- if (drawDebug == 2)
- testScene.physicsWorld.DrawDebugGeometry(true);
- IntVector2 pos = ui.cursorPosition;
- if (ui.GetElementAt(pos, true) is null && testScene.octree !is null)
- {
- Ray cameraRay = camera.GetScreenRay(float(pos.x) / graphics.width, float(pos.y) / graphics.height);
- RayQueryResult result = testScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, 250.0, DRAWABLE_GEOMETRY);
- if (result.drawable !is null)
- {
- Vector3 rayHitPos = cameraRay.origin + cameraRay.direction * result.distance;
- testScene.debugRenderer.AddBoundingBox(BoundingBox(rayHitPos + Vector3(-0.01, -0.01, -0.01), rayHitPos +
- Vector3(0.01, 0.01, 0.01)), Color(1.0, 1.0, 1.0), true);
- }
- }
- }
- void HandlePhysicsCollision(StringHash eventType, VariantMap& eventData)
- {
- // Check if either of the nodes has an AnimatedModel component
- Node@ nodeA = eventData["NodeA"].GetNode();
- Node@ nodeB = eventData["NodeB"].GetNode();
- if (nodeA.HasComponent("AnimatedModel"))
- hitObjects.Push(nodeA);
- else if (nodeB.HasComponent("AnimatedModel"))
- hitObjects.Push(nodeB);
- }
- void HandlePhysicsPostStep()
- {
- if (hitObjects.empty)
- return;
- for (uint i = 0; i < hitObjects.length; ++i)
- {
- Node@ node = hitObjects[i];
- // Remove the trigger physics shape, and create the ragdoll
- node.RemoveComponent("RigidBody");
- node.RemoveComponent("CollisionShape");
- CreateRagdoll(node.GetComponent("AnimatedModel"));
- }
- hitObjects.Clear();
- }
- void CreateRagdoll(AnimatedModel@ model)
- {
- Node@ root = model.node;
- CreateRagdollBone(root, "Bip01_Pelvis", SHAPE_CAPSULE, Vector3(0.3, 0.3, 0.3), Vector3(0.0, 0, 0), Quaternion(0, 0, 0));
- CreateRagdollBone(root, "Bip01_Spine1", SHAPE_CAPSULE, Vector3(0.3, 0.4, 0.3), Vector3(0.15, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_L_Thigh", SHAPE_CAPSULE, Vector3(0.175, 0.45, 0.175), Vector3(0.25, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_R_Thigh", SHAPE_CAPSULE, Vector3(0.175, 0.45, 0.175), Vector3(0.25, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_L_Calf", SHAPE_CAPSULE, Vector3(0.15, 0.55, 0.15), Vector3(0.25, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_R_Calf", SHAPE_CAPSULE, Vector3(0.15, 0.55, 0.15), Vector3(0.25, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_Head", SHAPE_SPHERE, Vector3(0.25, 0.25, 0.25), Vector3(0.1, 0, 0), Quaternion(0, 0, 0));
- CreateRagdollBone(root, "Bip01_L_UpperArm", SHAPE_CAPSULE, Vector3(0.125, 0.35, 0.125), Vector3(0.1, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_R_UpperArm", SHAPE_CAPSULE, Vector3(0.125, 0.35, 0.125), Vector3(0.1, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_L_Forearm", SHAPE_CAPSULE, Vector3(0.1, 0.3, 0.1), Vector3(0.15, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollBone(root, "Bip01_R_Forearm", SHAPE_CAPSULE, Vector3(0.1, 0.3, 0.1), Vector3(0.15, 0, 0), Quaternion(0, 0, 90));
- CreateRagdollConstraint(root, "Bip01_L_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3(0, 0, -1), Vector3(0, 0, 1), Vector2(45, 25), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_R_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3(0, 0, -1), Vector3(0, 0, 1), Vector2(45, 25), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_L_Calf", "Bip01_L_Thigh", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_R_Calf", "Bip01_R_Thigh", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_Spine1", "Bip01_Pelvis", CONSTRAINT_HINGE, Vector3(0, 0, 1), Vector3(0, 0, 1), Vector2(90, 0), Vector2(-25, 0));
- CreateRagdollConstraint(root, "Bip01_Head", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3(0, 0, 1), Vector3(0, 0, 1), Vector2(45, 25), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_L_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3(0, -1, 0), Vector3(0, 1, 0), Vector2(45, 45), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_R_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3(0, -1, 0), Vector3(0, 1, 0), Vector2(45, 45), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_L_Forearm", "Bip01_L_UpperArm", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0));
- CreateRagdollConstraint(root, "Bip01_R_Forearm", "Bip01_R_UpperArm", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0));
- // Disable animation from all bones (both physical and non-physical) to not interfere
- Skeleton@ skel = model.skeleton;
- for (uint i = 0; i < skel.numBones; ++i)
- skel.bones[i].animated = false;
- }
- void CreateRagdollBone(Node@ root, const String&in boneName, ShapeType type, const Vector3&in size, const Vector3&in position,
- const Quaternion&in rotation)
- {
- Node@ boneNode = root.GetChild(boneName, true);
- if (boneNode is null || boneNode.HasComponent("RigidBody"))
- return;
- RigidBody@ body = boneNode.CreateComponent("RigidBody", LOCAL);
- body.mass = 1.0;
- body.linearDamping = 0.05;
- body.angularDamping = 0.85;
- body.linearRestThreshold = 1.5;
- body.angularRestThreshold = 2.5;
- CollisionShape@ shape = boneNode.CreateComponent("CollisionShape", LOCAL);
- shape.shapeType = type;
- shape.size = size;
- shape.position = position;
- shape.rotation = rotation;
- }
- void CreateRagdollConstraint(Node@ root, const String&in boneName, const String&in parentName, ConstraintType type,
- const Vector3&in axis, const Vector3&in parentAxis, const Vector2&in highLimit, const Vector2&in lowLimit)
- {
- Node@ boneNode = root.GetChild(boneName, true);
- Node@ parentNode = root.GetChild(parentName, true);
- if (boneNode is null || parentNode is null || boneNode.HasComponent("Constraint"))
- return;
- Constraint@ constraint = boneNode.CreateComponent("Constraint", LOCAL);
- constraint.constraintType = type;
- constraint.disableCollision = true;
- // The connected body must be specified before setting the world position
- constraint.otherBody = parentNode.GetComponent("RigidBody");
- constraint.worldPosition = boneNode.worldPosition;
- constraint.axis = axis;
- constraint.otherAxis = parentAxis;
- constraint.highLimit = highLimit;
- constraint.lowLimit = lowLimit;
- }
|