private static Matrix3D GetProjectionMatrix(PerspectiveCamera camera, double aspectRatio) { if (camera == null) { throw new ArgumentNullException("camera"); } // This math is identical to what you find documented for // D3DXMatrixPerspectiveFovRH with the exception that in // WPF the camera's horizontal rather the vertical // field-of-view is specified. double hFoV = Math1D.DegreesToRadians(camera.FieldOfView); double zn = camera.NearPlaneDistance; double zf = camera.FarPlaneDistance; double xScale = 1 / Math.Tan(hFoV / 2); double yScale = aspectRatio * xScale; double m33 = (zf == double.PositiveInfinity) ? -1 : (zf / (zn - zf)); double m43 = zn * m33; return(new Matrix3D( xScale, 0, 0, 0, 0, yScale, 0, 0, 0, 0, m33, -1, 0, 0, m43, 0)); }
private static void AddArc(ScreenSpaceLines3D line, Point3D center, double radius, int segments, double startAngle, double stopAngle, bool closeEnd) { startAngle = Math1D.DegreesToRadians(startAngle); stopAngle = Math1D.DegreesToRadians(stopAngle); // swap angles if (startAngle > stopAngle) { double temp = startAngle; startAngle = stopAngle; stopAngle = temp; } Point3D[] points = new Point3D[segments + 1]; double inc = (stopAngle - startAngle) / segments; double r = startAngle; for (int i = 0; i <= segments; i++, r += inc) { points[i] = new Point3D( center.X + (Math.Cos(-r) * radius), center.Y + (Math.Sin(-r) * radius), center.Z); } line.AddPolygon(closeEnd, points); }
private void PhysicsBody_ApplyForceAndTorque(object sender, BodyApplyForceAndTorqueArgs e) { // See if there is anything to do if (_desiredOrientation == null) { return; } //TODO: Implement this.Offset //TODO: Allow rotations in the destination axis Vector3D current = e.Body.DirectionToWorld(new Vector3D(0, 0, 1)); Quaternion rotation = Math3D.GetRotation(current, _desiredOrientation.Value); if (rotation.IsIdentity) { // Don't set anything. If they are rotating along the allowed axis, then no problem. If they try // to rotate off that axis, another iteration of this method will rotate back //e.Body.AngularVelocity = new Vector3D(0, 0, 0); return; } // According to the newton wiki, angular velociy is radians per second Vector3D newAngVel = rotation.Axis.ToUnit() * Math1D.DegreesToRadians(rotation.Angle); newAngVel *= _multiplier; if (this.MaxVelocity != null && newAngVel.LengthSquared > this.MaxVelocity.Value * this.MaxVelocity.Value) { newAngVel = newAngVel.ToUnit() * this.MaxVelocity.Value; } e.Body.AngularVelocity = newAngVel; }
/// <summary> /// This defines the back side of a cylinder /// </summary> private static Geometry3D GetGeometry(int numSegments, double thetaOffset, double height, double radius, double translate) { double thetaStart = 270 - thetaOffset; double thetaStop = 270 + thetaOffset; MeshGeometry3D retVal = new MeshGeometry3D(); #region Initial calculations // The rest of this method has height along Z, but the final needs to go along Y Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90d))); //transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 180d))); transform.Children.Add(new TranslateTransform3D(0, 0, translate)); double halfHeight = height / 2d; Point[] points = new Point[numSegments]; double deltaTheta = Math1D.DegreesToRadians((thetaStop - thetaStart) / (numSegments - 1)); //NOTE: This will fail if theta start/stop goes past 0/360 double theta = Math1D.DegreesToRadians(thetaStart); for (int cntr = 0; cntr < numSegments; cntr++) { points[cntr] = new Point(Math.Cos(theta) * radius, Math.Sin(theta) * radius); theta += deltaTheta; } #endregion for (int cntr = 0; cntr < numSegments; cntr++) { retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X, points[cntr].Y, -halfHeight))); retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X, points[cntr].Y, halfHeight))); retVal.Normals.Add(transform.Transform(new Vector3D(-points[cntr].X, -points[cntr].Y, 0d))); // the normals point straight in from the side retVal.Normals.Add(transform.Transform(new Vector3D(-points[cntr].X, -points[cntr].Y, 0d))); double coord = Convert.ToDouble(cntr) / Convert.ToDouble(numSegments - 1); retVal.TextureCoordinates.Add(new Point(coord, 0)); retVal.TextureCoordinates.Add(new Point(coord, 1)); } for (int cntr = 0; cntr < numSegments - 1; cntr++) { // 0,2,3 retVal.TriangleIndices.Add((cntr * 2) + 0); retVal.TriangleIndices.Add((cntr * 2) + 3); retVal.TriangleIndices.Add((cntr * 2) + 2); // 0,3,1 retVal.TriangleIndices.Add((cntr * 2) + 0); retVal.TriangleIndices.Add((cntr * 2) + 1); retVal.TriangleIndices.Add((cntr * 2) + 3); } return(retVal); }
private void Brain_StraightToTarget_VelocityAware2() { // Velocity should be zero when touching the chase point //TODO: Implement this (when not attacking, velocity should slow to a max speed the closer to the chase point) // Convert everything to local coords Point3D position = new Point3D(0, 0, 0); Point3D chasePoint = this.PhysicsBody.PositionFromWorld(_chasePoint); Vector3D directionToGo = chasePoint.ToVector() - position.ToVector(); Quaternion rotation; #region Adjust for current velocity attempt1a Vector3D currentVelocity = this.VelocityWorld; if (!Math1D.IsNearZero(currentVelocity.LengthSquared)) { currentVelocity = this.PhysicsBody.DirectionFromWorld(currentVelocity); rotation = Math3D.GetRotation(directionToGo, currentVelocity); // This is how much to rotate direction to align with current velocity, I want to go against the current velocity (if aligned, // the angle will be zero, so negating won't make a difference) rotation = rotation.ToReverse(); // If it's greater than 90 degrees, then just use the original direction (because it will pull the velocity in line // eventually) I don't multiply by .5, because when it is very close to 90 degrees, the bot will thrash a bit if (Math.Abs(Math1D.DegreesToRadians(rotation.Angle)) < Math.PI * .4d) { // Change the direction by the angle directionToGo = rotation.GetRotatedVector(directionToGo); } } #endregion // Now that I know where to go, rotate the original thruster direction (0,1,0) to line up with the desired direction rotation = Math3D.GetRotation(_origThrustDirection, directionToGo); // Thrust Direction _thrustTransform = new RotateTransform3D(new QuaternionRotation3D(rotation)); // Thrust Strength if (_isAttacking) { _thrustPercent = 1d; } else { _thrustPercent = .5d; } }
/// <summary> /// This will emulate sounds coming from locations relative to the listener /// </summary> /// <remarks> /// Note that sound intensity doesn't diminish linearly from by distance, but by: /// I = P/(4*pi*r^2) /// /// I is final intensity /// P is intensity at the source /// r is distance from the listener /// </remarks> /// <param name="volume">0 (none) to 1 (full)</param> /// <param name="balance">-1 (all left) to 1 (all right)</param> /// <param name="offset">The location of the sound relative to the listener</param> /// <param name="sourceVolume">0 (none) to 1 (full) - this is how loud the source would be at the listener</param> private void GetPositionalSoundSettings(out double volume, out double balance, Vector3D offset, double sourceVolume) { #region Calculate Volume // I won't range check the input volume - I'll leave it up to the media player to either bomb or cap it double intensityRatio = 1d; double offsetLength = offset.Length; if (_distanceFalloffRatio == 0d || Math1D.IsNearZero(offsetLength)) { volume = sourceVolume; } else { double distance = offsetLength * _distanceFalloffRatio; intensityRatio = 1d / (4d * Math.PI * distance * distance); // I need this intensity when calculating balance volume = sourceVolume * intensityRatio; } #endregion #region Calculate Balance // This means that if a sound is a distance of very near zero, and all the way to the left or right, then instead of +-1, it is +-.5 const double MAXOPPOSITE_EAR = .5d; // When the intensity would be 75% of max, then I won't add anything to the opposite ear const double MAXOPPOSITE_DISTANCEINTENSITY = .75d; // Getting the angle (I don't want Z) double angle = Vector3D.AngleBetween(new Vector3D(1, 0, 0), new Vector3D(offset.X, offset.Y, 0)); // cos(0) is 1, cos(90) is 0, cos(180) is -1. Exactly what I need balance = Math.Cos(Math1D.DegreesToRadians(angle)); //NOTE: The problem with a pure cosine is that if a loud sound is sitting very near the person, but on the left, then in reality, the right // ear would hear something, but a simple cosine would be all the way -1 // // So, I'm going to approach .5 for objects that are near (still on the left, but can be heard on the right) if (intensityRatio > MAXOPPOSITE_DISTANCEINTENSITY) { // So when the intensity is 1 (right next to the head), then I will give back .5 // When the intensity is at the limit, then balance will be the pure cosine value // Anywhere in between is a linear interpelation balance = UtilityCore.GetScaledValue_Capped(balance, MAXOPPOSITE_EAR * balance, MAXOPPOSITE_DISTANCEINTENSITY, 1d, intensityRatio); } #endregion //TODO: Take in relative velocity, then manipulate playback speed to emulate doppler (unless there is a way to change pitch directly) }
protected override CJoint OnInitialise() { CJointBallSocket joint = new CJointBallSocket(this.World.NewtonWorld); joint.NewtonConstraintCreateBall( (Vector3D)BodyToWorld(this.ChildBody, this.PivotPoint), this.ChildBody.NewtonBody, this.ParentBody.NewtonBody); joint.BallSetConeLimits( BodyToWorld(this.ChildBody, Direction), (float)Math1D.DegreesToRadians(MaxConeAngle), (float)Math1D.DegreesToRadians(MaxTwistAngle)); joint.Ball += InternalUserCallback; return(joint); }
protected void Update() { if (IsInitialised) { if (IsInitialising) { _needsUpdate = true; } else { NetwonJoint.BallSetConeLimits( BodyToWorld(this.ChildBody, Direction), (float)Math1D.DegreesToRadians(MaxConeAngle), (float)Math1D.DegreesToRadians(MaxTwistAngle)); _needsUpdate = false; } } }
private void joint_Hinge(object sender, CHingeEventArgs e) { double newAngle = Math1D.RadiansToDegrees(NewtonJoint.HingeAngle); double angle = this.Angle + AngleDiffence(this.Angle, newAngle); SetValue(AnglePropertyKey, angle); if (this.SetAngle != null) { e.Desc.m_Accel = NewtonJoint.HingeCalculateStopAlpha(e.Desc, Math1D.DegreesToRadians((float)MathUtils.MinMax(this.MinAngle, (double)this.SetAngle, this.MaxAngle))) * (float)this.SetAngleStiffness; e.ApplyConstraint = true; } else if ((this.MinAngle != null) && (angle < (double)this.MinAngle)) { e.Desc.m_Accel = NewtonJoint.HingeCalculateStopAlpha(e.Desc, (float)Math1D.DegreesToRadians((double)this.MinAngle)); e.ApplyConstraint = true; } else if ((this.MaxAngle != null) && (angle > (double)this.MaxAngle)) { e.Desc.m_Accel = NewtonJoint.HingeCalculateStopAlpha(e.Desc, (float)Math1D.DegreesToRadians((double)this.MaxAngle)); e.ApplyConstraint = true; } else { if (this.AngularDamperning != 0) { // -(NewtonJoint.HingeOmega * e.Desc.m_Timestep * (float)this.AngularDamperning); e.Desc.m_Accel = -(NewtonJoint.HingeOmega / e.Desc.m_Timestep) * (float)AngularDamperning; e.ApplyConstraint = true; } if (this.Torque != 0) { e.Desc.m_Accel += (float)this.Torque; e.ApplyConstraint = true; } } }
private Vector3D StraightToTarget_VelocityAware1Worker(Point3D chasePointWorld) { // Convert everything to local coords Point3D position = new Point3D(0, 0, 0); Point3D chasePointLocal = this.PhysicsBody.PositionFromWorld(chasePointWorld); Vector3D directionToGo = chasePointLocal.ToVector() - position.ToVector(); Vector3D axis; double radians; #region Adjust for current velocity attempt1a Vector3D currentVelocity = this.VelocityWorld; if (!Math1D.IsNearZero(currentVelocity.LengthSquared)) { currentVelocity = this.PhysicsBody.DirectionFromWorld(currentVelocity); Quaternion rotation = Math3D.GetRotation(directionToGo, currentVelocity); // This is how much to rotate direction to align with current velocity, I want to go against the current velocity (if aligned, // the angle will be zero, so negating won't make a difference) rotation = rotation.ToReverse(); // If it's greater than 90 degrees, then just use the original direction (because it will pull the velocity in line // eventually) I don't multiply by .5, because when it is very close to 90 degrees, the bot will thrash a bit if (Math.Abs(Math1D.DegreesToRadians(rotation.Angle)) < Math.PI * .4d) { // Change the direction by the angle directionToGo = rotation.GetRotatedVector(directionToGo); } } #endregion // Exit Function return(directionToGo); }
/// <summary> /// Set the properties, then call create /// NOTE: This adds itself to the viewport and world. In the future, that should be handled by the caller /// </summary> public void CreateShip(MaterialManager materialManager, SharedVisuals sharedVisuals, Map map, ProgressBarGame progressBarCargo, ProgressBarGame progressBarFuel) { const double THRUSTLINELENGTH = .5d; const double THRUSTLINELENGTH_EXTRA = .75d; const double THRUSTLINELENGTH_TURN = .3; _sharedVisuals = sharedVisuals; _map = map; _progressBarCargo = progressBarCargo; _progressBarFuel = progressBarFuel; #region Thrusters // These need to be definded before the visuals are created double radians = Math1D.DegreesToRadians(225); _thrusterOffset_BottomLeft = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0); radians = Math1D.DegreesToRadians(135); _thrusterOffset_TopLeft = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0); radians = Math1D.DegreesToRadians(315); _thrusterOffset_BottomRight = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0); radians = Math1D.DegreesToRadians(45); _thrusterOffset_TopRight = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0); _thrustForce = 100d; _torqueballLeftRightThrusterForce = -10d; #region Define ThrustLines //NOTE: The ThrustLine class will add/remove visuals directly from the viewport. There's no need for the map to get involved // The reference to the fuel tank will be made when I create the tank ThrustLine thrustLine; // Up _thrustLines.Add(Key.Up, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _thrustForce, _thrusterOffset_BottomRight); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.Up].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _thrustForce, _thrusterOffset_BottomLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.Up].Add(thrustLine); // W _thrustLines.Add(Key.W, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * (_thrustForce * 2d), _thrusterOffset_BottomRight); thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA; _thrustLines[Key.W].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * (_thrustForce * 2d), _thrusterOffset_BottomLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA; _thrustLines[Key.W].Add(thrustLine); // Down _thrustLines.Add(Key.Down, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _thrustForce, _thrusterOffset_TopRight); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.Down].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _thrustForce, _thrusterOffset_TopLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.Down].Add(thrustLine); // S _thrustLines.Add(Key.S, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * (_thrustForce * 2d), _thrusterOffset_TopRight); thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA; _thrustLines[Key.S].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * (_thrustForce * 2d), _thrusterOffset_TopLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA; _thrustLines[Key.S].Add(thrustLine); // Left _thrustLines.Add(Key.Left, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_BottomRight); thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN; _thrustLines[Key.Left].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_TopLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN; _thrustLines[Key.Left].Add(thrustLine); // Right _thrustLines.Add(Key.Right, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_TopRight); thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN; _thrustLines[Key.Right].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_BottomLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN; _thrustLines[Key.Right].Add(thrustLine); // A _thrustLines.Add(Key.A, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(-1, 0, 0) * _thrustForce, _thrusterOffset_TopRight); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.A].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(-1, 0, 0) * _thrustForce, _thrusterOffset_BottomRight); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.A].Add(thrustLine); // D _thrustLines.Add(Key.D, new List <ThrustLine>()); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(1, 0, 0) * _thrustForce, _thrusterOffset_TopLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.D].Add(thrustLine); thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(1, 0, 0) * _thrustForce, _thrusterOffset_BottomLeft); thrustLine.LineMaxLength = THRUSTLINELENGTH; _thrustLines[Key.D].Add(thrustLine); #endregion #endregion MaterialGroup material = null; GeometryModel3D geometry = null; Model3DGroup models = new Model3DGroup(); ModelVisual3D model = null; #region Interior Extra Visuals // These are visuals that will stay oriented to the ship, but don't count in collision calculations #region Thrusters // These are the little balls, not the thrust lines double thrusterLocScale = 1d; models.Children.Add(GetThrusterVisual(_thrusterOffset_BottomLeft * thrusterLocScale)); models.Children.Add(GetThrusterVisual(_thrusterOffset_BottomRight * thrusterLocScale)); models.Children.Add(GetThrusterVisual(_thrusterOffset_TopLeft * thrusterLocScale)); models.Children.Add(GetThrusterVisual(_thrusterOffset_TopRight * thrusterLocScale)); #endregion #region Cargo Bay //TODO: Make a visual for this (probably pretty cube like) _cargoBay = new CargoBay(_cargoBayMass, _cargoBayVolume); _progressBarCargo.Minimum = 0d; _progressBarCargo.Maximum = _cargoBay.MaxVolume; _progressBarCargo.Value = 0d; #endregion #region Fuel Tank //TODO: This visual should be a pill _fuelTank = new FuelTank(); _fuelTank.DryMass = _fuelTankMass; _fuelTank.QuantityMax = _fuelTankCapacity; _fuelTank.QuantityCurrent = _fuelTank.QuantityMax; // a full tank with the purchace of a new ship!!! _fuelTank.FuelDensity = _fuelDensity; _progressBarFuel.Minimum = 0d; _progressBarFuel.Maximum = _fuelTank.QuantityMax; _progressBarFuel.Value = _fuelTank.QuantityCurrent; // Link to the thrusters foreach (List <ThrustLine> thrustLines in _thrustLines.Values) { foreach (ThrustLine thrustLine1 in thrustLines) { thrustLine1.FuelToThrustRatio = _fuelThrustRatio; thrustLine1.FuelTank = _fuelTank; } } #endregion #region Core // This just looks stupid. The idea is that you would see the various components (which would also be point masses). But until // the user can modify their ship, it's just an arbitrary ellipse that is ugly //// Material //material = new MaterialGroup(); //material.Children.Add(new DiffuseMaterial(Brushes.DimGray)); //material.Children.Add(new SpecularMaterial(Brushes.DimGray, 100d)); //// Geometry Model //geometry = new GeometryModel3D(); //geometry.Material = material; //geometry.BackMaterial = material; //geometry.Geometry = UtilityWPF.GetSphere(5, .45, .25, .05); //geometry.Transform = new TranslateTransform3D(0, this.RadiusY * -.25, 0); //// Model Visual //model = new ModelVisual3D(); //model.Content = geometry; ////NOTE: model.Transform is set to the physics body's transform every frame //// Add to the viewport //_viewport.Children.Add(model); //_visuals.Add(model); #endregion // Make a model visual for what I have so far model = new ModelVisual3D(); // this is the expensive one, so as few of these should be made as possible model.Content = models; _visuals.Add(model); _map.Viewport.Children.Add(model); #endregion #region WPF Collision Model // Material //NOTE: There seems to be an issue with drawing objects inside a semitransparent object - I think they have to be added in a certain order or something //Brush skinBrush = new SolidColorBrush(Color.FromArgb(50, _hullColor.R, _hullColor.G, _hullColor.B)); // making the skin semitransparent, so you can see the components inside Brush skinBrush = new SolidColorBrush(_hullColor); // decided to make it opaque, since I'm not showing anything inside material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(skinBrush)); material.Children.Add(new SpecularMaterial(Brushes.White, 75d)); // more reflective (and white light) MaterialGroup backMaterial = new MaterialGroup(); backMaterial.Children.Add(new DiffuseMaterial(skinBrush)); backMaterial.Children.Add(new SpecularMaterial(new SolidColorBrush(Color.FromArgb(255, 20, 20, 20)), 10d)); // dark light, and not very reflective // Geometry Model geometry = new GeometryModel3D(); geometry.Material = material; geometry.BackMaterial = backMaterial; geometry.Geometry = UtilityWPF.GetSphere_LatLon(5, this.RadiusX, this.RadiusY, this.RadiusZ); // Transform Transform3DGroup transform = new Transform3DGroup(); // rotate needs to be added before translate transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 0))); transform.Children.Add(new TranslateTransform3D(new Vector3D(0, 0, 0))); // Model Visual model = new ModelVisual3D(); model.Content = geometry; model.Transform = transform; _physicsModel = model; // remember this, so I don't set its transform _visuals.Add(model); // Add to the viewport (the physics body constructor requires it to be added) _map.Viewport.Children.Add(model); #endregion #region Physics Body // Make a physics body that represents this shape _physicsBody = new ConvexBody3D(_map.World, model); _physicsBody.MaterialGroupID = materialManager.ShipMaterialID; _physicsBody.NewtonBody.UserData = this; _physicsBody.Mass = Convert.ToSingle(this.TotalMass); _physicsBody.LinearDamping = .01f; //_physicsBody.AngularDamping = new Vector3D(.01f, .01f, .01f); //_physicsBody.AngularDamping = new Vector3D(10f, 10f, 10f); _physicsBody.AngularDamping = new Vector3D(1f, 1f, 1f); _physicsBody.ApplyForce += new BodyForceEventHandler(Body_ApplyForce); #endregion #region Exterior Extra Visuals // There is a bug in WPF where visuals added after a semitransparent one won't show inside. The cockpit looks stupid when you can see // it inside the skin #region Cockpit // Material material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.AlphaBlend(Colors.Teal, Colors.DimGray, .2d)))); material.Children.Add(new SpecularMaterial(Brushes.White, 100d)); // Geometry Model geometry = new GeometryModel3D(); geometry.Material = material; geometry.BackMaterial = material; //geometry.Geometry = UtilityWPF.GetSphere(3, .4, .2, .3); geometry.Geometry = UtilityWPF.GetSphere_LatLon(3, .45, .25, .25); geometry.Transform = new TranslateTransform3D(0, this.RadiusY * .5, 0); // Model Visual model = new ModelVisual3D(); model.Content = geometry; // Add to the viewport _visuals.Add(model); _map.Viewport.Children.Add(model); #endregion #region Headlight SpotLight spotLight = new SpotLight(); //spotLight.Color = Color.FromArgb(255, 50, 170, 50); spotLight.Color = UtilityWPF.AlphaBlend(Colors.White, _hullColor, .25d); spotLight.Direction = new Vector3D(0, 1, 0); spotLight.OuterConeAngle = 25; spotLight.InnerConeAngle = 5; //spotLight.LinearAttenuation = .1; spotLight.QuadraticAttenuation = .0001; spotLight.Range = 1000; model = new ModelVisual3D(); model.Content = spotLight; _visuals.Add(model); _map.Viewport.Children.Add(model); #endregion #endregion // Add to the map _map.AddItem(this); }