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(); } } }