void cMonster::SetPitchAndYawFromDestination() { Vector3d FinalDestination = m_FinalDestination; if (m_Target != NULL) { if (m_Target->IsPlayer()) { FinalDestination.y = ((cPlayer *)m_Target)->GetStance(); } else { FinalDestination.y = GetHeight(); } } Vector3d Distance = FinalDestination - GetPosition(); if (Distance.SqrLength() > 0.1f) { { double Rotation, Pitch; Distance.Normalize(); VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch); SetHeadYaw(Rotation); SetPitch(-Pitch); } { Vector3d BodyDistance = m_Destination - GetPosition(); double Rotation, Pitch; Distance.Normalize(); VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch); SetYaw(Rotation); } } }
void cMonster::SetPitchAndYawFromDestination(bool a_IsFollowingPath) { Vector3d BodyDistance; if (!a_IsFollowingPath && (GetTarget() != nullptr)) { BodyDistance = GetTarget()->GetPosition() - GetPosition(); } else { BodyDistance = m_NextWayPointPosition - GetPosition(); } double BodyRotation, BodyPitch; BodyDistance.Normalize(); VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, BodyRotation, BodyPitch); SetYaw(BodyRotation); Vector3d HeadDistance; if (GetTarget() != nullptr) { if (GetTarget()->IsPlayer()) // Look at a player { HeadDistance = GetTarget()->GetPosition() - GetPosition(); } else // Look at some other entity { HeadDistance = GetTarget()->GetPosition() - GetPosition(); // HeadDistance.y = GetTarget()->GetPosY() + GetHeight(); } } else // Look straight { HeadDistance = BodyDistance; HeadDistance.y = 0; } double HeadRotation, HeadPitch; HeadDistance.Normalize(); VectorToEuler(HeadDistance.x, HeadDistance.y, HeadDistance.z, HeadRotation, HeadPitch); if ((std::abs(BodyRotation - HeadRotation) < 70) && (std::abs(HeadPitch) < 60)) { SetHeadYaw(HeadRotation); SetPitch(-HeadPitch); } else { SetHeadYaw(BodyRotation); SetPitch(0); } }
void Entity::BillboardXZ(Entity *Target) { Vector3d Projection; // Vector dirección proyectado en el plano XZ. Vector3d AxisX(1,0,0); // Eje de las X. Nos interesa averiguar el ángulo que forma Projection con este eje. Vector3d Normal; // Indica si el ángulo es negativo o positivo. float AngleCosine; // Coseno del ángulo. // Obtenemos el vector dirección, lo proyectamos sobre XZ y lo normalizamos. Target->Position.Subtract(Position, Projection); Projection.y = 0; Projection.Normalize(); // Calculamos el angulo que forman el vector direccion y el eje de las X. AngleCosine = AxisX.DotProduct(Projection); // Evitamos posibles problemas de precisión if (AngleCosine > 1) AngleCosine = 1; else if (AngleCosine < -1) AngleCosine = -1; // Determinamos si el angulo es positivo o negativo. Normal = AxisX.CrossProduct(Projection); if( Normal.x==0 && Normal.y==0 && Normal.z==0 ) Normal.y=1; // Realizamos el giro de las coordenadas cilíndricas if( Normal.y>0 ) SetRotationY(acos(AngleCosine) * 180.0f/3.14f); else SetRotationY(-acos(AngleCosine) * 180.0f/3.14f); }
colorf DefaultShader::Run(const ShaderArgs &args) { // std::cout << "DefaultShader Run" << std::endl; colorf color = args.scene->GetAmbientLight(); std::vector<SimpleLight *> lightList = args.scene->GetLightList(); for (std::vector<SimpleLight *>::const_iterator i = lightList.begin(); i != lightList.end(); i++) { const SimpleLight *l = *i; // cast a ray at each light, see if we're in a shadow Ray ray; ray.origin = args.pos + args.normal * 0.001f; ray.dir = l->GetPos() - ray.origin; ray.dir.Normalize(); ray.light = true; // std::cout << "casting ray back to light" << std::endl; if (!args.scene->DoesIntersect(ray, (ray.origin - l->GetPos()).Length())) { Vector3d suntosurface = l->GetPos() - args.pos; suntosurface.Normalize(); // std::cout << "does not intersect" << std::endl; float light = Dot(suntosurface, args.normal); // calculate falloff color += (l->GetColor() * light) * m_DiffuseColor; } } // std::cout << "color " << color << std::endl; // see how much of it is a pure reflection if (m_Shinyness > 0.0f) { Ray ray; ray.origin = args.pos; // calculate the reflection ray float d = Dot(args.ray->dir, args.normal); Vector3d reflect( args.ray->dir.getx() - 2.0 * d * args.normal.getx(), args.ray->dir.gety() - 2.0 * d * args.normal.gety(), args.ray->dir.getz() - 2.0 * d * args.normal.getz()); ray.dir = reflect; color *= (1.0f - m_Shinyness); // recursively trace to see colorf reflectcolor; if (args.tracer->Cast(reflectcolor, ray)) { color += reflectcolor * m_Shinyness; } } // std::cout << "default shader color " << color << std::endl; return color; }
void cMonster::SetPitchAndYawFromDestination() { Vector3d FinalDestination = m_FinalDestination; if (m_Target != nullptr) { if (m_Target->IsPlayer()) { FinalDestination.y = static_cast<cPlayer *>(m_Target)->GetStance() - 1; } else { FinalDestination.y = m_Target->GetPosY() + GetHeight(); } } Vector3d BodyDistance; if (!m_IsFollowingPath && (m_Target != nullptr)) { BodyDistance = m_Target->GetPosition() - GetPosition(); } else { BodyDistance = m_NextWayPointPosition - GetPosition(); } double BodyRotation, BodyPitch; BodyDistance.Normalize(); VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, BodyRotation, BodyPitch); SetYaw(BodyRotation); Vector3d Distance = FinalDestination - GetPosition(); { double HeadRotation, HeadPitch; Distance.Normalize(); VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch); if (std::abs(BodyRotation - HeadRotation) < 90) { SetHeadYaw(HeadRotation); SetPitch(-HeadPitch); } else // We're not an owl. If it's more than 120, don't look behind and instead look at where you're walking. { SetHeadYaw(BodyRotation); SetPitch(-BodyPitch); } } }
void cMonster::MoveToWayPoint(cChunk & a_Chunk) { if ((m_NextWayPointPosition - GetPosition()).SqrLength() < WAYPOINT_RADIUS * WAYPOINT_RADIUS) { return; } if (m_JumpCoolDown == 0) { if (DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y))) { if (((IsOnGround()) && (GetSpeed().SqrLength() == 0.0f)) || (IsSwimming())) { m_bOnGround = false; m_JumpCoolDown = 20; // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport AddPosY(1.6); // Jump!! SetSpeedX(3.2 * (m_NextWayPointPosition.x - GetPosition().x)); // Move forward in a preset speed. SetSpeedZ(3.2 * (m_NextWayPointPosition.z - GetPosition().z)); // The numbers were picked based on trial and error and 1.6 and 3.2 are perfect. } } } else { --m_JumpCoolDown; } Vector3d Distance = m_NextWayPointPosition - GetPosition(); if ((Distance.x != 0.0f) || (Distance.z != 0.0f)) { Distance.y = 0; Distance.Normalize(); if (m_bOnGround) { Distance *= 2.5f; } else if (IsSwimming()) { Distance *= 1.3f; } else { // Don't let the mob move too much if he's falling. Distance *= 0.25f; } // Apply walk speed: Distance *= m_RelativeWalkSpeed; /* Reduced default speed. Close to Vanilla, easier for mobs to follow m_NextWayPointPositions, hence better pathfinding. */ Distance *= 0.5; AddSpeedX(Distance.x); AddSpeedZ(Distance.z); } }
Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const { Vector3d res = GetLookVector(); res.Normalize(); // TODO: Add a slight random change (+-0.0075 in each direction) return res * a_SpeedCoeff; }
void Rotation::setValue(const Vector3d & axis, const double fAngle) { // Taken from <http://de.wikipedia.org/wiki/Quaternionen> // this->quat[3] = (double)cos(fAngle/2.0); Vector3d norm = axis; norm.Normalize(); double scale = (double)sin(fAngle/2.0); this->quat[0] = norm.x * scale; this->quat[1] = norm.y * scale; this->quat[2] = norm.z * scale; }
// Retun the normal for an arbitary polygon Vector3d PolygonNormal(Vector3d polyData[]) { // Construct a normal for this polygon Vector3d v1 = polyData[0] - polyData[1]; Vector3d v2 = polyData[1] - polyData[2]; Vector3d normal; normal = Vector3d::CrossProduct(v1, v2); // Make sure this normal is a unit vector normal.Normalize(); return normal; }
void PolygonGraphRenderer::PreparePolygons() { m_displayListPolygons.Init(); m_displayListPolygons.Open(); for (PolygonGraph::CenterPtr p : m_graph.m_centers) { std::vector<PolygonGraph::CornerPtr> vecCorners = p->corners; // order them clockwise std::sort(vecCorners.begin(), vecCorners.end(), PolygonGraph::CornerSorter(p->point)); // draw triangle fan glBegin(GL_TRIANGLE_FAN); Color c = PolygonGraph::ColorByBiomeType(p->enBiomeType); //Color c = PolygonGraph::ColorByTerrainType(p->enTerrainType); //Color c = PolygonGraph::ColorByElevation(p->elevation); //Color c = PolygonGraph::ColorByMoisture(p->moisture); glColor3ubv(c.m_color); // normal ATLASSERT(vecCorners.size() >= 2); Vector3d center(p->point.X(), p->elevation * c_dElevationScaleFactor, p->point.Y()); Vector3d p1(vecCorners[0]->point.X(), vecCorners[0]->elevation * c_dElevationScaleFactor, vecCorners[0]->point.Y()); Vector3d p2(vecCorners[1]->point.X(), vecCorners[1]->elevation * c_dElevationScaleFactor, vecCorners[1]->point.Y()); Vector3d normal; normal.Cross(center-p1, center-p2); normal.Normalize(); glNormal3dv(normal.Data()); // center glVertex3d(p->point.X(), p->elevation * c_dElevationScaleFactor, p->point.Y()); for (PolygonGraph::CornerPtr q : vecCorners) glVertex3d(q->point.X(), q->elevation * c_dElevationScaleFactor, q->point.Y()); glVertex3d(vecCorners[0]->point.X(), vecCorners[0]->elevation * c_dElevationScaleFactor, vecCorners[0]->point.Y()); glEnd(); } m_displayListPolygons.Close(); }
void CSimObjMoveable::Calc(float total, float dt) { Vector3d v = (m_dir-m_pos); v.Normalize(); m_pos.x += v.x * m_speed * dt; m_pos.y += v.y * m_speed * dt; m_pos.z += v.z * m_speed * dt; if (Reached(m_dir, m_pos)) { m_pos = m_dir; if (m_path.Count() > 1) { m_next_node = (m_next_node + 1) % m_path.Count(); m_dir = m_path.GetNode(m_next_node); } } //m_pos += v * m_speed * dt; }
void ModelDisplayState::RenderModelNormals(const Group& group) const { AnimatedModel3d& model = *m_spModel->GetAnimated(); const Data& data = model.GetData(); OpenGL::PushedAttributes attrib(GL_LINE_BIT | GL_ENABLE_BIT | GL_CURRENT_BIT); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); glLineWidth(2.0f); glBegin(GL_LINES); for (size_t uiTriangleIndex : group.m_vecTriangleIndices) { ATLASSERT(uiTriangleIndex < data.m_vecTriangles.size()); const Triangle& t = data.m_vecTriangles[uiTriangleIndex]; for (unsigned int v=0; v<3; v++) { size_t vertexIndex = t.auiVertexIndices[v]; const Vertex& vert = data.m_vecVertices[vertexIndex]; Vector3d vVertex = vert.m_vPos; model.TransformVertex(vert, m_vecJointRenderData, vVertex); Vector3d vNormal = t.aNormals[v]; model.TransformNormal(vert, m_vecJointRenderData, vNormal); vNormal.Normalize(); vNormal *= 0.1; vNormal += vVertex; glVertex3dv(vVertex.Data()); glVertex3dv(vNormal.Data()); } } glEnd(); }
bool Matrix4D::toAxisAngle (Vector3d& rclBase, Vector3d& rclDir, double& rfAngle, double& fTranslation) const { // First check if the 3x3 submatrix is orthogonal for ( int i=0; i<3; i++ ) { // length must be one if ( fabs(dMtrx4D[0][i]*dMtrx4D[0][i]+dMtrx4D[1][i]*dMtrx4D[1][i]+dMtrx4D[2][i]*dMtrx4D[2][i]-1.0) > 0.01 ) return false; // scalar product with other rows must be zero if ( fabs(dMtrx4D[0][i]*dMtrx4D[0][(i+1)%3]+dMtrx4D[1][i]*dMtrx4D[1][(i+1)%3]+dMtrx4D[2][i]*dMtrx4D[2][(i+1)%3]) > 0.01 ) return false; } // Okay, the 3x3 matrix is orthogonal. // Note: The section to get the rotation axis and angle was taken from WildMagic Library. // // Let (x,y,z) be the unit-length axis and let A be an angle of rotation. // The rotation matrix is R = I + sin(A)*P + (1-cos(A))*P^2 where // I is the identity and // // +- -+ // P = | 0 -z +y | // | +z 0 -x | // | -y +x 0 | // +- -+ // // If A > 0, R represents a counterclockwise rotation about the axis in // the sense of looking from the tip of the axis vector towards the // origin. Some algebra will show that // // cos(A) = (trace(R)-1)/2 and R - R^t = 2*sin(A)*P // // In the event that A = pi, R-R^t = 0 which prevents us from extracting // the axis through P. Instead note that R = I+2*P^2 when A = pi, so // P^2 = (R-I)/2. The diagonal entries of P^2 are x^2-1, y^2-1, and // z^2-1. We can solve these for axis (x,y,z). Because the angle is pi, // it does not matter which sign you choose on the square roots. // // For more details see also http://www.math.niu.edu/~rusin/known-math/97/rotations double fTrace = dMtrx4D[0][0] + dMtrx4D[1][1] + dMtrx4D[2][2]; double fCos = 0.5*(fTrace-1.0); rfAngle = acos(fCos); // in [0,PI] if ( rfAngle > 0.0f ) { if ( rfAngle < F_PI ) { rclDir.x = (dMtrx4D[2][1]-dMtrx4D[1][2]); rclDir.y = (dMtrx4D[0][2]-dMtrx4D[2][0]); rclDir.z = (dMtrx4D[1][0]-dMtrx4D[0][1]); rclDir.Normalize(); } else { // angle is PI double fHalfInverse; if ( dMtrx4D[0][0] >= dMtrx4D[1][1] ) { // r00 >= r11 if ( dMtrx4D[0][0] >= dMtrx4D[2][2] ) { // r00 is maximum diagonal term rclDir.x = (0.5*sqrt(dMtrx4D[0][0] - dMtrx4D[1][1] - dMtrx4D[2][2] + 1.0)); fHalfInverse = 0.5/rclDir.x; rclDir.y = (fHalfInverse*dMtrx4D[0][1]); rclDir.z = (fHalfInverse*dMtrx4D[0][2]); } else { // r22 is maximum diagonal term rclDir.z = (0.5*sqrt(dMtrx4D[2][2] - dMtrx4D[0][0] - dMtrx4D[1][1] + 1.0)); fHalfInverse = 0.5/rclDir.z; rclDir.x = (fHalfInverse*dMtrx4D[0][2]); rclDir.y = (fHalfInverse*dMtrx4D[1][2]); } } else { // r11 > r00 if ( dMtrx4D[1][1] >= dMtrx4D[2][2] ) { // r11 is maximum diagonal term rclDir.y = (0.5*sqrt(dMtrx4D[1][1] - dMtrx4D[0][0] - dMtrx4D[2][2] + 1.0)); fHalfInverse = 0.5/rclDir.y; rclDir.x = (fHalfInverse*dMtrx4D[0][1]); rclDir.z = (fHalfInverse*dMtrx4D[1][2]); } else { // r22 is maximum diagonal term rclDir.z = (0.5*sqrt(dMtrx4D[2][2] - dMtrx4D[0][0] - dMtrx4D[1][1] + 1.0)); fHalfInverse = 0.5/rclDir.z; rclDir.x = (fHalfInverse*dMtrx4D[0][2]); rclDir.y = (fHalfInverse*dMtrx4D[1][2]); } } } } else { // The angle is 0 and the matrix is the identity. Any axis will // work, so just use the x-axis. rclDir.x = 1.0; rclDir.y = 0.0; rclDir.z = 0.0; rclBase.x = 0.0; rclBase.y = 0.0; rclBase.z = 0.0; } // This is the translation part in axis direction fTranslation = (dMtrx4D[0][3]*rclDir.x+dMtrx4D[1][3]*rclDir.y+dMtrx4D[2][3]*rclDir.z); Vector3d cPnt(dMtrx4D[0][3],dMtrx4D[1][3],dMtrx4D[2][3]); cPnt = cPnt - fTranslation * rclDir; // This is the base point of the rotation axis if ( rfAngle > 0.0f ) { double factor = 0.5*(1.0+fTrace)/sin(rfAngle); rclBase.x = (0.5*(cPnt.x+factor*(rclDir.y*cPnt.z-rclDir.z*cPnt.y))); rclBase.y = (0.5*(cPnt.y+factor*(rclDir.z*cPnt.x-rclDir.x*cPnt.z))); rclBase.z = (0.5*(cPnt.z+factor*(rclDir.x*cPnt.y-rclDir.y*cPnt.x))); } return true; }
void cMonster::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); if (m_Health <= 0) { // The mob is dead, but we're still animating the "puff" they leave when they die m_DestroyTimer += a_Dt / 1000; if (m_DestroyTimer > 1) { Destroy(true); } return; } // Burning in daylight HandleDaylightBurning(a_Chunk); HandlePhysics(a_Dt,a_Chunk); BroadcastMovementUpdate(); a_Dt /= 1000; if (m_bMovingToDestination) { Vector3f Pos( GetPosition() ); Vector3f Distance = m_Destination - Pos; if( !ReachedDestination() ) { Distance.y = 0; Distance.Normalize(); Distance *= 3; SetSpeedX( Distance.x ); SetSpeedZ( Distance.z ); if (m_EMState == ESCAPING) { //Runs Faster when escaping :D otherwise they just walk away SetSpeedX (GetSpeedX() * 2.f); SetSpeedZ (GetSpeedZ() * 2.f); } } else { m_bMovingToDestination = false; } if( GetSpeed().SqrLength() > 0.f ) { if( m_bOnGround ) { Vector3f NormSpeed = Vector3f(GetSpeed()).NormalizeCopy(); Vector3f NextBlock = Vector3f( GetPosition() ) + NormSpeed; int NextHeight; if (!m_World->TryGetHeight((int)NextBlock.x, (int)NextBlock.z, NextHeight)) { // The chunk at NextBlock is not loaded return; } if( NextHeight > (GetPosY() - 1.0) && (NextHeight - GetPosY()) < 2.5 ) { m_bOnGround = false; SetSpeedY(5.f); // Jump!! } } } } Vector3d Distance = m_Destination - GetPosition(); if (Distance.SqrLength() > 0.1f) { double Rotation, Pitch; Distance.Normalize(); VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch ); SetHeadYaw (Rotation); SetRotation( Rotation ); SetPitch( -Pitch ); } switch (m_EMState) { case IDLE: { // If enemy passive we ignore checks for player visibility InStateIdle(a_Dt); break; } case CHASING: { // If we do not see a player anymore skip chasing action InStateChasing(a_Dt); break; } case ESCAPING: { InStateEscaping(a_Dt); break; } } // switch (m_EMState) }
void cMonster::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); if (m_Health <= 0) { // The mob is dead, but we're still animating the "puff" they leave when they die m_DestroyTimer += a_Dt / 1000; if (m_DestroyTimer > 1) { Destroy(true); } return; } if ((m_Target != NULL) && m_Target->IsDestroyed()) m_Target = NULL; // Burning in daylight HandleDaylightBurning(a_Chunk); a_Dt /= 1000; if (m_bMovingToDestination) { if (m_bOnGround) { if (DoesPosYRequireJump((int)floor(m_Destination.y))) { m_bOnGround = false; // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport AddPosY(1.2); // Jump!! } } Vector3d Distance = m_Destination - GetPosition(); if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move { Distance.y = 0; Distance.Normalize(); if (m_bOnGround) { Distance *= 2.5f; } else if (IsSwimming()) { Distance *= 1.3f; } else { // Don't let the mob move too much if he's falling. Distance *= 0.25f; } // Apply walk speed: Distance *= m_RelativeWalkSpeed; AddSpeedX(Distance.x); AddSpeedZ(Distance.z); // It's too buggy! /* if (m_EMState == ESCAPING) { // Runs Faster when escaping :D otherwise they just walk away SetSpeedX (GetSpeedX() * 2.f); SetSpeedZ (GetSpeedZ() * 2.f); } */ } else { if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate { FinishPathFinding(); } else { TickPathFinding(); // We have reached the next point in our path, calculate another point } } } SetPitchAndYawFromDestination(); HandleFalling(); switch (m_EMState) { case IDLE: { // If enemy passive we ignore checks for player visibility InStateIdle(a_Dt); break; } case CHASING: { // If we do not see a player anymore skip chasing action InStateChasing(a_Dt); break; } case ESCAPING: { InStateEscaping(a_Dt); break; } case ATTACKING: break; } // switch (m_EMState) BroadcastMovementUpdate(); }