public virtual void Draw(Vector3d location, Quaterniond rotation) { Matrix4d trans; Matrix4d rot; Matrix4d sca; Matrix4d temp; Vector3d axis; double angle; //Console.WriteLine("DDDDrawing at {0},{1},{2}", location.X, location.Y, location.Z); // Translate and rotate stuff. trans = Matrix4d.CreateTranslation(location); rotation.ToAxisAngle(out axis, out angle); Matrix4d.CreateFromAxisAngle(axis, angle, out rot); sca = Matrix4d.Scale(scale.X, 1, scale.Y); temp = Matrix4d.Mult(Graphics.Modelview, trans); temp = Matrix4d.Mult(sca, Matrix4d.Mult(rot, temp)); //Console.WriteLine("MMMMatrix:\n{0}", temp); GL.PushMatrix(); GL.LoadMatrix(ref temp); //Console.WriteLine("Matrix'd"); // Do drawing stuff. GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, frames[animFrame]); geometry.Draw(); GL.PopMatrix(); }
public virtual void Draw(Vector3d location, Quaterniond rotation) { Matrix4d trans; Matrix4d rot; Matrix4d sca; Matrix4d temp; Vector3d axis; double angle; // Translate and rotate stuff. trans = Matrix4d.CreateTranslation(location); rotation.ToAxisAngle(out axis, out angle); Matrix4d.CreateFromAxisAngle(axis, angle, out rot); sca = Matrix4d.Scale(scale.X, 1, scale.Y); temp = Matrix4d.Mult(Graphics.Modelview, trans); temp = Matrix4d.Mult(sca, Matrix4d.Mult(rot, temp)); GL.PushMatrix(); GL.LoadMatrix(ref temp); //Console.WriteLine("Matrix'd"); // Do drawing stuff. //GL.ClientActiveTexture(TextureUnit.Texture0); //GL.ActiveTexture(TextureUnit.Texture1); //GL.BindTexture(TextureTarget.Texture2D, tex); //int loc = GL.GetUniformLocation(Graphics.CurrentShader, "tex1"); //GL.Uniform1(loc, 1); //Console.WriteLine("Texture'd {0}", tex); material.Draw(); geometry.Draw(); GL.PopMatrix(); }
public InputManager(KeyboardDevice keyboard) { _config = new CameraConfig(new Vector3d(10, 0, 0), new Vector3d(-1, 0, 0), new Vector3d(0, 1, 0), 1, 0, 1); _keyboard = keyboard; _bindings = new Dictionary <Key, Action <float> > { { Key.W, dt => _config.Position += _config.Lookat * dt * _config.MoveSpeed }, { Key.S, dt => _config.Position -= _config.Lookat * dt * _config.MoveSpeed }, { Key.A, dt => _config.Position += Vector3d.Cross(_config.Up, _config.Lookat) * dt * _config.MoveSpeed }, { Key.D, dt => _config.Position -= Vector3d.Cross(_config.Up, _config.Lookat) * dt * _config.MoveSpeed }, { Key.ShiftLeft, dt => _config.Position += _config.Up * dt * _config.MoveSpeed }, { Key.Space, dt => _config.Position -= _config.Up * dt * _config.MoveSpeed }, { Key.Q, dt => _config.Up = Vector3d.Transform(_config.Up, Matrix4d.CreateFromAxisAngle(_config.Lookat, TurnSpeed * dt)) }, { Key.E, dt => _config.Up = Vector3d.Transform(_config.Up, Matrix4d.CreateFromAxisAngle(_config.Lookat, -TurnSpeed * dt)) }, { Key.Left, dt => _config.Lookat = Vector3d.Transform(_config.Lookat, Matrix4d.CreateFromAxisAngle(_config.Up, TurnSpeed * dt * _config.Fov)) }, { Key.Right, dt => _config.Lookat = Vector3d.Transform(_config.Lookat, Matrix4d.CreateFromAxisAngle(_config.Up, -TurnSpeed * dt * _config.Fov)) }, { Key.Up, dt => _config.Lookat = Vector3d.Transform(_config.Lookat, Matrix4d.CreateFromAxisAngle(Vector3d.Cross(_config.Up, _config.Lookat), TurnSpeed * dt * _config.Fov)) }, { Key.Down, dt => _config.Lookat = Vector3d.Transform(_config.Lookat, Matrix4d.CreateFromAxisAngle(Vector3d.Cross(_config.Up, _config.Lookat), -TurnSpeed * dt * _config.Fov)) }, { Key.R, dt => _config.MoveSpeed *= 1 + dt }, { Key.F, dt => _config.MoveSpeed *= 1 - dt }, { Key.N, dt => _config.Fov *= 1 + dt }, { Key.M, dt => _config.Fov *= 1 - dt } }; _keyboard.KeyDown += KeyboardOnKeyDown; }
public void Update(double elapsedTime, EntityManager entityManager) { var speedExponent = Math.Max(0.5, Math.Log10(Math.Abs(_camera.Position.Y))); var delta = (elapsedTime - _lastUpdate) * Math.Pow(10, speedExponent); var up = Vector3d.Cross(_camera.Right, _camera.Forward).Normalized(); var direction = new Vector3d(0, 0, 0); bool keyDown = false; if (_keyboardInputProcessor.IsButtonDown(Key.W)) { direction += _camera.Forward; keyDown = true; } if (_keyboardInputProcessor.IsButtonDown(Key.S)) { direction += -_camera.Forward; keyDown = true; } if (_keyboardInputProcessor.IsButtonDown(Key.D)) { direction += _camera.Right; keyDown = true; } if (_keyboardInputProcessor.IsButtonDown(Key.A)) { direction += -_camera.Right; keyDown = true; } if (_keyboardInputProcessor.IsButtonDown(Key.LShift)) { direction += up; keyDown = true; } if (_keyboardInputProcessor.IsButtonDown(Key.LControl)) { direction += -up; keyDown = true; } if (keyDown) { var result = Vector3d.Multiply(direction.Normalized(), delta); _camera.Target += result; _camera.Position += result; } var relativeMousePositionDelta = _mouseInputProcessor.GetMousePositionDelta(); var rotation = Matrix4d.CreateFromAxisAngle(up, -relativeMousePositionDelta.X / 500.0) * Matrix4d.CreateFromAxisAngle(_camera.Right, -relativeMousePositionDelta.Y / 500.0); var rotated = Vector3d.Transform(_camera.Forward, rotation); _camera.Target = _camera.Position + rotated; _lastUpdate = elapsedTime; }
public static Location RotateAround(this ILocatable loc, ILocatable axis, float degs) { var a = degs * Math.PI / 180; var p = loc.ToPositionAboveSeaLeveld(0); var o = axis.ToPositionAboveSeaLeveld(0); o.Normalize(); var m = Matrix4d.CreateFromAxisAngle(o, a); var r = m.Tx(p); return(r.ToLocation()); }
Vector3d point(double ang) { var maxr = Math.Max(MajorRadius, MinorRadius); var minr = Math.Min(MajorRadius, MinorRadius); MajorRadius = maxr; MinorRadius = minr; var mtr4 = Matrix4d.CreateFromAxisAngle(Normal, ang); var res = Vector4d.Transform(new Vector4d(norm), mtr4); var realAng = Vector3d.CalculateAngle(res.Xyz, RefDir); var rad = MajorRadius * MinorRadius / (Math.Sqrt(Math.Pow(MajorRadius * Math.Sin(realAng), 2) + Math.Pow(MinorRadius * Math.Cos(realAng), 2))); res *= rad; return(Location + res.Xyz); }
public void Orbit(double aYaw, double aPitch) { Matrix4d m1 = Matrix4d.CreateFromAxisAngle(mUp, aYaw); Matrix4d m2 = Matrix4d.CreateFromAxisAngle(mRight, aPitch); Matrix4d m = m1 * m2; Matrix4d mI = Matrix4d.Transpose(m); Vector3d tmp = mEye - mCenter; double dst = tmp.Length; tmp.Normalize(); mUp = Vector3d.Transform(mUp, mI); mUp.Normalize(); tmp = Vector3d.Transform(tmp, mI); tmp.Normalize(); mRight = Vector3d.Cross(mUp, tmp); mEye = tmp * dst + mCenter; }
internal Vector3d CalcConjugateNormal() { var nm = tring1.GetPlane().Normal.Normalized(); var point0 = AuxPoint0; var point1 = AuxPoint1; var neg = -nm; var axis = (edge.End - edge.Start).Normalized(); PlaneSurface pp = new PlaneSurface() { Position = edge.Start, Normal = axis }; var prj0 = pp.ProjPoint(point0) - edge.Start; var prj1 = pp.ProjPoint(point1) - edge.Start; var crs1 = Vector3d.Cross(prj0, prj1) / prj0.Length / prj1.Length; var ang2 = Vector3d.CalculateAngle(prj0, prj1); if (crs1.Length > 1e-8) { axis = -crs1.Normalized(); } var mtr = Matrix4d.CreateFromAxisAngle(axis, ang2); var mtr2 = Matrix4d.CreateFromAxisAngle(axis, -ang2); var trans = Vector3d.Transform(neg, mtr2); var check = Vector3d.Transform(prj0.Normalized(), mtr); var check2 = Vector3d.Transform(prj1.Normalized(), mtr); if (!(Vector3d.Cross(tring2.GetPlane().Normal, trans).Length < 1e-8 || Vector3d.Cross(tring2.GetPlane().Normal, -trans).Length < 1e-8)) { DebugHelper.Error?.Invoke("inconsistent normal was calculated"); } normal1 = trans; return(trans); }
public override void Drag(OpenGLControlWrapper w, MouseEventArgs e) { if (_dragging == DragState.Idle) { return; } Lookat = Target.Position; switch (_dragging) { case DragState.ArcBalling: // moving { var relativePosition = _eye - _lookat; var lookToward = new Vector3d(-relativePosition); lookToward.Normalize(); var right = Vector3d.Cross(lookToward, Up); var yaw = YawGain * (e.Location.X - _lastLocation.X); var yawMatrix = Matrix4d.CreateFromAxisAngle(Up, yaw); var pitch = PitchGain * (e.Location.Y - _lastLocation.Y); var pitchMatrix = Matrix4d.CreateFromAxisAngle(right, pitch); var distance = relativePosition.Length; relativePosition = Vector3d.TransformVector(relativePosition, yawMatrix * pitchMatrix); relativePosition.Normalize(); relativePosition = relativePosition * distance; _eye = _lookat + relativePosition; relativePosition.Normalize(); Up = Vector3d.Cross(relativePosition, right); Up.Normalize(); _lastLocation = e.Location; } break; case DragState.Scaling: // scaling { var d = ZoomGain * (e.Location.Y - _lastLocation.Y); var zoom = Math.Exp(d); var rp = _startPosition * (ZoomFactor * zoom); _eye = _lookat + rp; } break; case DragState.RotatingUp: { var centerX = w.Width / 2; var centerY = w.Height / 2; var v1 = new Vector3d(_lastLocation.X - centerX, _lastLocation.Y - centerY, 0d); var v2 = new Vector3d(e.Location.X - centerX, e.Location.Y - centerY, 0d); var v3 = Vector3d.Cross(v1, v2); var v3Mag = v3[2]; var angDeg = Math.Asin(v3Mag / (v1.Length * v2.Length)); //*180d/Math.PI var axis = _lookat - _eye; axis.Normalize(); var mat = Matrix4d.CreateFromAxisAngle(axis, -angDeg); Up = Vector3d.TransformVector(Up, mat); // was _startUp Up.Normalize(); _lastLocation = e.Location; // not sure about this } break; } Dirty = true; w.Invalidate(); }
public override void UpdateMesh(ProjectPolygon[] p) { ProjectPolygons = p; PlaneSurface ps = new PlaneSurface() { Position = Location, Normal = Axis }; var bs = ps.GetBasis(); var vec0 = bs[0] * Radius; //stage1 //check nesting List <ProjectPolygon> tops = new List <ProjectPolygon>(); foreach (var item in ProjectPolygons) { bool good = true; foreach (var item2 in ProjectPolygons) { if (item == item2) { continue; } var pnts2 = item2.Points.ToArray(); if (GeometryUtils.pnpoly(pnts2, item.Points[0].X, item.Points[0].Y)) { good = false; break; } } if (good) { tops.Add(item); } } List <Vector2d[]> triangls = new List <Vector2d[]>(); double step = AngleStep / 180f * Math.PI; //extract 3d contours Contours.Clear(); foreach (var item in tops) { var cc = new Contour3d(); Contours.Add(cc); var maxy = item.Points.Max(z => z.Y) + 1; var miny = item.Points.Min(z => z.Y) - 1; for (int i = 0; i < item.Points.Count; i++) { var p0 = item.Points[i]; var p1 = item.Points[(i + 1) % item.Points.Count]; double last = 0; List <Vector2d> cutPoints = new List <Vector2d>(); List <Vector2d> tempPoints = new List <Vector2d>(); cutPoints.Add(p0); while (true) { var p00 = last; var p11 = p00 + step; last += step; p00 = Math.Min(p00, 10 * Math.PI * 2); p11 = Math.Min(p11, 10 * Math.PI * 2); if (Math.Abs(p00 - p11) < 1e-8) { break; } Vector2d ret1 = Vector2d.Zero; if (GeometryUtils.IntersectSegments(p0, p1, new Vector2d(p11, miny), new Vector2d(p11, maxy), ref ret1)) { tempPoints.Add(ret1); } } tempPoints.Add(p1); while (tempPoints.Any()) { var fr = tempPoints.OrderBy(z => (z - cutPoints.Last()).Length).First(); cutPoints.Add(fr); tempPoints.Remove(fr); } for (int j = 0; j < cutPoints.Count; j++) { var ang = cutPoints[j].X; var mtr = Matrix4d.CreateFromAxisAngle(Axis, -ang); var rot0 = Vector3d.Transform(vec0 + Axis * cutPoints[j].Y * Lenght, mtr); cc.Points.Add(Location + rot0); } } } foreach (var item in tops) { List <ProjectPolygon> holes = new List <ProjectPolygon>(); var pnts2 = item.Points.ToArray(); foreach (var xitem in ProjectPolygons.Except(tops)) { if (GeometryUtils.pnpoly(pnts2, xitem.Points[0].X, xitem.Points[0].Y)) { holes.Add(xitem); } } PolyBoolCS.PolyBool pb = new PolyBoolCS.PolyBool(); PolyBoolCS.Polygon p1 = new PolyBoolCS.Polygon(); var pl1 = new PolyBoolCS.PointList(); p1.regions = new List <PolyBoolCS.PointList>(); pl1.AddRange(item.Points.Select(z => new PolyBoolCS.Point(z.X, z.Y)).ToArray()); p1.regions.Add(pl1); var maxy = pl1.Max(z => z.y) + 1; var miny = pl1.Min(z => z.y) - 1; double last = 0; while (true) //for (double i = step; i < (Math.PI * 2); i += step) { var p0 = last; var p11 = p0 + step; last += step; p0 = Math.Min(p0, 10 * Math.PI * 2); p11 = Math.Min(p11, 10 * Math.PI * 2); if (Math.Abs(p0 - p11) < 1e-8) { break; } PolyBoolCS.Polygon p2 = new PolyBoolCS.Polygon(); p2.regions = new List <PolyBoolCS.PointList>(); var pl2 = new PolyBoolCS.PointList(); pl2.Add(new PolyBoolCS.Point(p0, miny)); pl2.Add(new PolyBoolCS.Point(p0, maxy)); pl2.Add(new PolyBoolCS.Point(p11, maxy)); pl2.Add(new PolyBoolCS.Point(p11, miny)); p2.regions.Add(pl2); if (holes.Any(z => GeometryUtils.AlmostEqual(z.Area(), 0))) { throw new GeomPadException("zero area contour detected"); } var res = pb.intersect(p1, p2); if (res.regions.Any()) { foreach (var region in res.regions) { var triangls2 = GeometryUtils.TriangulateWithHoles( new[] { region.Select(z => new Vector2d(z.x, z.y)).ToArray() } , holes.Select(z => z.Points.ToArray()).ToArray(), true); triangls.AddRange(triangls2); } } } } //stage2 List <TriangleInfo> tt = new List <TriangleInfo>(); foreach (var item in triangls) { TriangleInfo tin = new TriangleInfo(); List <VertexInfo> v = new List <VertexInfo>(); foreach (var d in item) { var ang = d.X; var mtr = Matrix4d.CreateFromAxisAngle(Axis, -ang); var rot0 = Vector3d.Transform(vec0 + Axis * d.Y * Lenght, mtr); v.Add(new VertexInfo() { Position = Location + rot0 }); } var v01 = v[1].Position - v[0].Position; var v11 = v[2].Position - v[0].Position; var crs = Vector3d.Cross(v01, v11).Normalized(); if (double.IsNaN(crs.X)) { throw new GeomPadException("normal is NaN"); } foreach (var item0 in v) { item0.Normal = crs; } tin.Vertices = v.ToArray(); tt.Add(tin); } Mesh = new Mesh() { Triangles = tt }; }
public override void Draw(IDrawingContext gr) { if (!Visible) { return; } GL.Color3(Color.Blue); if (Selected) { GL.Color3(Color.Red); } if (ShowGismos) { DrawHelpers.DrawCross(Location, DrawSize); PlaneSurface ps = new PlaneSurface() { Position = Location, Normal = Axis }; var bs = ps.GetBasis(); var dir = bs[0] * Radius; List <Vector3d> pnts = new List <Vector3d>(); var step = Math.PI * AngleStep / 180f; for (double i = 0; i <= Math.PI * 2; i += step) { var mtr4 = Matrix4d.CreateFromAxisAngle(Axis, i); var res = Vector4d.Transform(new Vector4d(dir), mtr4); pnts.Add(Location + res.Xyz); } GL.Begin(PrimitiveType.LineStrip); for (int i = 0; i < pnts.Count; i++) { GL.Vertex3(pnts[i]); } GL.End(); pnts.Clear(); for (double i = 0; i <= Math.PI * 2; i += step) { var mtr4 = Matrix4d.CreateFromAxisAngle(Axis, i); var res = Vector4d.Transform(new Vector4d(dir), mtr4); pnts.Add(Location + res.Xyz + Axis * Lenght); } GL.Begin(PrimitiveType.LineStrip); for (int i = 0; i < pnts.Count; i++) { GL.Vertex3(pnts[i]); } GL.End(); GL.Begin(PrimitiveType.Lines); GL.Vertex3(Location); GL.Vertex3(Location + Axis * Lenght); GL.End(); } if (ShowMesh) { drawMesh(); } drawContours(); }
public void RotateAxis(Vector3d axis, double angle) { matrix = Matrix4d.CreateFromAxisAngle(axis, angle) * matrix; inverse_matrix *= Matrix4d.CreateFromAxisAngle(axis, -angle); }
public LensRayTransferFunction.Parameters ConvertSurfaceRayToParameters( Ray ray, Vector3d canonicalNormal, double surfaceSinTheta, Sphere sphericalSurface, ElementSurface surface) { //Console.WriteLine("ray->parameters"); // - convert origin // *- transform to hemispherical coordinates // - find out if it is on the surface // *- scale with respect to the spherical cap // *- normalize Vector3d unitSpherePos = (ray.Origin - sphericalSurface.Center) * sphericalSurface.RadiusInv; unitSpherePos.Z *= canonicalNormal.Z; //Console.WriteLine("unit sphere position: {0}", unitSpherePos); Vector2d originParametric = Sampler.SampleSphereWithUniformSpacingInverse( unitSpherePos, surfaceSinTheta, 1); // - convert direction // *- transform from camera space to local frame // *- compute normal at origin //Console.WriteLine("ray origin: {0}", ray.Origin); Vector3d normalLocal = surface.SurfaceNormalField.GetNormal(ray.Origin); normalLocal.Normalize(); // TODO: check if it is unnecessary //Console.WriteLine("local normal: {0}", normalLocal); // *- create rotation quaternion from canonical normal to local // normal Vector3d direction = ray.Direction; //Console.WriteLine("local direction: {0}", direction); if (surface.Convex) { direction = -direction; } Vector3d rotationAxis = Vector3d.Cross(canonicalNormal, normalLocal); //Console.WriteLine("rotation axis: {0}", rotationAxis); if (rotationAxis.Length > 0) { double angle = Math.Acos(Vector3d.Dot(normalLocal, canonicalNormal)); //Console.WriteLine("angle: {0}", angle); double positionPhi = originParametric.Y; // first transformed to the frame of the local normal //Console.WriteLine("position phi: {0}", positionPhi); Matrix4d rotMatrix = Matrix4d.CreateFromAxisAngle(rotationAxis, -angle); // then rotate the local direction around Z using the position phi rotMatrix = rotMatrix * Matrix4d.CreateRotationZ(2 * Math.PI * -positionPhi); direction = Vector3d.Transform(direction, rotMatrix); } //Console.WriteLine("abs. direction: {0}", direction); // *- transform to hemispherical coordinates // - find out if it is within the local hemisphere double sinTheta = direction.Z / canonicalNormal.Z; double dirTheta = Math.Asin(sinTheta); double cosTheta = Math.Sqrt(1 - sinTheta * sinTheta); double dirPhi = Math.Atan2(direction.Y, direction.X); if (dirPhi < 0) { // map [-PI; PI] to [0; 2*PI] dirPhi += 2 * Math.PI; } // *- normalize Vector2d directionParametric = new Vector2d( dirTheta / (0.5 * Math.PI), dirPhi / (2 * Math.PI)); //Console.WriteLine("position parameters: {0}", new Vector2d( // originParametric.X, originParametric.Y)); return(new LensRayTransferFunction.Parameters( originParametric.X, originParametric.Y, directionParametric.X, directionParametric.Y)); }
/// <summary> /// Convert a ray with origin at the back or front lens surface from /// its parametric representation. /// </summary> /// <param name="position">Position on lens surface in parameteric /// representation (normalized hemispherical coordinates).</param> /// <param name="direction">Direction of the ray with respect to the /// local frame in parameteric representation (normalized hemispherical /// coordinates). /// </param> /// <param name="canonicalNormal">Normal of the lens surface /// hemisphere (typically (0,0,1) for the back surface or (0,0,-1) for /// the front surface).</param> /// <param name="surfaceSinTheta">Sine of the surface spherical cap /// theta angle.</param> /// <param name="sphericalSurface">Lens surface represented as a /// sphere.</param> /// <param name="surface">Lens surface with its normal field.</param> /// <returns>Ray corresponding to its parametric representation. /// </returns> public Ray ConvertParametersToSurfaceRay( LensRayTransferFunction.Parameters parameters, Vector3d canonicalNormal, double surfaceSinTheta, Sphere sphericalSurface, ElementSurface surface) { //Console.WriteLine("parameters->ray"); //Console.WriteLine("position parameters: {0}", parameters.Position); // uniform spacing sampling for LRTF sampling Vector3d unitSpherePos = Sampler.SampleSphereWithUniformSpacing( parameters.Position, surfaceSinTheta, 1); //Console.WriteLine("unit sphere position: {0}", unitSpherePos); unitSpherePos.Z *= canonicalNormal.Z; Vector3d lensPos = sphericalSurface.Center + sphericalSurface.Radius * unitSpherePos; //Console.WriteLine("ray origin: {0}", lensPos); // - get normal N at P Vector3d normalLocal = surface.SurfaceNormalField.GetNormal(lensPos); // - compute direction D from spherical coordinates (wrt normal Z = (0,0,+/-1)) double theta = 0.5 * Math.PI * parameters.DirectionTheta; double phi = 2 * Math.PI * parameters.DirectionPhi; double cosTheta = Math.Cos(theta); Vector3d directionZ = new Vector3d( Math.Cos(phi) * cosTheta, Math.Sin(phi) * cosTheta, Math.Sin(theta) * canonicalNormal.Z); // - rotate D from Z to N frame // - using a (normalized) quaternion Q // - N and Z should be assumed to be already normalized // - more efficient method: Efficiently building a matrix to // rotate one vector to another [moller1999] normalLocal.Normalize(); // TODO: check if it is unnecessary //Console.WriteLine("abs. direction: {0}", directionZ); //Console.WriteLine("local normal: {0}", normalLocal); Vector3d rotationAxis = Vector3d.Cross(canonicalNormal, normalLocal); //Console.WriteLine("rotation axis: {0}", rotationAxis); Vector3d rotatedDir = directionZ; if (rotationAxis.Length > 0) { double angle = Math.Acos(Vector3d.Dot(canonicalNormal, normalLocal)); //Console.WriteLine("angle: {0}", angle); // first the local direction must be rotated around using the position phi! //Console.WriteLine("position phi: {0}", parameters.PositionPhi); Matrix4d rotMatrix = Matrix4d.CreateRotationZ(2 * Math.PI * parameters.PositionPhi); // only then can be transformed to the frame of the local normal rotMatrix = rotMatrix * Matrix4d.CreateFromAxisAngle(rotationAxis, angle); rotatedDir = Vector3d.Transform(directionZ, rotMatrix); } if (surface.Convex) { rotatedDir = -rotatedDir; } //Console.WriteLine("local direction: {0}", rotatedDir); Ray result = new Ray(lensPos, rotatedDir); return(result); }