void Object_Player::createCapsuleObject(hkpWorld* world) { // Create a temp body info hkpCharacterRigidBodyCinfo bodyInfo; // Capsule Parameters hkVector4 vertexA(0.0f, 1.0f, 0.0f, 0); // Top hkVector4 vertexB(0.0f, -1.0f, 0.0f, 0); // Bottom hkReal radius = 1.0f; // Radius // Create Capsule Based on Parameters hkpCapsuleShape* capsuleShape = new hkpCapsuleShape(vertexA, vertexB, radius); // Set The Object's Properties bodyInfo.m_shape = capsuleShape; bodyInfo.m_position.set(position.x, position.y, position.z, 0.0f); bodyInfo.m_maxSlope = HK_REAL_PI / 3.0f; // Calculate Mass Properties hkMassProperties massProperties; hkpInertiaTensorComputer::computeShapeVolumeMassProperties(capsuleShape, mass, massProperties); // Create Rigid Body objectBody = new hkpCharacterRigidBody(bodyInfo); // No longer need the reference on the shape, as the rigidbody owns it now capsuleShape->removeReference(); // Add Rigid Body to the World world->addEntity(objectBody->getRigidBody()); }
void Gdc2005Demo::optionUpdate() { const hkVector4 UP(0,1,0); // Handle load save //Set capsule size. { const hkReal totalHeight = m_options.m_Proxy.m_height; const hkReal radius = m_options.m_Proxy.m_radius; const hkReal capsulePoint = totalHeight*0.5f - radius; updateProxyDisplay(m_options.m_Proxy.m_radius, m_options.m_Proxy.m_height); hkVector4 vertexA(0, capsulePoint * 2 + radius, 0); hkVector4 vertexB(0, radius, 0); hkpCapsuleShape* capsule = static_cast<hkpCapsuleShape*>( const_cast<hkpShape*>(m_characterProxy->getShapePhantom()->getCollidable()->getShape() )); capsule->setRadius( radius ); capsule->setVertex(0, vertexA); capsule->setVertex(1, vertexB); } // Set gravity hkVector4 gravity; gravity.setMul4( -m_options.m_Physics.m_gravity, UP); m_world->setGravity( gravity ); // Ragdoll bodies (green) if (m_options.m_Display.m_ragdoll != m_ragdollDisplayBodiesVisible ) { toggleRagdollVisibility(); } if (m_options.m_Display.m_proxy != m_proxyVisible) { toggleProxyVisibility(); } // Graphics hkDefaultDemo::forceShadowState( m_options.m_Display.m_shadows ); if (m_lightmapDisplay) { if (m_options.m_Display.m_lightmaps) { int vertsIn = m_env->m_displayWorld->findDisplayObject( m_vertexColorDisplay ); if (vertsIn >= 0 ) { m_env->m_displayWorld->removeDisplayObject( vertsIn ); m_vertexColorDisplay->release(); // already have a ref anyway m_env->m_displayWorld->addDisplayObject( m_lightmapDisplay ); } } else { int lmIn = m_env->m_displayWorld->findDisplayObject( m_lightmapDisplay ); if (lmIn >= 0 ) { m_env->m_displayWorld->removeDisplayObject( lmIn ); m_lightmapDisplay->release(); // already have a ref anyway m_env->m_displayWorld->addDisplayObject( m_vertexColorDisplay ); } } } hkReal w = hkMath::max2( m_animatedSkeleton->getAnimationControl(GDC_DEATH_CONTROL)->getWeight(), m_animatedSkeleton->getAnimationControl(GDC_DYING_CONTROL)->getWeight()); setMotors(m_ragdollInstance, m_options.m_Matching.m_force * w, m_options.m_Matching.m_tau, m_options.m_Matching.m_proportinalRecovery, m_options.m_Matching.m_constantRecovery); // Do rebuild walls, save and load from XML, etc., when we have finished tweaking if (m_tweaking == false) { switch (m_options.m_Misc.m_settings) { case hkGdcMiscOptions::SAVE: { hkBinaryPackfileWriter pw; pw.setContents(&m_options, Gdc2005DemoOptionsClass); hkOfstream settingsFile("GdcDemoSettings.bin"); if (settingsFile.isOk()) { hkPackfileWriter::Options o; pw.save( settingsFile.getStreamWriter(), o ); } } break; case hkGdcMiscOptions::LOAD: { hkBinaryPackfileReader pw; hkIfstream settingsFile("GdcDemoSettings.bin"); if (settingsFile.isOk()) { pw.loadEntireFile( settingsFile.getStreamReader() ); Gdc2005DemoOptions* options = (Gdc2005DemoOptions*)pw.getContents(Gdc2005DemoOptionsClass.getName()); m_options = *options; } } break; case hkGdcMiscOptions::DEFAULT: { // Copy from defaults m_options = Gdc2005DemoOptions(); m_selected = "/"; } break; case hkGdcMiscOptions::NONE: break; } m_options.m_Misc.m_settings = hkGdcMiscOptions::NONE; if (m_options.m_Physics.m_rebuildWall) { rebuildBrickWall(); m_options.m_Physics.m_rebuildWall = false; // reset } } }
AsymetricCharacterRbDemo::AsymetricCharacterRbDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // Create the world { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0, -9.8f, 0); info.m_collisionTolerance = 0.01f; info.m_contactPointGeneration = hkpWorldCinfo::CONTACT_POINT_ACCEPT_ALWAYS; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // Create a terrain (more bumpy as in the classical character proxy demo) TerrainHeightFieldShape* heightFieldShape; { hkpSampledHeightFieldBaseCinfo ci; ci.m_xRes = 64; ci.m_zRes = 64; ci.m_scale.set(1.6f, 0.2f, 1.6f); // Fill in a data array m_data = hkAllocate<hkReal>((ci.m_xRes * ci.m_zRes), HK_MEMORY_CLASS_DEMO); for (int x = 0; x < ci.m_xRes; x++) { for (int z = 0; z < ci.m_zRes; z++) { hkReal dx,dz,height = 0; int octave = 1; // Add together a few sine and cose waves for (int i=0; i< 3; i++) { dx = hkReal(x * octave) / ci.m_xRes; dz = hkReal(z * octave) / ci.m_zRes; height += 4 * i * hkMath::cos(dx * HK_REAL_PI) * hkMath::sin(dz * HK_REAL_PI); height -= 2.5f; octave *= 2; } m_data[x*ci.m_zRes + z] = height; } } heightFieldShape = new TerrainHeightFieldShape( ci , m_data ); // Create terrain as a fixed rigid body { hkpRigidBodyCinfo rci; rci.m_motionType = hkpMotion::MOTION_FIXED; rci.m_position.setMul4( -0.5f, heightFieldShape->m_extents ); // center the heighfield rci.m_shape = heightFieldShape; rci.m_friction = 0.5f; hkpRigidBody* terrain = new hkpRigidBody( rci ); m_world->addEntity(terrain); terrain->removeReference(); } heightFieldShape->removeReference(); } // Create some random static pilars (green) and smaller dynamic boxes (blue) { hkPseudoRandomGenerator randgen(12345); for (int i=0; i < 80; i++) { if (i%2) { // Dynamic boxes of random size hkVector4 size; randgen.getRandomVector11(size); size.setAbs4( size ); size.mul4(0.5f); hkVector4 minSize; minSize.setAll3(0.25f); size.add4(minSize); // Random position hkVector4 position; randgen.getRandomVector11( position ); position(0) *= 25; position(2) *= 25; position(1) = 4; { // To illustrate using the shape, create a rigid body by first defining a template. hkpRigidBodyCinfo rci; rci.m_shape = new hkpBoxShape( size ); rci.m_position = position; rci.m_friction = 0.5f; rci.m_restitution = 0.0f; // Density of concrete const hkReal density = 2000.0f; rci.m_mass = size(0)*size(1)*size(2)*density; hkVector4 halfExtents(size(0) * 0.5f, size(1) * 0.5f, size(2) * 0.5f); hkpMassProperties massProperties; hkpInertiaTensorComputer::computeBoxVolumeMassProperties(halfExtents, rci.m_mass, massProperties); rci.m_inertiaTensor = massProperties.m_inertiaTensor; rci.m_motionType = hkpMotion::MOTION_BOX_INERTIA; // Create a rigid body (using the template above). hkpRigidBody* box = new hkpRigidBody(rci); // Remove reference since the body now "owns" the Shape. rci.m_shape->removeReference(); box->addProperty(HK_PROPERTY_DEBUG_DISPLAY_COLOR, int(hkColor::DARKBLUE)); // Finally add body so we can see it, and remove reference since the world now "owns" it. m_world->addEntity(box)->removeReference(); } } else { // Fixed pilars of random size hkVector4 size; randgen.getRandomVector11(size); size.setAbs4( size ); hkVector4 minSize; minSize.setAll3(0.5f); size.add4(minSize); size(1) = 2.5f; // Random position hkVector4 position; randgen.getRandomVector11( position ); position(0) *= 25; position(2) *= 25; position(1) = 0; { // To illustrate using the shape, create a rigid body by first defining a template. hkpRigidBodyCinfo rci; rci.m_shape = new hkpBoxShape( size ); rci.m_position = position; rci.m_friction = 0.1f; rci.m_motionType = hkpMotion::MOTION_FIXED; // Create a rigid body (using the template above). hkpRigidBody* pilar = new hkpRigidBody(rci); // Remove reference since the body now "owns" the shape. rci.m_shape->removeReference(); pilar->addProperty(HK_PROPERTY_DEBUG_DISPLAY_COLOR, int(hkColor::DARKGREEN)); // Finally add body so we can see it, and remove reference since the world now "owns" it. m_world->addEntity(pilar); pilar->removeReference(); } } } } // Create a character rigid body { // Construct a shape hkVector4 vertexA(0.4f,0,0); hkVector4 vertexB(-0.4f,0,0); // Create a capsule to represent the character standing hkpShape* capsule = new hkpCapsuleShape(vertexA, vertexB, 0.6f); // Construct a character rigid body hkpCharacterRigidBodyCinfo info; info.m_mass = 100.0f; info.m_shape = capsule; info.m_maxForce = 1000.0f; info.m_up = UP; info.m_position.set(32.0f, 3.0f, 10.0f); info.m_maxSlope = HK_REAL_PI/2.0f; // Only vertical plane is too steep m_characterRigidBody = new hkpCharacterRigidBody( info ); m_world->addEntity( m_characterRigidBody->getRigidBody() ); capsule->removeReference(); } // Create the character state machine and context { hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING); state->removeReference(); state = new hkpCharacterStateClimbing(); manager->registerState( state, HK_CHARACTER_CLIMBING); state->removeReference(); m_characterContext = new hkpCharacterContext(manager, HK_CHARACTER_IN_AIR); manager->removeReference(); // Set new filter parameters for final output velocity filtering // Smoother interactions with small dynamic boxes m_characterContext->setCharacterType(hkpCharacterContext::HK_CHARACTER_RIGIDBODY); m_characterContext->setFilterParameters(0.9f,12.0f,200.0f); } // Initialize hkpSurfaceInfo of ground from previous frame // Specific case (character is in the air, UP is Y) m_previousGround = new hkpSurfaceInfo(UP,hkVector4::getZero(),hkpSurfaceInfo::UNSUPPORTED); m_framesInAir = 0; // Current camera angle about up m_currentAngle = 0.0f; // Init actual time m_time = 0.0f; // Init rigid body normal m_rigidBodyNormal = UP; m_world->unlock(); }
hkpWorld* PlanetGravityDemo::loadWorld( const char* path, hkpPhysicsData** physicsData, hkPackfileReader::AllocatedData** memData ) { hkIstream infile( path ); HK_ASSERT( 0x215d080c, infile.isOk() ); *physicsData = hkpHavokSnapshot::load( infile.getStreamReader(), memData ); HK_ASSERT( 0, *physicsData != HK_NULL ); // Ensure non-multithreaded simulation for non-multithreaded platforms hkpWorld* world = (*physicsData)->createWorld(); world->setGravity( hkVector4::getZero() ); // Create a character rigid body object { // Construct a shape hkVector4 vertexA( 0.0f, 0.4f, 0.0f ); hkVector4 vertexB( 0.0f, -0.4f, 0.0f ); // Create a capsule to represent the character standing m_standShape = new hkpCapsuleShape( vertexA, vertexB, 0.6f ); // Create a capsule to represent the character crouching // Note that we create the smaller capsule with the base at the same position as the larger capsule. m_crouchShape = new hkpCapsuleShape( hkVector4::getZero(), vertexB, 0.6f ); // Construct a character rigid body hkpCharacterRigidBodyCinfo info; info.m_mass = 80.0f; info.m_shape = m_standShape; info.m_maxForce = 8000.0f; info.m_position.set( 30.f, 0.f, 30.f ); info.m_maxSlope = 45.0f * HK_REAL_DEG_TO_RAD; info.m_friction = 0.25f; m_characterRigidBody = new hkpCharacterRigidBody( info ); world->addEntity( m_characterRigidBody->getRigidBody() ); m_characterRigidBody->getRigidBody()->setRestitution( 0.0f ); } // Create the Character state machine and context { hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND ); static_cast<hkpCharacterStateOnGround*>( manager->getState( HK_CHARACTER_ON_GROUND ) )->setDisableHorizontalProjection( true ); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR ); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING ); state->removeReference(); m_characterContext = new hkpCharacterContext( manager, HK_CHARACTER_IN_AIR ); manager->removeReference(); // Set character type m_characterContext->setCharacterType( hkpCharacterContext::HK_CHARACTER_RIGIDBODY ); } return world; }
PlatformsCharacterRbDemo::PlatformsCharacterRbDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // Setup the graphics { // Disable back face culling setGraphicsState(HKG_ENABLED_CULLFACE, false); // don't really want shadows as makes it too dark forceShadowState(false); setupLights(m_env); // so that the extra lights are added // allow color change on precreated objects m_env->m_displayHandler->setAllowColorChangeOnPrecreated(true); } // Create the world { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0,0,-9.8f); info.m_collisionTolerance = 0.01f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // Load the level { m_loader = new hkLoader(); hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Physics/levels/test_platform.hkx"); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkxScene* scene = reinterpret_cast<hkxScene*>( container->findObjectByType( hkxSceneClass.getName() )); HK_ASSERT2(0x27343635, scene, "No scene loaded"); env->m_sceneConverter->convert( scene, hkgAssetConverter::CONVERT_ALL ); hkpPhysicsData* physics = reinterpret_cast<hkpPhysicsData*>( container->findObjectByType( hkpPhysicsDataClass.getName() )); HK_ASSERT2(0x27343635, physics, "No physics loaded"); // Physics if (physics) { const hkArray<hkpPhysicsSystem*>& psys = physics->getPhysicsSystems(); // Tie the two together for (int i=0; i<psys.getSize(); i++) { hkpPhysicsSystem* system = psys[i]; // Change the layer of the rigid bodies for (int rb=0; rb < system->getRigidBodies().getSize(); rb++) { const hkUlong id = hkUlong(system->getRigidBodies()[rb]->getCollidable()); HK_SET_OBJECT_COLOR(id,NORMAL_GRAY); m_objectIds.pushBack(id); } // Associate the display and physics (by name) if (scene) { addPrecreatedDisplayObjectsByName( psys[i]->getRigidBodies(), scene ); } // add the lot to the world m_world->addPhysicsSystem(system); } } } // Add horizontal keyframed platform { hkpShape* platform = new hkpBoxShape(hkVector4(1.5,2.5,0.25)); hkpRigidBodyCinfo rbci; rbci.m_shape = platform; rbci.m_motionType = hkpMotion::MOTION_KEYFRAMED; rbci.m_position.set(2.5f, 0.0f, 0.25f); rbci.m_friction = 1.0f; rbci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(hkpGroupFilter::calcFilterInfo(1)); m_horPlatform = new hkpRigidBody(rbci); platform->removeReference(); m_world->addEntity(m_horPlatform); m_horPlatform->removeReference(); } // Add vertical keyframed platform { hkpShape* platform = new hkpBoxShape(hkVector4(1.5,2.5,0.25)); hkpRigidBodyCinfo rbci; rbci.m_shape = platform; rbci.m_motionType = hkpMotion::MOTION_KEYFRAMED; rbci.m_position.set(-3.5f, 0.0f, 3.25f); rbci.m_friction = 1.0f; rbci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(hkpGroupFilter::calcFilterInfo(1)); m_verPlatform = new hkpRigidBody(rbci); platform->removeReference(); m_world->addEntity(m_verPlatform); m_verPlatform->removeReference(); } // Create a character rigid body { // Create a capsule to represent the character standing hkVector4 vertexA(0,0, 0.4f); hkVector4 vertexB(0,0,-0.4f); m_standShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Construct a character rigid body hkpCharacterRigidBodyCinfo info; info.m_mass = 100.0f; info.m_shape = m_standShape; info.m_maxForce = 1000.0f; info.m_up = UP; info.m_position.set(0.0f, 5.0f, 1.5f); info.m_maxSlope = HK_REAL_PI/2.0f; m_characterRigidBody = new hkpCharacterRigidBody( info ); m_world->addEntity( m_characterRigidBody->getRigidBody() ); } // Create the character state machine { hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING); state->removeReference(); state = new hkpCharacterStateClimbing(); manager->registerState( state, HK_CHARACTER_CLIMBING); state->removeReference(); m_characterContext = new hkpCharacterContext(manager, HK_CHARACTER_ON_GROUND); m_characterContext->setCharacterType(hkpCharacterContext::HK_CHARACTER_RIGIDBODY); manager->removeReference(); } // Set colors of platforms HK_SET_OBJECT_COLOR(hkUlong(m_verPlatform->getCollidable()),hkColor::BLUE); HK_SET_OBJECT_COLOR(hkUlong(m_horPlatform->getCollidable()),hkColor::GREEN); // Set global time m_time = 0.0f; // Initialize hkpSurfaceInfo for previous ground m_previousGround = new hkpSurfaceInfo(); m_framesInAir = 0; // Current camera angle about up m_currentAngle = HK_REAL_PI * 0.5f; m_world->unlock(); }
int main( void ) { // init random seed equal to current time std::srand(std::time(0)); const unsigned MAX_NR_RECTANGLES = 100; // windows size int windowWidth = 600; int windowHeight = 600; // Initialise GLFW if(!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; return -1; } glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Open a window and create its OpenGL context // window = glfwCreateWindow( 1024, 768, "Tutorial 03 - Matrices", NULL, NULL); window = glfwCreateWindow(windowWidth, windowHeight, "Mondrian", NULL, NULL); if(window == NULL) { std::cerr << "Failed to open GLFW window."; std::cerr << " If you have an Intel GPU, they are not 3.3 compatible."; std::cerr << " Try the 2.1 version of the tutorials." << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // Initialize GLEW glewExperimental = true; // Needed for core profile if (glewInit() != GLEW_OK) { std::cerr << "Failed to initialize GLEW" << std::endl; return -1; } // enable z-buffer glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); // Ensure we can capture the escape key being pressed below glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); glfwSetMouseButtonCallback(window, mouseButtonCallback); // white background glm::vec4 whiteColor (1.0f, 1.0f, 1.0f, 0.0f); glClearColor(whiteColor.r, whiteColor.g, whiteColor.b, whiteColor.a); // nr rectangles * 2 triangles each * 3 vertices * 4 floats float cpuBufferDataPoints[MAX_NR_RECTANGLES * 2 * 3 * 4]; float cpuBufferColors[MAX_NR_RECTANGLES * 2 * 3 * 4]; // nr rectangles * 2 triangles each * 3 vertices * 4x4 floats float cpuBufferMVProw1[MAX_NR_RECTANGLES * 2 * 3 * 4]; float cpuBufferMVProw2[MAX_NR_RECTANGLES * 2 * 3 * 4]; float cpuBufferMVProw3[MAX_NR_RECTANGLES * 2 * 3 * 4]; float cpuBufferMVProw4[MAX_NR_RECTANGLES * 2 * 3 * 4]; float *cpuBufferLines; // Create and compile our GLSL program from the shaders GLuint rectangleProgram = LoadShaders( "rectangleVertexShader.glsl", "rectangleFragmentShader.glsl" ); GLuint lineProgram = LoadShaders( "lineVertexShader.glsl", "lineFragmentShader.glsl" ); // Use our shader (it's not required to be using a program to bind VAOs) glUseProgram(rectangleProgram); // VAOs GLuint rectangleVAO; GLuint lineVAO; glGenVertexArrays(1, &rectangleVAO); glGenVertexArrays(1, &lineVAO); glBindVertexArray(rectangleVAO); // left, right, bottom, top, angle1, angle2 // glm::mat4 Projection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f,0.0001f,10.0f); // In world coordinates glm::mat4 Projection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f); // In world coordinates for (unsigned row = 0; row < 4; row++) { for (unsigned col = 0; col < 4; col++) { std::cout << std::setw(10) << Projection[col][row] << " "; } std::cout << std::endl; } glm::vec4 testvertex; for (int i = -10; i <= 10; i++) { testvertex = glm::vec4(1.0); testvertex.z = i; testvertex = Projection * testvertex; std::cout << "z = " << std::setw(3) << i << " " << testvertex.z << std::endl; } std::cout << std::endl; // glm::mat4 Projection = glm::ortho(-20.0f, 20.0f, -20.0f, 20.0f,1.0f,100.0f); // In world coordinates /* glm::mat4 Projection = glm::perspective( 45.0f, // The horizontal Field of View, in degrees : the amount of "zoom". Think "camera lens". Usually between 90° (extra wide) and 30° (quite zoomed in) 4.0f / 4.0f, // Aspect Ratio. Depends on the size of your window. Notice that 4/3 == 800/600 == 1280/960, sounds familiar ? 0.1f, // Near clipping plane. Keep as big as possible, or you'll get precision issues. 100.0f // Far clipping plane. Keep as little as possible. ); */ // Camera matrix /* * view es una matriz cuadrada almacenada por columnas (no por filas) * al poner la camara mirando al origen en una posicion z=2 (positivo), * lo que hace, es generar una matriz de transformación que moverá el objeto * en el eje z dos unidades de "w" */ glm::mat4 View = glm::lookAt( glm::vec3(0,0,2), // Camera is at (4,3,3), in World Space glm::vec3(0,0,0), // and looks at the origin glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down) ); // glm::mat4 View = glm::mat4(1.0f); /* for (unsigned row = 0; row < 4; row++) { for (unsigned col = 0; col < 4; col++) { std::cout << std::setw(3) << View[col][row] << " "; } std::cout << std::endl; } */ GLuint rectangleVertexBuffer; glGenBuffers(1, &rectangleVertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, rectangleVertexBuffer); glEnableVertexAttribArray(0); glVertexAttribPointer( 0, // attribute. No particular reason for 0, but must match the layout in the shader. 4, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); GLuint rectangleColorBuffer; glGenBuffers(1, &rectangleColorBuffer); glBindBuffer(GL_ARRAY_BUFFER, rectangleColorBuffer); glEnableVertexAttribArray(1); glVertexAttribPointer( 1, // attribute. No particular reason for 0, but must match the layout in the shader. 4, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); // GLuint rectangleMVPBuffer; GLuint rectangleMVProw1Buffer; GLuint rectangleMVProw2Buffer; GLuint rectangleMVProw3Buffer; GLuint rectangleMVProw4Buffer; glGenBuffers(1, &rectangleMVProw1Buffer); glGenBuffers(1, &rectangleMVProw2Buffer); glGenBuffers(1, &rectangleMVProw3Buffer); glGenBuffers(1, &rectangleMVProw4Buffer); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw1Buffer); glEnableVertexAttribArray(2); glVertexAttribPointer( 2, // attribute. No particular reason for 0, but must match the layout in the shader. 4, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)(0) // array buffer offset ); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw2Buffer); glEnableVertexAttribArray(3); glVertexAttribPointer( 3, // attribute. No particular reason for 0, but must match the layout in the shader. 4, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)(0) // array buffer offset ); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw3Buffer); glEnableVertexAttribArray(4); glVertexAttribPointer( 4, // attribute. No particular reason for 0, but must match the layout in the shader. 4, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)(0) // array buffer offset ); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw4Buffer); glEnableVertexAttribArray(5); glVertexAttribPointer( 5, // attribute. No particular reason for 0, but must match the layout in the shader. 4, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)(0) // array buffer offset ); glBindVertexArray(lineVAO); GLuint lineVertexBuffer; glGenBuffers(1, &lineVertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, lineVertexBuffer); glEnableVertexAttribArray(0); glVertexAttribPointer( 0, // attribute. No particular reason for 0, but must match the layout in the shader. 2, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); // get a handle for MVP uniform matrix in line program (it's not required // to be using the line program right now // GLuint lineMVPID = glGetUniformLocation(lineProgram, "MVP"); glBindVertexArray(rectangleVAO); std::set<float> verticalLines; std::set<float> horizontalLines; unsigned nrLines = 0; unsigned simulationTime = 0; bool justEnded = true; double lineThickness = 0.1; do { // update window's title to show fps updateFPSCounter(window); // Clear the screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // update viewport glfwGetWindowSize(window, &windowWidth, &windowHeight); glViewport(0, 0, windowWidth, windowHeight); // (x,y) offset from lower left; (width, height) // std::cout << "nr rectangles: " << rectangles.size() << std::endl; // every 75 steps, create a new rectangle if (simulationTime % 500 == 0 && !endSimulation && rectangles.size() < MAX_NR_RECTANGLES) { // create rectangle Rectangle rectangle; // insert rectangle into array rectangles.push_back(rectangle); } // update cpu buffers // fill up new cpu position buffers float rectangleCoords[2 * 3 * 4]; unsigned coordCounter = 0; for (unsigned i = 0; i < rectangles.size(); i++) { rectangles[i].getCoords(rectangleCoords); for (unsigned j = 0; j < 2*3*4; j++) { cpuBufferDataPoints[coordCounter] = rectangleCoords[j]; coordCounter++; } // std::cout << "rectangle ID: " << rectangles[i].getID() << std::endl; // std::cout << "horizontal: [" << rectangles[i].getLeft() << " : " << rectangles[i].getRight() << "]" << std::endl; // std::cout << "vertical: [" << rectangles[i].getBottom() << " : " << rectangles[i].getTop() << "]" << std::endl; } // fill up new cpu colors buffers float rectangleColorComponents[2 * 3 * 4]; coordCounter = 0; for (unsigned i = 0; i < rectangles.size(); i++) { rectangles[i].getColorComponents(rectangleColorComponents); for (unsigned j = 0; j < 2*3*4; j++) { cpuBufferColors[coordCounter] = rectangleColorComponents[j]; coordCounter++; } } // fill up new cpu mvp buffers unsigned counter = 0; for (unsigned i = 0; i < rectangles.size(); i++) { glm::mat4 Model = rectangles[i].getModel(); // glm::mat4 MVP = Projection * View * Model; glm::mat4 MVP = Projection * Model * View; // TODO: try to transfer glm::mat MVP to buffer directly with glBufferData // glm::vec4 vertexa = Model * rectangles[i].getVertexA(); // glm::vec4 vertexb = Model * rectangles[i].getVertexB(); // glm::vec4 vertexc = Model * rectangles[i].getVertexC(); // glm::vec4 vertexd = Model * rectangles[i].getVertexD(); // std::cout << "final positions: " << std::endl; // std::cout << vertexa.x << " " << vertexa.y << " " << vertexa.z << std::endl; // std::cout << vertexb.x << " " << vertexb.y << " " << vertexb.z << std::endl; // std::cout << vertexc.x << " " << vertexc.y << " " << vertexc.z << std::endl; // std::cout << vertexd.x << " " << vertexd.y << " " << vertexd.z << std::endl; for (unsigned vertex = 0; vertex < 6; vertex++) { for (unsigned element = 0; element < 4; element++) { // cpuBufferMVProw1[counter] = static_cast<int>(MVP[0][element]); // cpuBufferMVProw2[counter] = static_cast<int>(MVP[1][element]); // cpuBufferMVProw3[counter] = static_cast<int>(MVP[2][element]); // cpuBufferMVProw4[counter] = static_cast<int>(MVP[3][element]); // TODO swap these lines cpuBufferMVProw1[counter] = MVP[0][element]; cpuBufferMVProw2[counter] = MVP[1][element]; cpuBufferMVProw3[counter] = MVP[2][element]; cpuBufferMVProw4[counter] = MVP[3][element]; // for these ones // cpuBufferMVProw1[counter] = MVP[element][0]; // cpuBufferMVProw2[counter] = MVP[element][1]; // cpuBufferMVProw3[counter] = MVP[element][2]; // cpuBufferMVProw4[counter] = MVP[element][3]; // std::cout << "double: " << std::endl; // std::cout << MVP[0][element] << " "; // std::cout << MVP[1][element] << " "; // std::cout << MVP[2][element] << " "; // std::cout << MVP[3][element] << std::endl; // std::cout << "int: " << std::endl; // std::cout << cpuBufferMVProw1[counter] << " "; // std::cout << cpuBufferMVProw2[counter] << " "; // std::cout << cpuBufferMVProw3[counter] << " "; // std::cout << cpuBufferMVProw4[counter] << std::endl; counter++; } } } glUseProgram(rectangleProgram); glBindVertexArray(rectangleVAO); // transfer data to position and color buffers glBindBuffer(GL_ARRAY_BUFFER, rectangleVertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * rectangles.size() * 2 * 3 * 4, cpuBufferDataPoints, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, rectangleColorBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * rectangles.size() * 2 * 3 * 4, cpuBufferColors, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw1Buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * rectangles.size() * 2 * 3 * 4, cpuBufferMVProw1, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw2Buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * rectangles.size() * 2 * 3 * 4, cpuBufferMVProw2, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw3Buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * rectangles.size() * 2 * 3 * 4, cpuBufferMVProw3, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, rectangleMVProw4Buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * rectangles.size() * 2 * 3 * 4, cpuBufferMVProw4, GL_STREAM_DRAW); // draw rectangles glDrawArrays(GL_TRIANGLES, 0, rectangles.size()*2*3); // 3 indices starting at 0 -> 1 triangle for (unsigned i = 0; i < rectangles.size(); i++) { // std::cout << "updating rectangle id: " << i << std::endl; rectangles[i].updateModel(); rectangles[i].shouldBeAlive(); } for (std::vector<Rectangle>::iterator it = rectangles.begin(); it != rectangles.end();) { if (it->isAlive()) { it++; } else { it = rectangles.erase(it); } } if (endSimulation && !justEnded) { glUseProgram(lineProgram); glBindVertexArray(lineVAO); // std::cout << "drawing lines..." << std::endl; glDrawArrays(GL_TRIANGLES, 0, nrLines * 2 * 3); // 3 indices starting at 0 -> 1 triangle } if (endSimulation && justEnded) { std::cout << "creating lines..." << std::endl; justEnded = false; // load data in cpuBufferLines just the very first time // get vertical and horizontal coords of every line that should be drawn for (unsigned i = 0; i < rectangles.size(); i++) { if (rectangles[i].getIsPinned()) { // values in {-10:10} int left = static_cast<int>(round(rectangles[i].getLeft())); int right = static_cast<int>(round(rectangles[i].getRight())); int bottom = static_cast<int>(round(rectangles[i].getBottom())); int top = static_cast<int>(round(rectangles[i].getTop())); std::cout << "left: " << left << " right: " << right << " top: " << top << " bottom: " << bottom << std::endl; verticalLines.insert(left); verticalLines.insert(right); horizontalLines.insert(bottom); horizontalLines.insert(top); } } unsigned nrVerticalLines = verticalLines.size(); unsigned nrHorizontalLines = horizontalLines.size(); nrLines = nrVerticalLines + nrHorizontalLines; std::cout << "nr lines to draw: " << nrLines << std::endl; // 1 line = 2 triangles; 1 triangle = 3 points each; 1 point = 2 coord each; cpuBufferLines = new float[nrLines * 2 * 3 * 2]; unsigned counter = 0; glm::mat4 PV = Projection * View; for (std::set<float>::iterator it = verticalLines.begin(); it != verticalLines.end(); it++) { glm::vec4 vertexA (*it - lineThickness, 10, 0, 1); glm::vec4 vertexB (*it + lineThickness, 10, 0, 1); glm::vec4 vertexC (*it - lineThickness, -10, 0, 1); glm::vec4 vertexD (*it + lineThickness, -10, 0, 1); vertexA = PV * vertexA; vertexB = PV * vertexB; vertexC = PV * vertexC; vertexD = PV * vertexD; // glm::vec4 firstPointMVP = Projection * View * firstPoint; // glm::vec4 secondPointMVP = Projection * View * secondPoint; // sent the points in {-10:10} domain // first triangle ABC cpuBufferLines[counter] = vertexA.x; // x counter++; cpuBufferLines[counter] = vertexA.y; // y counter++; cpuBufferLines[counter] = vertexB.x; // x counter++; cpuBufferLines[counter] = vertexB.y; // y counter++; cpuBufferLines[counter] = vertexC.x; // x counter++; cpuBufferLines[counter] = vertexC.y; // y counter++; // second triangle BCD cpuBufferLines[counter] = vertexB.x; // x counter++; cpuBufferLines[counter] = vertexB.y; // y counter++; cpuBufferLines[counter] = vertexC.x; // x counter++; cpuBufferLines[counter] = vertexC.y; // y counter++; cpuBufferLines[counter] = vertexD.x; // x counter++; cpuBufferLines[counter] = vertexD.y; // y counter++; // std::cout << "vertical line: " << std::endl; // std::cout << "(" << firstPointMVP.x << "," << firstPointMVP.y << ")" << std::endl; // std::cout << "(" << secondPointMVP.x << "," << secondPointMVP.y << ")" << std::endl; } for (std::set<float>::iterator it = horizontalLines.begin(); it != horizontalLines.end(); it++) { glm::vec4 vertexA (-10, *it + lineThickness, 0, 1); glm::vec4 vertexB (10, *it + lineThickness, 0, 1); glm::vec4 vertexC (-10, *it - lineThickness, 0, 1); glm::vec4 vertexD (10, *it - lineThickness, 0, 1); vertexA = PV * vertexA; vertexB = PV * vertexB; vertexC = PV * vertexC; vertexD = PV * vertexD; // glm::vec4 firstPointMVP = Projection * View * firstPoint; // glm::vec4 secondPointMVP = Projection * View * secondPoint; // first triangle ABC cpuBufferLines[counter] = vertexA.x; // x counter++; cpuBufferLines[counter] = vertexA.y; // y counter++; cpuBufferLines[counter] = vertexB.x; // x counter++; cpuBufferLines[counter] = vertexB.y; // y counter++; cpuBufferLines[counter] = vertexC.x; // x counter++; cpuBufferLines[counter] = vertexC.y; // y counter++; // second triangle BCD cpuBufferLines[counter] = vertexB.x; // x counter++; cpuBufferLines[counter] = vertexB.y; // y counter++; cpuBufferLines[counter] = vertexC.x; // x counter++; cpuBufferLines[counter] = vertexC.y; // y counter++; cpuBufferLines[counter] = vertexD.x; // x counter++; cpuBufferLines[counter] = vertexD.y; // y counter++; // std::cout << "horizontal line: " << std::endl; // std::cout << "(" << firstPointMVP.x << "," << firstPointMVP.y << ")" << std::endl; // std::cout << "(" << secondPointMVP.x << "," << secondPointMVP.y << ")" << std::endl; } glBindBuffer(GL_ARRAY_BUFFER, lineVertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * nrLines * 2 * 3 * 2, cpuBufferLines, GL_STATIC_DRAW); // send MVP matrix to line program // TODO: check if i need to be using line program and to have bound line VAO // glUniformMatrix4fv(lineMVPID, 1, GL_FALSE, &PV[0][0]); } // Swap buffers glfwSwapBuffers(window); glfwPollEvents(); // usleep(500000); // usleep(100000); simulationTime++; // int dummy; // std::cin >> dummy; } while ( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 ); glBindVertexArray(rectangleVAO); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindVertexArray(lineVAO); glDisableVertexAttribArray(0); // Cleanup VBO and shader glDeleteBuffers(1, &rectangleVertexBuffer); glDeleteBuffers(1, &rectangleColorBuffer); glDeleteBuffers(1, &rectangleMVProw1Buffer); glDeleteBuffers(1, &rectangleMVProw2Buffer); glDeleteBuffers(1, &rectangleMVProw3Buffer); glDeleteBuffers(1, &rectangleMVProw4Buffer); glDeleteBuffers(1, &lineVertexBuffer); glDeleteProgram(rectangleProgram); glDeleteProgram(lineProgram); glDeleteVertexArrays(1, &rectangleVAO); glDeleteVertexArrays(1, &lineVAO); // Close OpenGL window and terminate GLFW glfwTerminate(); delete [] cpuBufferLines; // make sure new was executed, i.e: right click event return 0; }
void PrevailingWindDemo::createPalmTree ( hkpWorld* world, const hkpWind* wind, const hkVector4& pos ) { const hkReal trunkHeight = 4.0f; const hkReal trunkBottomRadius = 0.5f; const hkReal trunkTopRadius = 0.2f; const hkReal trunkStiffness = 0.1f; const hkReal segmentMass = 0.6f; const int numberOfSegments = 4; const hkReal segmentGap = 0.2f; const int numberOfFronds = 6; const hkReal frondWidth = 2.0f; const hkReal frondLength = 3.0f; const hkReal frondMass = 0.4f; // The trunk hkArray<hkpRigidBody*> trunk; const hkReal segmentHeight = (trunkHeight - ((numberOfSegments - 1) * segmentGap)) / numberOfSegments; const hkReal radiusIncrement = (trunkBottomRadius - trunkTopRadius) / numberOfSegments; for ( int i = 0; i < numberOfSegments; i++ ) { hkpShape* segmentShape; hkpRigidBodyCinfo info; { hkVector4 bottom( 0.0f, (segmentHeight + segmentGap) * i, 0.0f ); hkVector4 top( 0.0f, (segmentHeight + segmentGap) * i + segmentHeight, 0.0f ); hkReal radius = trunkBottomRadius - (radiusIncrement * i); segmentShape = new hkpCylinderShape( bottom, top, radius, 0.03f ); info.m_shape = segmentShape; info.m_position = pos; if (i == 0) { info.m_motionType = hkpMotion::MOTION_FIXED; } else { hkpMassProperties massProperties; { hkpInertiaTensorComputer::computeCylinderVolumeMassProperties( bottom, top, radius, segmentMass, massProperties ); } info.m_motionType = hkpMotion::MOTION_DYNAMIC; info.m_mass = massProperties.m_mass; info.m_inertiaTensor = massProperties.m_inertiaTensor; info.m_centerOfMass = massProperties.m_centerOfMass; } } hkpRigidBody* segment = new hkpRigidBody( info ); segmentShape->removeReference(); trunk.pushBack( segment ); world->addEntity( segment ); segment->removeReference(); if (i > 0) { hkpWindAction* action = new hkpWindAction( segment, wind, 0.1f ); world->addAction(action); action->removeReference(); } } for ( int i = 1; i < numberOfSegments; i++ ) { // We model the connection between the segments with a ragdoll constraint. hkpRagdollConstraintData* rdc; { hkReal planeMin = HK_REAL_PI * -0.025f; hkReal planeMax = HK_REAL_PI * 0.025f; hkReal twistMin = HK_REAL_PI * -0.025f; hkReal twistMax = HK_REAL_PI * 0.025f; hkReal coneMin = HK_REAL_PI * -0.05f; hkReal coneMax = HK_REAL_PI * 0.05f; rdc = new hkpRagdollConstraintData(); rdc->setPlaneMinAngularLimit( planeMin ); rdc->setPlaneMaxAngularLimit( planeMax ); rdc->setTwistMinAngularLimit( twistMin ); rdc->setTwistMaxAngularLimit( twistMax ); hkVector4 twistAxis( 0.0f, 1.0f, 0.0f ); hkVector4 planeAxis( 0.0f, 0.0f, 1.0f ); hkVector4 pivot( 0.0f, (segmentHeight + segmentGap) * i, 0.0f ); rdc->setInBodySpace( pivot, pivot, planeAxis, planeAxis, twistAxis, twistAxis ); rdc->setAsymmetricConeAngle( coneMin, coneMax ); //world->createAndAddConstraintInstance( trunk[i - 1], trunk[i], rdc )->removeReference(); hkpConstraintInstance* constraint = new hkpConstraintInstance( trunk[i - 1], trunk[i], rdc ); world->addConstraint(constraint); hkpPositionConstraintMotor* motor = new hkpPositionConstraintMotor( 0 ); motor->m_tau = trunkStiffness; motor->m_maxForce = 1000.0f; motor->m_constantRecoveryVelocity = 0.1f; rdc->setTwistMotor( motor ); rdc->setConeMotor( motor ); rdc->setPlaneMotor( motor ); rdc->setMotorsActive(constraint, true); motor->removeReference(); constraint->removeReference(); rdc->removeReference(); } } // The angle that the leaves make with the ground in their half lifted position. hkQuaternion tilt; { hkVector4 axis( 0.0f, 0.0f, 1.0f ); tilt.setAxisAngle( axis, HK_REAL_PI * 0.1f ); } hkQuaternion tiltRot; // The fronds for ( int i = 0; i < numberOfFronds; i++ ) { hkQuaternion rotation; { hkVector4 axis( 0.0f, 1.0f, 0.0f ); rotation.setAxisAngle( axis, HK_REAL_PI * 2.0f * ( i / (hkReal) numberOfFronds ) ); rotation.normalize(); } hkpShape* frondShape; hkpRigidBodyCinfo info; { hkVector4 vertexA( 0.0f, 0.0f, 0.0f ); hkVector4 vertexB( frondLength, 0.0f, frondWidth / 2.0f ); hkVector4 vertexC( frondLength, 0.0f, - frondWidth / 2.0f ); frondShape = new hkpTriangleShape( vertexA, vertexB, vertexC, 0.01f ); info.m_shape = frondShape; hkVector4 relPos; relPos.setRotatedDir( rotation, hkVector4( trunkTopRadius + 0.3f, trunkHeight, 0.0f ) ); info.m_position.setAdd4( pos, relPos ); hkpMassProperties massProperties; { hkReal mass = frondMass; hkpInertiaTensorComputer::computeTriangleSurfaceMassProperties( vertexA, vertexB, vertexC, mass, 0.01f, massProperties ); } info.m_motionType = hkpMotion::MOTION_DYNAMIC; info.m_mass = massProperties.m_mass; info.m_inertiaTensor = massProperties.m_inertiaTensor; info.m_centerOfMass = massProperties.m_centerOfMass; tiltRot.setMul( rotation, tilt ); info.m_rotation = tiltRot; } hkpRigidBody* frond = new hkpRigidBody( info ); frondShape->removeReference(); world->addEntity( frond ); hkpWindAction* action = new hkpWindAction( frond, wind, 0.1f ); world->addAction(action); action->removeReference(); // We model the connection between the fronds and the trunk with a ragdoll constraint. hkpRagdollConstraintData* rdc; { hkReal planeMin = HK_REAL_PI * -0.005f; hkReal planeMax = HK_REAL_PI * 0.005f; hkReal twistMin = HK_REAL_PI * -0.05f; hkReal twistMax = HK_REAL_PI * 0.05f; hkReal coneMin = HK_REAL_PI * -0.2f; hkReal coneMax = HK_REAL_PI * 0.2f; rdc = new hkpRagdollConstraintData(); rdc->setPlaneMinAngularLimit( planeMin ); rdc->setPlaneMaxAngularLimit( planeMax ); rdc->setTwistMinAngularLimit( twistMin ); rdc->setTwistMaxAngularLimit( twistMax ); hkVector4 twistAxisFrond( 1.0f, 0.0f, 0.0f ); hkVector4 twistAxisTrunk; twistAxisTrunk.setRotatedDir( tiltRot, twistAxisFrond ); hkVector4 planeAxisFrond( 0.0f, 0.0f, 1.0f ); hkVector4 planeAxisTrunk; planeAxisTrunk.setRotatedDir( tiltRot, planeAxisFrond ); hkVector4 pivotFrond( 0.0f, 0.0f, 0.0f ); hkVector4 pivotTrunk; pivotTrunk.setRotatedDir( rotation, hkVector4( trunkTopRadius + 0.3f, trunkHeight, 0.0f ) ); rdc->setInBodySpace( pivotTrunk, pivotFrond, planeAxisTrunk, planeAxisFrond, twistAxisTrunk, twistAxisFrond ); rdc->setAsymmetricConeAngle( coneMin, coneMax ); world->createAndAddConstraintInstance( trunk[ numberOfSegments - 1 ], frond, rdc )->removeReference(); rdc->removeReference(); frond->removeReference(); } } }
bool FEdge::intersectParametric(FEdge & fe2, Vec3r viewpoint, real t3D, real u3D) { Vec3r A1 = vertexA()->getPoint3D(); Vec3r B1 = vertexB()->getPoint3D(); Vec3r A2 = fe2.vertexA()->getPoint3D(); Vec3r B2 = fe2.vertexB()->getPoint3D(); if (sameSide(A1,B1,viewpoint, A2, B2) || sameSide(A2, B2, viewpoint, A1, B1)) return false; // now, there *must* be an intersection. // for each edge, the normal of the plane containing the edge and the viewpoint Vec3r N1 = (A1-viewpoint) ^ (B1-viewpoint); Vec3r N2 = (A2-viewpoint) ^ (B2-viewpoint); // direction vector of the intersection of the two planes. Vec3r V = N1 ^ N2; // check if the planes coincide (i.e., source edges are colinear) assert(V.norm() > 0); // ----- compute t parameter ------ // form a plane for line 1, normal to the plane containing the viewpoint Vec3r BA1 = B1 - A1; Vec3r hsNormal1 = N1 ^ BA1; // intersect ray in direction of V through the plane real w1; GeomUtils::intersection_test res1 = GeomUtils::intersectLinePlanePN(viewpoint, V, hsNormal1, A1, w1); if (res1 != GeomUtils::DO_INTERSECT) { printf("res1 = %d\n", res1); printf("viewpoint = [%f %f %f]\n", viewpoint[0], viewpoint[1], viewpoint[2]); printf("A1 = [%f %f %f]\n", A1[0], A1[1], A1[2]); printf("B1 = [%f %f %f]\n", B1[0], B1[1], B1[2]); printf("A2 = [%f %f %f]\n", A2[0], A2[1], A2[2]); printf("B2 = [%f %f %f]\n", B2[0], B2[1], B2[2]); printf("N1 = [%f %f %f]\n", N1[0], N1[1], N1[2]); printf("N2 = [%f %f %f]\n", N2[0], N2[1], N2[2]); printf("V = [%f %f %f]\n", V[0], V[1], V[2]); printf("hsNormal1 = [%f %f %f]\n", hsNormal1[0], hsNormal1[1], hsNormal1[2]); } assert(res1 == GeomUtils::DO_INTERSECT); Vec3r pt1 = viewpoint + w1 * V; t3D = ((pt1 - A1) * BA1) / (BA1*BA1); assert(t3D >=0 && t3D <= 1); // if (t3D < 0 || t3D > 1) // return false; // ----- compute u parameter ------ // form a half-space plane for line 2 Vec3r BA2 = B2 - A2; Vec3r hsNormal2 = N2 ^ BA2; real w2; GeomUtils::intersection_test res2 = GeomUtils::intersectLinePlanePN(viewpoint, V, hsNormal2, A2, w2); if (res2 != GeomUtils::DO_INTERSECT) { printf("res1 = %d\n", res1); printf("viewpoint = [%f %f %f]\n", viewpoint[0], viewpoint[1], viewpoint[2]); printf("A1 = [%f %f %f]\n", A1[0], A1[1], A1[2]); printf("B1 = [%f %f %f]\n", B1[0], B1[1], B1[2]); printf("A2 = [%f %f %f]\n", A2[0], A2[1], A2[2]); printf("B2 = [%f %f %f]\n", B2[0], B2[1], B2[2]); printf("N1 = [%f %f %f]\n", N1[0], N1[1], N1[2]); printf("N2 = [%f %f %f]\n", N2[0], N2[1], N2[2]); printf("V = [%f %f %f]\n", V[0], V[1], V[2]); printf("hsNormal2 = [%f %f %f]\n", hsNormal2[0], hsNormal2[1], hsNormal2[2]); } assert(res2 == GeomUtils::DO_INTERSECT); Vec3r pt2 = viewpoint + w2 * V; u3D = ((pt2 - A2) * BA2) / (BA2*BA2); assert( u3D >=0 && u3D <=1); // if (u3D < 0 || u3D > 1) // return false; return true; }
CharacterDemo::CharacterDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // // Setup the camera // { hkVector4 from( 0.0f, 20.0f, -80.0f); hkVector4 to ( 0.0f, 0.0f, 0.0f); hkVector4 up ( 0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); // disable back face culling setGraphicsState(HKG_ENABLED_CULLFACE, false); // don't really want shadows as makes it too dark forceShadowState(false); setupLights(m_env); // so that the extra lights are added // float lightDir[] = { 0, -0.5f, -1 }; // setSoleDirectionLight(m_env, lightDir, 0xffffffff ); } // // Create the world // { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0,0,-9.8f); info.m_collisionTolerance = 0.1f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // Load the level { hkVector4 tkScaleFactor(.32f,.32f,.32f); hkString fullname("Resources/Physics/Tk/CharacterController/"); // We load our test case level. //fullname += "testcases.tk"; fullname += "level.tk"; hkpShape* moppShape = GameUtils::loadTK2MOPP(fullname.cString(),tkScaleFactor, -1.0f); HK_ASSERT2(0x64232cc0, moppShape,"TK file failed to load to MOPP in GameUtils::loadTK2MOPP."); hkpRigidBodyCinfo ci; ci.m_shape = moppShape; ci.m_motionType = hkpMotion::MOTION_FIXED; ci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo( 0, 1 ); hkpRigidBody* entity = new hkpRigidBody(ci); moppShape->removeReference(); m_world->addEntity(entity); entity->removeReference(); } // Add a ladder hkVector4 baseSize( 1.0f, 0.5f, 3.6f); { hkpRigidBodyCinfo rci; rci.m_shape = new hkpBoxShape( baseSize ); rci.m_position.set(3.4f, 8.f, 2); rci.m_motionType = hkpMotion::MOTION_FIXED; hkpRigidBody* ladder = new hkpRigidBody(rci); rci.m_shape->removeReference(); m_world->addEntity(ladder)->removeReference(); // Add a property so we can identify this as a ladder hkpPropertyValue val(1); ladder->addProperty(HK_OBJECT_IS_LADDER, val); // Color the ladder so we can see it clearly HK_SET_OBJECT_COLOR((hkUlong)ladder->getCollidable(), 0x7f1f3f1f); } // // Create a character proxy object // { // Construct a shape hkVector4 vertexA(0,0, 0.4f); hkVector4 vertexB(0,0,-0.4f); // Create a capsule to represent the character standing m_standShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Create a capsule to represent the character crouching // Note that we create the smaller capsule with the base at the same position as the larger capsule. // This means we can simply swap the shapes without having to reposition the character proxy, // and if the character is standing on the ground, it will still be on the ground. vertexA.setZero4(); m_crouchShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Construct a Shape Phantom m_phantom = new hkpSimpleShapePhantom( m_standShape, hkTransform::getIdentity(), hkpGroupFilter::calcFilterInfo(0,2) ); // Add the phantom to the world m_world->addPhantom(m_phantom); m_phantom->removeReference(); // Construct a character proxy hkpCharacterProxyCinfo cpci; cpci.m_position.set(-9.1f, 35, .4f); cpci.m_staticFriction = 0.0f; cpci.m_dynamicFriction = 1.0f; cpci.m_up.setNeg4( m_world->getGravity() ); cpci.m_up.normalize3(); cpci.m_userPlanes = 4; cpci.m_maxSlope = HK_REAL_PI / 3.f; cpci.m_shapePhantom = m_phantom; m_characterProxy = new hkpCharacterProxy( cpci ); } // // Add in a custom friction model // { hkVector4 up( 0.f, 0.f, 1.f ); m_listener = new MyCharacterListener(); m_characterProxy->addCharacterProxyListener(m_listener); } // // Create the Character state machine and context // { hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING); state->removeReference(); state = new hkpCharacterStateClimbing(); manager->registerState( state, HK_CHARACTER_CLIMBING); state->removeReference(); m_characterContext = new hkpCharacterContext(manager, HK_CHARACTER_ON_GROUND); manager->removeReference(); } // Current camera angle about up m_currentAngle = HK_REAL_PI * 0.5f; m_world->unlock(); }
UnitAI::UnitAI ( float fHeight, float fRadius, bool bReference ) : AI ( ) { fH = fHeight; fR = fRadius; ZeroMemory ( &movement, sizeof MOVEMENT_STRUCT ); movement.bEnabled = true; movement.fSpeed = 1.0f; if ( !bReference ) { APPHANDLE->core->PhysicsDevice->GetWorld()->lock ( ); // Create a capsule to the character standing hkVector4 vertexA ( 0, fHeight, 0 ); hkVector4 vertexB ( 0, fRadius, 0 ); hkpShape* standShape = new hkpCapsuleShape ( vertexA, vertexB, fRadius ); // Construct a character rigid body hkpCharacterRigidBodyCinfo info; info.m_mass = 250.0f; info.m_friction = 0.0f; info.m_shape = standShape; info.m_maxForce = 50.0f; info.m_up = hkVector4 ( 0, 1, 0 ); info.m_position.set ( 0, 0, 0 ); info.m_maxSlope = 35.0f * HK_REAL_DEG_TO_RAD; characterRigidBody = new hkpCharacterRigidBody ( info ); standShape->removeReference ( ); hkpCharacterRigidBodyListener* listener = new hkpCharacterRigidBodyListener ( ); characterRigidBody->setListener ( listener ); listener->removeReference ( ); APPHANDLE->core->PhysicsDevice->GetWorld()->addEntity( characterRigidBody->getRigidBody ( ) ); hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager ( ); state = new hkpCharacterStateOnGround ( ); manager->registerState ( state, HK_CHARACTER_ON_GROUND ); state->removeReference ( ); state = new hkpCharacterStateInAir ( ); manager->registerState ( state, HK_CHARACTER_IN_AIR ); state->removeReference ( ); state = new hkpCharacterStateJumping ( ); manager->registerState ( state, HK_CHARACTER_JUMPING ); state->removeReference ( ); state = new hkpCharacterStateClimbing ( ); manager->registerState ( state, HK_CHARACTER_CLIMBING ); state->removeReference ( ); characterContext = new hkpCharacterContext ( manager, HK_CHARACTER_ON_GROUND ); manager->removeReference ( ); // Set character type characterContext->setCharacterType ( hkpCharacterContext::HK_CHARACTER_RIGIDBODY ); APPHANDLE->core->PhysicsDevice->GetWorld()->unlock ( ); } else characterContext = nullptr; }