int Geometry::rayIntersectSphere(const Vector3 &ray_point, const Vector3 &ray_direction, const Vector3 &sphere_center, double sphere_radius, Vector3 *hit1, Vector3 *hit2) { Vector3 ray_direction_sphere = ray_point.sub(sphere_center); double a, b, c, d; a = ray_direction.x * ray_direction.x + ray_direction.y * ray_direction.y + ray_direction.z * ray_direction.z; b = 2 * (ray_direction.x * ray_direction_sphere.x + ray_direction.y * ray_direction_sphere.y + ray_direction.z * ray_direction_sphere.z); c = ray_direction_sphere.x * ray_direction_sphere.x + ray_direction_sphere.y * ray_direction_sphere.y + ray_direction_sphere.z * ray_direction_sphere.z - sphere_radius * sphere_radius; d = b * b - 4 * a * c; if (d < 0.0) { return 0; } else if (d > 0.0) { if (hit1 && hit2) { *hit1 = ray_point.add(ray_direction.scale((-b - sqrt(d)) / (2 * a))); *hit2 = ray_point.add(ray_direction.scale((-b + sqrt(d)) / (2 * a))); } return 2; } else { if (hit1) { *hit1 = ray_point.add(ray_direction.scale(-b / (2 * a))); } return 1; } }
Vector3 Object::computeLocalIllumination(Vector3& position, Vector3& normal, Light& light, Vector3& eyePosition) { Vector3 color; if (!material.skipLocalIllumination) { /* compute ambient factor */ color.add(material.ambient * light.ambient); /* compute the diffuse factor */ /* assume light is directional*/ real d = - dot(light.direction, normal); if (d > 0) { /* this is not a back-facing part of the object wrt the light */ color.add(d * (material.diffuse * light.diffuse)); } /* compute the specular factor */ Vector3 view = eyePosition - position; Vector3 halfway = 0.5f * (view - light.direction); halfway.normalize(); real s = dot(halfway, normal); if (s > 0) { color.add( pow(s, material.shininess) * material.specular * light.specular); } } return color; }
void CatmullRomSpline::getPath (std::vector<Vector3>& points, int numPoints) { int idx = 0; if (controlPoints.size() < 4) return; for (unsigned int i = 1; i <= controlPoints.size() - 3; i++) { points[idx++] = controlPoints[i]; float increment = 1.0f / (numPoints + 1); float t = increment; T1.set(controlPoints[i + 1]).sub(controlPoints[i - 1]).mul(0.5f); T2.set(controlPoints[i + 2]).sub(controlPoints[i]).mul(0.5f); for (int j = 0; j < numPoints; j++) { float h1 = 2 * t * t * t - 3 * t * t + 1; // calculate basis // function 1 float h2 = -2 * t * t * t + 3 * t * t; // calculate basis // function 2 float h3 = t * t * t - 2 * t * t + t; // calculate basis // function 3 float h4 = t * t * t - t * t; // calculate basis function 4 Vector3 point = points[idx++].set(controlPoints[i]).mul(h1); point.add(controlPoints[i + 1].tmp().mul(h2)); point.add(T1.tmp().mul(h3)); point.add(T2.tmp().mul(h4)); t += increment; } } points[idx].set(controlPoints[controlPoints.size() - 2]); }
Vector3 Vector3::getNormal5(const Vector3 &posx, const Vector3 &negx, const Vector3 &posy, const Vector3 &negy) const { Vector3 dnegx = negx.sub(*this); Vector3 dposy = posy.sub(*this); Vector3 dposx = posx.sub(*this); Vector3 dnegy = negy.sub(*this); Vector3 normal = dposy.crossProduct(dnegx); normal = normal.add(dposx.crossProduct(dposy)); normal = normal.add(dnegy.crossProduct(dposx)); normal = normal.add(dnegx.crossProduct(dnegy)); return normal.normalize(); }
void idle() { static float position = 0; long end = (clock() - start); if( end/CLOCKS_PER_SEC > 1 ) { printf( "FPS: %d\n", frames ); frames = 0; start = clock(); } frames++; if ( !followPenguin ) { position = min(cameraPath->size() - 1.0f, max(0.0f, position + cameraPlay)); float percentComplete = position / (cameraPath->size()-1); if (cameraPlay != 0) { camera->setCenterOfProjection( *cameraPath->at( (int)position ) ); camera->setLookAtPoint( *lookatPath->at( (int)position ) ); } if (percentComplete == 0 || percentComplete == 1) { cameraPlay = 0; } } else { // Center camera on penguin. Vector3 t = Vector3( pengFrontNormal ); t.scale( -15 ); t.add( t, pengLoc ); Vector3 up = Vector3( pengNormal ); up.scale( 10 ); t.add( t, up ); Vector3 t2 = Vector3( pengLoc ); up.scale( .5 ); t2.add( t2, up ); camera->setCenterOfProjection( t ); camera->setUp( pengNormal ); camera->setLookAtPoint( t2 ); frust->generateFrustumPlanes( camera, frustum ); } display(); }
Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model) { Vector3 center; const BoundingBox& box = model->getMesh()->getBoundingBox(); if (!(box.min.isZero() && box.max.isZero())) { Vector3 bMin, bMax; model->getNode()->getWorldMatrix().transformPoint(box.min, &bMin); model->getNode()->getWorldMatrix().transformPoint(box.max, &bMax); center.set(bMin, bMax); center.scale(0.5f); center.add(bMin); } else { const BoundingSphere& sphere = model->getMesh()->getBoundingSphere(); if (!(sphere.center.isZero() && sphere.radius == 0)) { model->getNode()->getWorldMatrix().transformPoint(sphere.center, ¢er); } else { // Warn the user that the model has no bounding volume. WARN_VARG("Model \'%s\' has no bounding volume - center of mass is defaulting to local coordinate origin.", model->getNode()->getId()); model->getNode()->getWorldMatrix().transformPoint(¢er); } } return center; }
void Viewport::getMovementVector(float x, float y, Vector3& v) const { Vector3 xb(xDir()), yb(yDir()); xb.inplaceMul(x/scale); yb.inplaceMul(y/scale); v.add(xb,yb); }
static Vector3 _getDetailNormal(Vector3 base_location, Vector3 base_normal, TextureLayerDefinition *layer, double precision, bool normal5) { Vector3 result; /* Find guiding vectors in the appoximated local plane */ Vector3 dx, dy; Vector3 pivot; if (base_normal.y > 0.95) { pivot = VECTOR_NORTH; } else { pivot = VECTOR_UP; } dx = base_normal.crossProduct(pivot).normalize(); dy = base_normal.crossProduct(dx).normalize(); /* Apply detail noise locally */ Vector3 center, north, east, south, west; auto detail_noise = layer->propDetailNoise()->getGenerator(); double detail = precision; double offset = precision * 0.1; center = base_location.add(base_normal.scale(detail_noise->getTriplanar(detail, base_location, base_normal))); east = base_location.add(dx.scale(offset)); east = east.add(base_normal.scale(detail_noise->getTriplanar(detail, east, base_normal))); south = base_location.add(dy.scale(offset)); south = south.add(base_normal.scale(detail_noise->getTriplanar(detail, south, base_normal))); if (normal5) { west = base_location.add(dx.scale(-offset)); west = west.add(base_normal.scale(detail_noise->getTriplanar(detail, west, base_normal))); north = base_location.add(dy.scale(-offset)); north = north.add(base_normal.scale(detail_noise->getTriplanar(detail, north, base_normal))); result = center.getNormal5(south, north, east, west); } else { result = center.getNormal3(south, east); } if (result.dotProduct(base_normal) < 0.0) { result = result.scale(-1.0); } return result; }
void Viewport::getMovementVectorAtDistance(float x, float y, float dist, Vector3& v) const { Vector3 xb(xDir()), yb(yDir()); Real imagePlaneDepth = w*scale; xb.inplaceMul(x*dist/imagePlaneDepth); yb.inplaceMul(y*dist/imagePlaneDepth); v.add(xb,yb); }
Vector3 TexturesRenderer::displaceTerrain(const TexturesDefinition *textures, const Vector3 &location, const Vector3 &normal) const { double offset = 0.0; int i, n; n = textures->getLayerCount(); for (i = 0; i < n; i++) { TextureLayerDefinition *layer = textures->getTextureLayer(i); if (layer->hasDisplacement()) { offset += _getLayerDisplacement(layer, location, normal); } } return location.add(normal.scale(offset)); }
vector<Vector3> TexturesRenderer::getLayersDisplacement(const TexturesDefinition *textures, const Vector3 &location, const Vector3 &normal, const vector<double> &presence) const { int n = textures->getLayerCount(); assert(presence.size() == to_size(n)); vector<Vector3> result; Vector3 displaced = location; for (int i = 0; i < n; i++) { double layer_presence = presence[i]; if (layer_presence > 0.0) { TextureLayerDefinition *layer = textures->getTextureLayer(i); double displacement = _getLayerDisplacement(layer, location, normal, layer_presence); displaced = displaced.add(normal.scale(displacement * layer_presence)); } result.push_back(displaced); } return result; }
GodRaysResult GodRaysSampler::getResult(const SpaceSegment &segment) { Vector3 step = segment.getEnd().sub(segment.getStart()); double max_length = step.getNorm(); step = step.normalize().scale(walk_step); Vector3 walker = segment.getStart(); double travelled = 0.0; double inside = 0.0; if (max_length > this->max_length) { max_length = this->max_length; } while (travelled < max_length) { double light = getCachedLight(walker); inside += light * walk_step; walker = walker.add(step); travelled += walk_step; } return GodRaysResult(inside, travelled); }
/*! * creates a BoundingSphere which encloses all given bvhNodes and adds all children * to this parent */ void DeformableBvhNode::createBoundingSpherePrecise(const std::list<DeformableBvhNode*>& bvhNodes) { //std::cout << "DeformableBvhNode::createBoundingSphere(const std::list<DeformableBvhNode*>& bvhNodes)" << std::endl; int counter = 0; Vector3 centerVector; real biggestDistance = 0.0f; real biggestRadius = 0.0f; for (std::list<DeformableBvhNode*>::const_iterator iter = bvhNodes.begin(); iter != bvhNodes.end(); ++iter) { ++counter; centerVector.add(((BoundingSphere*)((*iter)->getBoundingVolume()))->getCenterVector()); } centerVector = centerVector * ( 1.0f / counter); real tempDistance; real tempRadius; for (std::list<DeformableBvhNode*>::const_iterator iter = bvhNodes.begin(); iter != bvhNodes.end(); ++iter) { tempDistance = (centerVector - (((BoundingSphere*)((*iter)->getBoundingVolume()))->getCenterVector())).length(); tempRadius = ((BoundingSphere*)((*iter)->getBoundingVolume()))->getRadius(); if ( tempDistance+tempRadius > biggestDistance ) { biggestDistance = tempDistance+tempRadius; } } biggestRadius = biggestDistance; mBoundingVolume = new BoundingSphere(centerVector, biggestRadius); }
Vector3 Vector3::lerp(Vector3& target, float alpha) { Vector3 r = this->mul(1.0f - alpha); r.add(target.tmp().mul(alpha)); return r; }
/** détecte, entre b1 et b2, la collision et donne les informations nécessaires à la réponse dans *collision - principe : il faut déterminer les distances de recouvrement sur chacun des 4 axes possibles (2 axes pour b1 et 2 axes pour b2). si on trouve une distance négative, c'est que les boites ne se recouvrent pas sur cet axe => pas de collision (arrêt). si toutes les distances sont positives : b1 et b2 sont en intersection, et on renseigne *collision : - collision->mtd=un double : distance minimal sur les 4 axes (i.e. distance nécessaire pour séparer les 2 boites : sera utilisé pour la correction en position) - collision->normale=un Vector3 : l'axe de la distance minimal qui donne la normale au contact (i.e. direction de séparation) - collision->apply=un Vector3 : le point d'application qui sera utilisé pour l'impulsion (utilisé pour le calcul du moment de la force d'impulsion) : Le point d'application est déjà calculé (moyenne de tous les sommets intérieurs aux boites). **/ bool Box::detectCollision(Box *b1,Box *b2,CollisionInfo *collision) { double dist; double dist_min; Vector3 axis[4]; // 4 axes à tester Vector3 axe_min; // l'axe qui correspond à la plus petite distance de séparation. double direction; // les 4 axes potentiellement séparateurs axis[0]=b1->directionX(); // axe x de b1 axis[1]=b1->directionY(); // axe y de b1 axis[2]=b2->directionX(); // axe x de b2 axis[3]=b2->directionY(); // axe y de b2 bool detect; // A completer (1 seul axe pour l'instant => il faut tenir compte des 4 axes) : // - déterminez la distance minimale dist_min de recouvrement entre les 4 axes axis[i] qui sont non séparateurs (Attention : minimale en valeur absolue !, mais dist_min est négative s'il y a recouvrement) // - vous devez affecter correctement axe_min (l'axe correspondant à dist_min) qui est un des axis[i] *mais* en tenant compte du sens de séparation de // b2 par rapport à b1 (i.e. multiplier axis[i] par le signe (-1 ou 1) retourné par la méthode distance(b1,b2,...,)). // - assurez vous d'avoir affecté correctement detect à la fin (==true il y a collision, == false pas de collision). distance(b1,b2,axis[0],&dist,&direction); if (dist<0) p3d::addDebug(b1->position(),b1->position()-direction*dist*axis[0],"",Vector3(0.2,0.2,1)); detect=false; // force une non détection (à enlever lorsque la détection est implémentée...). // affecter les informations nécessaires à la réponse if (detect) { collision->mtd(dist_min); collision->axis(axe_min); // Calcul du point d'application de l'impulsion (ici barycentre des sommets intérieurs). // on créé la liste de tous les sommets inclus dans une des boites vector<Vector3> liste; liste.clear(); for(unsigned int i=0; i<4; i++) { if (b1->isInside(b2->vertex(i))) liste.push_back(b2->vertex(i)); } for(unsigned int i=0; i<4; i++) { if (b2->isInside(b1->vertex(i))) liste.push_back(b1->vertex(i)); } Vector3 apply; apply.set(0,0,0); for(unsigned int i=0; i<liste.size(); i++) { apply.add(liste[i]); } apply=apply/liste.size(); collision->applicationPoint(apply); collision->box1(b1); collision->box2(b2); } return detect; }
void update(int t) { if (currentCamera == 0) { cameraAngle += (diffMouseDownX / 100.0); cameraDistance = (cameraDistance += (diffMouseDownY / 20.0)) < 10 ? 10 : cameraDistance; camera.set( cameraDistance * cos(cameraAngle * (M_PI / 180)), cameraElevation, cameraDistance * sin(cameraAngle * (M_PI / 180)) ); cameraLookAt = Vector3(); cameraUp = Vector3(0, 1, 0); } else if (currentCamera == 1) { aboveCamera.y = (std::max(50.0, aboveCamera.y + (diffMouseDownY / 100.0))); aboveCameraLookAt = Vector3(0, aboveCamera.y - 100, aboveCamera.z); cameraLookAt = aboveCameraLookAt; camera.set(aboveCamera.x, aboveCamera.y, aboveCamera.z); cameraUp = aboveCameraUp; } else if (currentCamera == 2) { frontCamera.y = (frontCamera.y + (diffMouseDownY / 100.0)); frontCamera.x = (frontCamera.x - (diffMouseDownX / 100.0)); frontCamera.z = (cameraDistance); frontCameraLookAt = frontCamera.add(Vector3(0.0, 0.0, -1.0)); cameraLookAt = frontCameraLookAt; camera.set(frontCamera.x, frontCamera.y, frontCamera.z); cameraUp = frontCameraUp; } else if (currentCamera == 3) { getFreeCameraLookAt(); cameraLookAt = freeCameraLookAt; camera.set(freeCamera.x, freeCamera.y, freeCamera.z); freeCameraUp.x = sin(upAngle * (M_PI / 180)); freeCameraUp.y = cos(upAngle * (M_PI / 180)); cameraUp = freeCameraUp; } else if (currentCamera >= 4) { updateFlyBy(); cameraLookAt = flyBySettings.lookAt; camera.set( flyBySettings.position.x, flyBySettings.position.y, flyBySettings.position.z ); cameraUp = flyBySettings.up; } gravity.y = gravityIntensity; particleSystem.applyForce(gravity); for (int i = 0; i < 9; i++) { if (gravitationalForce[i].type != GRAVITATIONALFORCETYPE_NONE) { particleSystem.applyGravitationalForce(gravitationalForce[i]); } } if (cycleColours) { colourSwitch--; if (colourSwitch == 0) { colourSwitch = 10; Particle::startColour = emitColours[initialColour]; currentColour = Particle::startColour; initialColour = (++initialColour) == colourCount ? 0 : initialColour; } else { Particle::startColour.r = linearEase(10 - colourSwitch, currentColour.r, emitColours[initialColour].r - currentColour.r, 10); Particle::startColour.g = linearEase(10 - colourSwitch, currentColour.g, emitColours[initialColour].g - currentColour.g, 10); Particle::startColour.b = linearEase(10 - colourSwitch, currentColour.b, emitColours[initialColour].b - currentColour.b, 10); } } particleSystem.update(); // FPS monitoring frame++; elapsedTime = glutGet(GLUT_ELAPSED_TIME); if (elapsedTime - timebase > 1000) { fps = frame * 1000.0 / (elapsedTime - timebase); timebase = elapsedTime; frame = 0; } glutPostRedisplay(); glutTimerFunc(30, update, 0); }
void idle() { keyboardEvent(); int time_ = glutGet(GLUT_ELAPSED_TIME); float angle = time_ / 1000.0 * 10; Vector3 pos = player.getPosition(); float angX = player.getRotationX(), angY = player.getRotationY(); Vector3 cpos = cube.getPosition(), cpos2= cube2.getPosition(); GLfloat D = cpos.distance(&cpos2), W = (cube.dimension() + cube2.dimension())/2; float bound = 6.0; //if(time_%100 < 10) // gravity = Vector3(rand()%10-5, rand()%10-5, rand()%10-5); cvelocity.add(&gravity); Vector3 s = cvelocity; s.mult(-mass/1000).add(&cpos2); bool collides = true; if(cpos2.x < -bound && cvelocity.x > 0.0f){ cvelocity.x = -abs(cvelocity.x)*0.5; gravity.x = -abs(gravity.x); } else if(cpos2.x > bound && cvelocity.x < 0.0f){ cvelocity.x = abs(cvelocity.x)*0.5; gravity.x = abs(gravity.x); } else if(cpos2.y < -bound && cvelocity.y > 0.0f){ cvelocity.y = -abs(cvelocity.y)*0.5; gravity.y = -abs(gravity.y); } else if(cpos2.y > bound && cvelocity.y < 0.0f){ cvelocity.y = abs(cvelocity.y)*0.5; gravity.y = abs(gravity.y); } else if(cpos2.z < -bound && cvelocity.z > 0.0f){ cvelocity.z = -abs(cvelocity.z)*0.5; gravity.z = -abs(gravity.z); } else if(cpos2.z > bound && cvelocity.z < 0.0f){ cvelocity.z = abs(cvelocity.z)*0.5; gravity.z = abs(gravity.z); } else{ collides = false; } if(!collides){ if(cpos.x + cube.min.x <= cpos2.x + cube2.max.x && cpos.x + cube.max.x >= cpos2.x + cube2.min.x && cpos.z + cube.min.z <= cpos2.z + cube2.max.z && cpos.z + cube.max.z >= cpos2.z + cube2.min.z && cpos.y + cube.min.y <= cpos2.y + cube2.max.y && cpos.y + cube.max.y >= cpos2.y + cube2.min.y){ collides = true; cvelocity.x = cvelocity.y = cvelocity.z = 0.0f; } if(!collides) cube2.setPosition(s); } player.updateForce(); for (int i = 0; i < BALLS; i++){ balls[i].updateForce(); Vector3 ball_pos = balls[i].getPosition(), ball_vel = balls[i].dynamics.velocity; //printf("x: %f, y: %f, z %f: %f\n", ball_pos.x, ball_pos.y, ball_pos.z, BOUNDARY); if(ball_pos.x < -BOUNDARY || ball_pos.x > BOUNDARY) balls[i].addVelocity(Vector3(-2 * ball_vel.x, 0.0f, 0.0f)); if(ball_pos.y < -BOUNDARY || ball_pos.y > BOUNDARY) balls[i].addVelocity(Vector3(0.0f, -2 * ball_vel.y, 0.0f)); if(ball_pos.z < -BOUNDARY || ball_pos.z > BOUNDARY) balls[i].addVelocity(Vector3(0.0f, 0.0f, -2 * ball_vel.z)); } Matrix4 model = cube.getTransformMatrix(), model2 = cube2.getTransformMatrix(); Matrix4 projection = Matrix4().Perspective(45.0f, 1.0f*screen_width/screen_height, 0.1f, 50.0f), view = Matrix4().lookAt(pos, Vector3(pos.x-cos(angX), pos.y + sin(angY), pos.z + sin(angX)), Vector3(0.0f, 1.0f, 0.0f)); Matrix4 anim = Matrix4().RotateA(angle*3.0f, Vector3(1, 0, 0)) * // X axis Matrix4().RotateA(angle*2.0f, Vector3(0, 1, 0)) * // Y axis Matrix4().RotateA(angle*4.0f, Vector3(0, 0, 1)); // Z axis Matrix4 m_transform = projection * view; glUseProgram(cube.getProgram()); glUniformMatrix4fv(cube.getUniform("m_transform"), 1, GL_FALSE, m_transform * model); glUseProgram(cube2.getProgram()); glUniformMatrix4fv(cube2.getUniform("m_transform"), 1, GL_FALSE, m_transform * model2); for (int i = 0; i < BALLS; i++){ glUseProgram(balls[i].getProgram()); glUniformMatrix4fv( balls[i].getUniform("m_transform"), // m_transform is the transformation of balls[i] in shaders 1, // one uniform-buffer GL_FALSE, // no nprmalization m_transform * balls[i].getTransformMatrix() ); } for (int i = 0; i < DETAIL_GRID*3; i++){ grid[i].updateForce(); glUseProgram(grid[i].getProgram()); glUniformMatrix4fv( grid[i].getUniform("m_transform"), // m_transform is the transformation of grid[i] in shaders 1, // one uniform-buffer GL_FALSE, // no nprmalization m_transform * grid[i].getTransformMatrix() ); } glutPostRedisplay(); }
Vector3 operator+(Vector3 vectorA, const Vector3& vectorB) { return vectorA.add(vectorB); }