/// <summary> /// Initializes a new instance of the <see cref="Quaternion"/> class. /// </summary> /// <param name="sourcePosition">The source position.</param> /// <param name="destinationPosition">The destination position.</param> public Quaternion(Vector3 sourcePosition, Vector3 destinationPosition) { var r = sourcePosition.Cross(destinationPosition); var s = Functions.Sqrt(2 * (1 + sourcePosition.Dot(destinationPosition))); mValues = new Vector4(r / s, s / 2); }
/// 2点間の距離を返す(XとZのみ) public static float DistanceXZ( Vector3 pos1, Vector3 pos2 ) { calPos = pos1 - pos2; calPos.Y = 0; float dis = FMath.Sqrt( calPos.Dot(calPos) ); return dis; }
public MeshTriangle(byte id, Vector3 p0, Vector3 p1, Vector3 p2) { Id = id; P0 = p0; P1 = p1; P2 = p2; Points = new List<Vector3>{P0, P1, P2}; U = P1 - P0; V = P2 - P0; Normal = U.Cross(V).NormalizeRet(); Direction = CalculateDirection(); UU = U.Dot(U); VV = V.Dot(V); UV = U.Dot(V); D = UV * UV - UU * VV; }
static double AngleBetweenVectors(Vector3 Vector1, Vector3 Vector2) { float dotProduct = Vector1.Dot(Vector2); float vectorsMagnitude = Vector1.Length * Vector2.Length; double angle = Math.Acos(dotProduct / vectorsMagnitude); if (double.IsNaN(angle)) return 0; return (angle); }
/// <summary> /// 2つのベクトルがなす角をかえす /// </summary> /// <param name="vecA"></param> /// <param name="vecB"></param> /// <returns></returns> public static double VecToRad( Vector3 vecA, Vector3 vecB ) { vecA.Normalize(); vecB.Normalize(); double dir = (double)(Axiom.Math.Utility.ASin(vecA.Dot(vecB)) - Axiom.Math.Utility.HALF_PI); Vector3 resVec = vecA.Cross(vecB); if (resVec.z < 0) dir = -dir; return dir; }
public double GetAngleBetweenVectors(Vector3 a, Vector3 b) { var cosAlpha = a.Dot(b) / (a.Magnitude * b.Magnitude); if (1 - Math.Abs(cosAlpha) < Consts.DoubleEqualityThreshold) { return cosAlpha < 0 ? Math.PI : 0; } return Math.Acos(cosAlpha); }
/// <summary> /// Sets up the frame /// </summary> /// <param name="position"> Frame origin </param> /// <param name="velocity"> Velocity. Becomes frame tangent (normalised by constructor) </param> /// <param name="acceleration"> Acceleration. Used to calculate frame normal and binormal </param> public CurveFrame( Point3 position, Vector3 velocity, Vector3 acceleration ) { float sqrSpeed = velocity.SqrLength; float dotVA = velocity.Dot( acceleration ); Translation = position; XAxis = velocity.MakeNormal( ); YAxis = ( acceleration * sqrSpeed ) - ( velocity * dotVA ); ZAxis = Vector3.Cross( XAxis, YAxis ); m_Speed = Functions.Sqrt( sqrSpeed ); // NOTE: It's quite easy to calculate curvature here (because we've got first and second derivatives, and the square of speed, ready at hand). // I've removed the calculation because it does involve a length and a cross-product, which is a bit much if the caller isn't interested in the // curvature value (as is likely). Call Curve.EvaluateCurvature() instead. }
public void Integrate(float duration) { if (!IsAwake) return; LastFrameAcceleration = Acceleration; LastFrameAcceleration += (ForceAccumulation * InverseMass); Vector3 angularAcceleration = InverseInertiaTensorWorld.Transform(TorqueAccumulation); Velocity += (LastFrameAcceleration * duration); Rotation += (angularAcceleration * duration); Velocity *= MathHelper.Pow(LinearDrag, duration); Rotation *= MathHelper.Pow(AngularDrag, duration); Position += (Velocity * duration); Orientation.AddScaledVector(Rotation, duration); CalculateDerivedData(); ClearAccumulation(); if (CanSleep) { float currentMotion = Velocity.Dot(Velocity) + Rotation.Dot(Rotation); float bias = MathHelper.Pow(0.5f, duration); Motion = bias * Motion + (1.0f - bias) * currentMotion; if (Motion < MathHelper.SleepEpilson) IsAwake = (false); else if (Motion > 10 * MathHelper.SleepEpilson) Motion = 10.0f * MathHelper.SleepEpilson; } }
/// <summary> /// Gets the shortest arc quaternion to rotate this vector /// to the destination vector. /// </summary> /// <remarks> /// If you call this with a dest vector that is close to the inverse /// of this vector, we will rotate 180 degrees around the 'fallbackAxis' /// (if specified, or a generated axis if not) since in this case /// ANY axis of rotation is valid. /// </remarks> public Quaternion GetRotationTo(Vector3 destination, Vector3 fallbackAxis) { // Based on Stan Melax's article in Game Programming Gems Quaternion q = new Quaternion(); Vector3 v0 = new Vector3(this.x, this.y, this.z); Vector3 v1 = destination; // normalize both vectors v0.Normalize(); v1.Normalize(); // get the cross product of the vectors Vector3 c = v0.Cross(v1); // If the cross product approaches zero, we get unstable because ANY axis will do // when v0 == -v1 float d = v0.Dot(v1); // If dot == 1, vectors are the same if (d >= 1.0f) { return Quaternion.Identity; } if (d < (1e-6f - 1.0f)) { if (fallbackAxis != Vector3.Zero) // rotate 180 degrees about the fallback axis q = Quaternion.FromAngleAxis((float)Math.PI, fallbackAxis); else { // Generate an axis Vector3 axis = Vector3.UnitX.Cross(this); if (axis.IsZero) // pick another if colinear axis = Vector3.UnitY.Cross(this); axis.Normalize(); q = Quaternion.FromAngleAxis((float)Math.PI, axis); } } else { float s = MathUtil.Sqrt( (1+d) * 2 ); float inverse = 1 / s; q.x = c.x * inverse; q.y = c.y * inverse; q.z = c.z * inverse; q.w = s * 0.5f; q.Normalize(); } return q; }
public void ReadSkewMatrix( ref Matrix4 matrix, XmlNode node ) { string[] values = node.InnerText.Split( (char[]) null, StringSplitOptions.RemoveEmptyEntries ); Debug.Assert( values.Length == 7 ); float angle = float.Parse( values[ 0 ] ); if( angle == 0 ) return; angle = MathUtil.RadiansToDegrees( angle ); Vector3 axis = new Vector3(); axis.x = float.Parse( values[ 0 ] ); axis.y = float.Parse( values[ 1 ] ); axis.z = float.Parse( values[ 2 ] ); Vector3 along = new Vector3(); along.x = float.Parse( values[ 3 ] ); along.y = float.Parse( values[ 4 ] ); along.z = float.Parse( values[ 5 ] ); Matrix4 shear = Matrix4.Identity; shear[ 0, 1 ] = (float) Math.Tan( angle ); Debug.Assert( axis.Dot( along ) < 0.001f, "Vectors for skew must be perpendicular" ); // FIXME: Handle these skews DebugMessage( node ); }
public float[] GetAutoSplatSampleNormalized( long heightMM, Vector3 normal ) { AutoSplatHeightAngleRange lowerRange = null; AutoSplatHeightAngleRange higherRange = null; // We assume the ranges are sorted in increasing order by height foreach( AutoSplatHeightAngleRange range in m_RangeList ) { if( range.HeightMM == heightMM ) { lowerRange = range; higherRange = range; break; } if( range.HeightMM < heightMM ) { lowerRange = range; continue; } if( range.HeightMM > heightMM ) { higherRange = range; // We should have both the lower & upper bounds now, so break; break; } } if( lowerRange == null ) { lowerRange = m_RangeList[ 0 ]; // allows us to continue } if( higherRange == null ) { higherRange = m_RangeList[ m_RangeList.Count - 1 ]; // allows us to continue } // We want the angle of the normal relative to the XZ plane, so // we first use the dot product to get the angle to the Y-axis // which is perpendicular to the XZ plane, convert it to degress, // and then subtract it from 90. float angleRadians = normal.Dot( Vector3.UnitY ); float angleDegrees = Convert.ToSingle( 90 - RadiansToDegrees( angleRadians ) ); if( lowerRange == higherRange ) { // No need to do any weighting since we at the exact height return lowerRange.GetAutoSplatSampleNormalized( angleDegrees ); } // Compute the gradiant weighting for the lower & higher angled textures float lowerWeight; float higherWeight; long heightDiff = higherRange.HeightMM - lowerRange.HeightMM; if( heightDiff == 0 ) { // Give equal weighting to both samples. // This covers the case when we have two ranges at the // same height....this really shouldn't happen due to the // way we choose the lower/higher ranges. lowerWeight = 0.5f; higherWeight = 0.5f; } else { // How close is the angle to the higher/lower angle? Normalize // that distance from 0..1 and use that as the gradient weights higherWeight = ((float) (heightMM - lowerRange.HeightMM)) / heightDiff; lowerWeight = 1f - higherWeight; } float[] lowerNormalizedSample = lowerRange.GetAutoSplatSampleNormalized( angleDegrees ); float[] higherNormalizedSample = higherRange.GetAutoSplatSampleNormalized( angleDegrees ); float[] normalizedSample = new float[ AlphaSplatTerrainConfig.MAX_LAYER_TEXTURES ]; for( int i = 0; i < AlphaSplatTerrainConfig.MAX_LAYER_TEXTURES; i++ ) { normalizedSample[ i ] = lowerNormalizedSample[ i ] * lowerWeight + higherNormalizedSample[ i ] * higherWeight; } return normalizedSample; }
/// <summary> /// Concatenates two quaternions. The right argument is applied first. /// </summary> /// <param name="left">The left operand which is applied after the right one.</param> /// <param name="right">The right operand which is applied first.</param> /// <returns>A quaternion containing the rotations of both given quaternions.</returns> public static Quaternion operator *(Quaternion left, Quaternion right) { var v1 = new Vector3(right.X, right.Y, right.Z); var v2 = new Vector3(left.X, left.Y, left.Z); var w = left.W * right.W - v1.Dot(v2); var v = right.W * v2 + left.W * v1 + v2.Cross(v1); return new Quaternion(v, w); }
public static float ProjectVectorOnNormalizedVector(Vector3 projectedV, Vector3 projectOnV) { return(Vector3.Dot(projectedV, projectOnV)); }
////////////////////////////// CLOSET POINT ON LINE """""""""""\* ///// ///// Возвращает точку на линии vA_vB, которая ближе всего к точке vPoint ///// ////////////////////////////// CLOSET POINT ON LINE """""""""""\* static Vector3 ClosestPointOnLine(Vector3 vA, Vector3 vB, Vector3 vPoint) { // Эта функция принимает сегмент линии, от vA до vB, затем точку в пространстве, // vPoint. Мы хотим найти ближайшую точку отрезка vA_vB к точке в пространстве. // Или это будет одна из двух крайних точек линии, или точка где-то между // vA и vB. В отношении определения пересечений это очень важная функция. // Вот как это работает. Сначала это всё кажется немного запутанным, так что постарайтесь // сосредоточится. Сначала нам нужно найти вектор от "vA" к точке в пространстве. // Затем нужно нормализовать вектор от "vA" к "vB", так как нам не нужна его полная длинна, // только направление. Запомните это, так как позже мы будем использовать скалярное // произведение (dot product) при рассчетах. Итак, сейчас у нас есть 2 вектора, образующие // угол воображаемого треугольника на плоскости (2 точки линии и точка пространства). // Далее нам нужно найти величину (magnitude) сегмента линии. Это делается простой // формулой дистанции. Затем вычисляем dot между "vVector2" и "vVector1". Используя // это скалярное произведение, мы можем по существу спроэцировать vVector1 на нормализованный // вектор сегмента линии, "vVector2". Если результат скалярного произведения равен нулю, // это значит, что векторы были перпендикулярны и имели между собой угол в 90 градусов. // 0 - это дистанция нового спроэцированного вектора от vVector2. Если результат - // отрицательный, значит угол между двумя векторами более 90 градусов, что в свою очередь // означает, что ближайшая точка - "vA", так как этот спроэцированный вектор находится // снаружи линии. Если же результат - положительное число, спроэцированный вектор будет // находится с правой стороны "vA", но возможно и справа от "vB". Чтобы это проверить, // мы убедимся, что результат скалярного произведения НЕ больше дистанции "d". Если // он больше, то ближайшая точка - "vB". // Итак, мы можем найти ближайшую точку довольно просто, если это одна из крайних точек линии. // Но как мы найдём точку между двумя краями линии? Это просто. Посколько у нас есть // дистанция "t" от точки "vA" (полученная из скалярного произведения двух векторов), // мы просто используем наш вектор направления сегмента линии, "vVector2", и умножим его // на дистанцию "t". Это создаст вектор, идущий в направлении сегмента линии, с величиной // (magnitude) спроецированного вектора, "vVector1", от точки "vA". Затем прибавляем // этот вектор к "vA", что даст нам точку на линии, которая ближе всего к нашей точке // пространства, "vPoint". // Наверно, это всё очень сложно представить на основе комментариев, пока у вас // нет хорошего понимания линейной алгебры. // Создаём вектор от точки vA к точке пространства vPoint. Vector3 vVector1 = vPoint - vA; // Создаём нормализированный вектор направления от точки vA до vB. Vector3 vVector2 = Vector3.Normalize(vB - vA); // Используем формулу дистанции, чтобы найти величину (magnitude) сегмента линии. float d = Distance(vA, vB); // Используя скалярное произведение, проэцируем vVector1 на vVector2. // Это, по существу, даст нам расстояние от нашего спроецированного вектора до vA. float t = Vector3.Dot(vVector2, vVector1); // Если наша спроецированная дистанция от vA, "t", меньше или равна нулю, ближайшая // точка к vPoint - vA. Возвращаем эту точку. if (t <= 0) { return(vA); } // Если спроецированная дистанция от vA, "t", Больше или равна длинне сегмента линии, // ближайшая точка на линии - vB. Вернём её. if (t >= d) { return(vB); } // Здесь мы создаём вектор с длинной t и направлением vVector2. Vector3 vVector3 = new Vector3(vVector2.X * t, vVector2.Y * t, vVector2.Z * t); // Чтобы найти ближайшую точку на отрезке линии, просто прибавляем vVector3 к точке vA. Vector3 vClosestPoint = vA + vVector3; // Вернём ближайшую точку на линии return(vClosestPoint); }
public static void InersectNormal(ref Vector3 vector, ref Vector3 normal, out Vector3 result) { result = (normal * vector.Dot(normal)); }
public override void Raycast(PointerEventData eventData, List <RaycastResult> resultAppendList) { if (canvas == null) { Debug.LogError("PvrGraphicRaycaster requires that the game object needs 'Canvas' componet !"); return /*false*/; } if (eventCamera == null) { Debug.LogError("PvrGraphicRaycaster requires that the eventCamera is not null"); return; } if (canvas.renderMode != RenderMode.WorldSpace) { Debug.LogError("PvrGraphicRaycaster requires that the canvas renderMode is set to WorldSpace."); return /*false*/; } Ray ray = PvrInputMoudle.ray; if (!PUI_UnityAPI.isControllerConnected()) { ray = new Ray(eventCamera.transform.position, eventCamera.transform.forward); PvrInputMoudle.ray = ray; } PvrInputMoudle.FindInputModule().Impl.RayDirection = ray.direction; float dist = 20f; MaxPointerEndPoint = ray.GetPoint(dist); Debug.DrawLine(ray.origin, ray.origin + (ray.direction * 5F), Color.red); float hitDistance = float.MaxValue; if (blockingObjects != BlockingObjects.None) /**标记为 None 标签的不需要处理*/ { if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All) { RaycastHit hit; if (Physics.Raycast(ray, out hit, dist, m_BlockingMask)) { hitDistance = hit.distance; //Debug.Log("Hit postition : " + hit.point); //Debug.Log("ditance : " + Vector3.Distance(hit.point, ray.origin) + " Hitdistance : " + hitDistance); } } if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All) { RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, dist, m_BlockingMask); if (hit.collider != null) { hitDistance = hit.fraction * dist; } } } m_RaycastResults.Clear(); Raycast(canvas, ray, eventCamera, dist, m_RaycastResults); //Debug.Log("RaycastResult 数量 : " + m_RaycastResults.Count); for (var index = 0; index < m_RaycastResults.Count; index++) { //Debug.Log("RaycastResult 数量 : " + m_RaycastResults.Count + " name "+m_RaycastResults[index].gameObject.name); var go = m_RaycastResults[index].gameObject; bool appendGraphic = true; if (ignoreReversedGraphics) { // If we have a camera compare the direction against the cameras forward. Vector3 cameraFoward = eventCamera.transform.rotation * Vector3.forward; Vector3 dir = go.transform.rotation * Vector3.forward; appendGraphic = Vector3.Dot(cameraFoward, dir) > 0; } if (appendGraphic) { float resultDistance = 0; Transform trans = go.transform; Vector3 transForward = trans.forward; // http://geomalgorithms.com/a06-_intersect-2.html float transDot = Vector3.Dot(transForward, trans.position - ray.origin); float rayDot = Vector3.Dot(transForward, ray.direction); resultDistance = transDot / rayDot; Vector3 hitPosition = ray.origin + (ray.direction * resultDistance); resultDistance = resultDistance + 0; //Debug.Log("resultDistance : "+ resultDistance+ " hitDistance : "+ hitDistance + " dist "+dist); // Check to see if the go is behind the camera. if (resultDistance < 0 || resultDistance >= hitDistance || resultDistance > dist) { continue; } //Transform pointerTransform = // GvrPointerInputModule.Pointer.PointerTransform; //float delta = (hitPosition - pointerTransform.position).magnitude; //if (delta < pointerRay.distanceFromStart) //{ // continue; //} RaycastResult castResult = new RaycastResult { gameObject = go, module = this, distance = resultDistance, worldPosition = hitPosition, screenPosition = eventCamera.WorldToScreenPoint(hitPosition), index = resultAppendList.Count, depth = m_RaycastResults[index].depth, sortingLayer = canvas.sortingLayerID, sortingOrder = canvas.sortingOrder }; resultAppendList.Add(castResult); } } //Debug.Log("resultAppendList.Count : " + resultAppendList.Count); }
private Node GenerateTree(List <Polygon> polygons) { if (polygons.Count == 0) { return(null); } else { var polyRoot = new Node(polygons[0].ID); var frontPolygons = new List <Polygon>(); var backPolygons = new List <Polygon>(); var d = -Vector3.Dot(polygons[0].normal, Transformations.V4ToV3(polygons[0].vertices[0])); var plane = new Vector4(polygons[0].normal, d); for (int i = 1; i < polygons.Count; i++) { var polyPos = CheckPosition(polygons[i], plane); if (polyPos == Position.InFront) { frontPolygons.Add(polygons[i]); } else if (polyPos == Position.Behind) { backPolygons.Add(polygons[i]); } else { var d2 = -Vector3.Dot(polygons[i].normal, Transformations.V4ToV3(polygons[i].vertices[0])); var v = Vector3.Cross(polygons[0].normal, polygons[i].normal); var dot = Vector3.Dot(v, v); var u1 = d2 * polygons[0].normal; var u2 = -d * polygons[i].normal; var p = Vector3.Cross(u1 + u2, v / dot); int p1pos = -1, p2pos = -1; Vector3 point1 = new Vector3(), point2 = new Vector3(); for (int j = 0; j < polygons[i].vertices.Length; j++) { var current = polygons[i].vertices[j]; var next = polygons[i].vertices[(j + 1) % polygons[i].vertices.Length]; if (Vector4.Dot(current, plane) * Vector4.Dot(next, plane) <= 0) { var u = Transformations.V4ToV3(next - current); var a = Vector3.Cross(v, u); var b = Vector3.Cross(Transformations.V4ToV3(next) - p, u); var t = 0.0F; if (a.X != 0) { t = b.X / a.X; } else if (a.Y != 0) { t = b.Y / a.Y; } else if (a.Z != 0) { t = b.Z / a.Z; } if (p1pos == -1) { point1 = p + (t * v); p1pos = j + 1; } else { point2 = p + (t * v); p2pos = j + 1; } } } var poly1 = new Polygon { ID = Polygons.Count, vertices = new Vector4[p1pos + (polygons[i].vertices.Length - p2pos) + 2], normal = polygons[i].normal }; for (int j = 0, k = 0; k < p1pos; j++, k++) { poly1.vertices[j] = polygons[i].vertices[k]; } poly1.vertices[p1pos] = new Vector4(point1, 1.0F); poly1.vertices[p1pos + 1] = new Vector4(point2, 1.0F); for (int j = p1pos + 2, k = p2pos; k < polygons[i].vertices.Length; j++, k++) { poly1.vertices[j] = polygons[i].vertices[k]; } poly1.normal = Transformations.CalculateSurfaceNormal(poly1); Polygons.Add(poly1); var poly2 = new Polygon { ID = Polygons.Count, vertices = new Vector4[p2pos - p1pos + 2], normal = polygons[i].normal }; poly2.vertices[0] = new Vector4(point1, 1.0F); for (int j = 1, k = p1pos; k < p2pos; j++, k++) { poly2.vertices[j] = polygons[i].vertices[k]; } poly2.vertices[p2pos - p1pos + 1] = new Vector4(point2, 1.0F); Polygons.Add(poly2); if (CheckPosition(poly1, plane) == Position.InFront) { frontPolygons.Add(poly1); backPolygons.Add(poly2); } else { frontPolygons.Add(poly2); backPolygons.Add(poly1); } } } polyRoot.Front = GenerateTree(frontPolygons); polyRoot.Back = GenerateTree(backPolygons); return(polyRoot); } }
/// <summary> /// Tessellate a solid cone by specifying the facet chord length around the base circle. /// </summary> /// <param name="vertices">Populated with the cone vertices (output).</param> /// <param name="normals">Populated with the cone normals (output).</param> /// <param name="indices">Populated with the triangle indices (output).</param> /// <param name="apex">The cone apex vertex to construct with.</param> /// <param name="axis">The cone primary axis (direction) to construct with.</param> /// <param name="length">The cone length.</param> /// <param name="angle">The cone angle between the wall and the primary <paramref name="axis"/> /// (radians).</param> /// <param name="baseChordLength">The chord length around the base circle.</param> /// <param name="tessellateBase">Tessellate the base (true) or leave it open (false).</param> /// <returns>True on success, false if the arguments prevent tessellation.</returns> /// <remarks> /// This method tessellates to try and keep quadrilaterals (trapezoids) of the same area. /// The cone is divided into rings, but the distance between the rings increases /// away from the cone base in order to maintain a similar area. /// The last division is set to consume the remainder. The ASCII art below illustrates the /// divisions. /// /// <code> /// Cone setup: /// h[3] = 0 /\ /// / \ /// / \ /// / \ /// h[2] /--------\ /// / \ /// h[1] /------------\ /// h[0] /--------------\ /// /// h[n] defines the length of each ring from the apex, with: /// h[0] < h[1] < ... < h[n-1] < h[n] /// </code> /// /// There are a known number of facets around the ring, where <c>c[n]</c> is /// the chord length of a facet (defined by the ring of radius <c>r[n]</c>). /// Set <c>c[0] = baseChordLength</c>, which generally defines the tessellation resolution. /// </remarks> public static bool SolidByBaseChord(List <Vector3> vertices, List <Vector3> normals, List <int> indices, Vector3 apex, Vector3 axis, float length, float angle, float baseChordLength = 0, bool tessellateBase = true) { float quadArea = baseChordLength * baseChordLength; float baseRadius = length * Mathf.Tan(angle); float segmentAngle = 2.0f * Mathf.Asin(baseChordLength / (2 * baseRadius)); int facets = Mathf.FloorToInt(2.0f * Mathf.PI / segmentAngle + 0.5f); float facetAngle = 2.0f * Mathf.PI / facets; if (facets < MinFacets) { facets = MinFacets; facetAngle = 2.0f * Mathf.PI / facets; baseChordLength = 2 * baseRadius * Mathf.Sin(0.5f * facetAngle); quadArea = baseChordLength * baseChordLength; } segmentAngle = 2.0f * Mathf.PI / facets; if (baseChordLength <= 0) { return(false); } // Building on the XML comment above: // Constants or initial values: // A: quadArea (c[0] * c[0]) // theta: cone angle // phi: segmentAngle // At ring n: // r[n] : ring radius // c[n] : facet chord length (trapezoid base length). // d[n] : distance to the next ring (n+1). // h[n] : ring length or the distance from the cone apex to the ring. // A : quadArea // // A[i] = A[j] = quadArea Constant // A[n] = d[n] * (c[n-1] + c[n]) / 2 Trapezoid area. // c[n] = 2r[n] sin(phi / 2) (1) // d[n] = 2A / (c[n-1] + c[n]) (2) // h[n-1] = h[n] + d[n] (3) // h[n] = r[n] / tan(theta) (4) // Thus from (4): // r[n] = h[n] tan(theta) (4a) // Substitute (3) in (4a): // r[n] = (h[n-1] - d[n]) tan(theta) (5) // // Substitute (5) in (1): // c[n] = 2(h[n-1] - d[n]) tan(theta) sin(phi/2) // Let T = 2 * tan(theta) sin(phi/2) // c[n] = T(h[n-1] - d[n]) (6) // // Substitute (2) in (6): // c[n] = T(h[n-1] - 2A / (c[n-1] + c[n])) // ... // c[n] * c[n] + (c[n-1] - Th[n-1])c[n] + T(2A - h[n-1]c[n-1]) = 0 // (7) // // However, we can show that the coefficient of c[n] is zero: // From (4): // r[n] = h[n] tan(theta) (4a) // Substitute (4a) in (1): // c[n] = 2 h[n] tan(theta) sin(phi / 2) // = h[n] 2 tan(theta) sin(phi / 2) // = Th[n] // Therefore: // c[n-1] = Th[n-1] (8) // // Substitute (8) in (7): // c[n] * c[n] + (c[n-1] - Th[n-1])c[n] + T(2A - h[n-1]c[n-1]) = 0 // c[n] * c[n] + (c[n-1] - c[n-1])c[n] + T(2A - h[n-1]c[n-1]) = 0 // c[n] * c[n] + T(2A - h[n-1]c[n-1]) = 0 // c[n] * c[n] = -T(2A - h[n-1]c[n-1]) // c[n] * c[n] = T(h[n-1]c[n-1] - 2A) // c[n] = sqrt(T(h[n-1]c[n-1] - 2A)) (9) // // We continue so long as the root term in (9) is positive. The sign changes // once we pass the cone apex. We also add a restriction h[n] >= baseChordLength, // stopping once that fails. I suspect that this only occurs once the root term // in (9) changes sign. // We don't know how many vertices we have head of time. Vector3[] radials = new Vector3[2]; float nearAlignedDot = Mathf.Cos(85.0f / 180.0f * Mathf.PI); if (Vector3.Dot(axis, new Vector3(0, 1, 0)) < nearAlignedDot) { radials[0] = Vector3.Cross(new Vector3(0, 1, 0), axis).normalized; } else { radials[0] = Vector3.Cross(new Vector3(1, 0, 0), axis).normalized; } radials[1] = Vector3.Cross(axis, radials[0]).normalized; // Add the base ring. // We build vertices for each ring first, then tessellate between the rings. Vector3 ringCentre, radial, vertex, firstVertex, normal; // Add each following ring. int rings = 0; float hn = length; // h[n] float cn = baseChordLength; // c[n] float dn = 0; // d[n] float radius = baseChordLength; // r[n-1] float hp, cp; // h[n-1] and c[n-1] ('p' for previous). // let T = 2 * tan(theta) sin(phi/2) float T = 2 * Mathf.Tan(angle) * Mathf.Sin(0.5f * segmentAngle); while (hn > baseChordLength) { hp = hn; cp = cn; // Add vertices for the ring at hp before. { //// Bitmap V coordinate: //// 1 at base, zero at apex. //float uf = (hn / length); radius = hp * Mathf.Tan(angle); //float vrange = radius / baseRadius; //float vstart = 0.5f - 0.5f * vrange; //float rlen; ringCentre = apex + hp * axis; firstVertex = ringCentre + radius * radials[0]; vertices.Add(firstVertex); for (int f = 1; f < facets; ++f) { //// Bitmap V coordinate. Range varies such that at the base it is [0, 1] and it is 0.5 a the apex. //float vf = vstart + vrange * ((float)f / (float)facets); float currentFacetAngle = f * segmentAngle; radial = radius * (Mathf.Cos(currentFacetAngle) * radials[0] + Mathf.Sin(currentFacetAngle) * radials[1]); //rlen = radial.magnitude; vertex = ringCentre + radial; vertices.Add(vertex); } } // c[n] = sqrt(T(h[n-1]c[n-1] - 2A)) (9) float rootTerm = T * (hp * cp - 2 * quadArea); if (rootTerm > 0) { cn = Mathf.Sqrt(rootTerm); // d[n] = 2A / (c[n-1] + c[n]) (2) dn = 2 * quadArea / (cp + cn); // Setup next iteration. hn = hp - dn; } else { hn = dn = 0; } ++rings; } // Add the apex vertex as the last vertex. // Add apex vertices. If not generating normals, we just add one. // If generating normals, we add one for each facet to support individual normals. int apexStart = vertices.Count; if (normals == null) { vertices.Add(apex); } else { for (int i = 0; i < facets; ++i) { vertices.Add(apex); } // Add normals for each of the existing vertices. // Each facet vertex has the same normal as the other vertices for the same facet. Vector3 toApex, v; // rings + 1 to cover the apex vertices for (int r = 0; r < rings + 1; ++r) { for (int f = 0; f < facets; ++f) { normal = vertices[f]; // Always start with base vertex. // Find the vector to the apex. toApex = apex - normal; // Remove height component from the future normal normal -= Vector3.Dot(normal, axis) * axis; //normal.Normalize(); // Cross and normalise to get the actual normal. v = Vector3.Cross(toApex, normal); normal = Vector3.Cross(v, toApex).normalized; normals.Add(normal); } } } // Now triangulate between the rings. for (int r = 1; r < rings; ++r) { int ringStartIndex = r * facets; int prevRingStartIndex = ringStartIndex - facets; for (int f = 0; f < facets; ++f) { indices.Add(prevRingStartIndex + f); indices.Add(ringStartIndex + (f + 1) % facets); indices.Add(prevRingStartIndex + (f + 1) % facets); indices.Add(prevRingStartIndex + f); indices.Add(ringStartIndex + f); indices.Add(ringStartIndex + (f + 1) % facets); } } // Triangulate with the apex vertex. int lastStartIndex = (rings - 1) * facets; if (normals == null) { for (int f = 0; f < facets; ++f) { indices.Add(apexStart); // Apex vertex indices.Add(lastStartIndex + (f + 1) % facets); indices.Add(lastStartIndex + f); } } else { for (int f = 0; f < facets; ++f) { indices.Add(apexStart + f); // Apex vertex indices.Add(lastStartIndex + (f + 1) % facets); indices.Add(lastStartIndex + f); } } if (tessellateBase) { // Add and tessellate base vertices. We copy or re-use the initial ring int firstBaseIndex = 0; if (normals != null) { // Copy initial ring. firstBaseIndex = vertices.Count; for (int i = 0; i < facets; ++i) { vertices.Add(vertices[i]); normals.Add(axis); } } for (int i = 1; i < facets - 1; ++i) { indices.Add(firstBaseIndex); indices.Add(firstBaseIndex + i); indices.Add(firstBaseIndex + i + 1); } } return(true); }
/// <summary> /// Calculate a rotatation based on mouse movement /// </summary> Quaternion ArcBall(Vector3 from, Vector3 to) { float dot = Vector3.Dot(from, to); Vector3 part = Vector3.Cross(from, to); return new Quaternion(part.X, part.Y, part.Z, dot); }
public Mesh InitializeStarfield() { float arg_49_0 = (!(Camera.main != null)) ? ((!(Camera.current != null)) ? 990f : Camera.current.farClipPlane) : (Camera.main.farClipPlane - 10f); float num = 5200f; float size = num / 100f * this.starSizeScale; TextAsset textAsset = Resources.Load <TextAsset>("StarsData"); if (textAsset == null) { Debug.Log("Can't find or read StarsData.bytes file."); return(null); } StarField.Star[] array = new StarField.Star[9110]; using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(textAsset.bytes))) { for (int i = 0; i < 9110; i++) { array[i].position.x = binaryReader.ReadSingle(); array[i].position.z = binaryReader.ReadSingle(); array[i].position.y = binaryReader.ReadSingle(); array[i].position = Vector3.Scale(array[i].position, new Vector3(-1f, 1f, -1f)); array[i].color.r = binaryReader.ReadSingle(); array[i].color.g = binaryReader.ReadSingle(); array[i].color.b = binaryReader.ReadSingle(); float a = Vector3.Dot(new Vector3(array[i].color.r, array[i].color.g, array[i].color.b), new Vector3(0.22f, 0.707f, 0.071f)); array[i].color.a = a; if (array[i].position.y >= 0.1f && array[i].color.a >= 0.017037f) { CombineInstance item = default(CombineInstance); item.mesh = this.createQuad(size); item.transform = this.BillboardMatrix(array[i].position * num); Color[] colors = new Color[] { array[i].color, array[i].color, array[i].color, array[i].color }; item.mesh.colors = colors; this.starQuad.Add(item); } } } Mesh mesh = new Mesh(); mesh.name = "StarFieldMesh"; mesh.CombineMeshes(this.starQuad.ToArray()); for (int j = 0; j < this.starQuad.Count; j++) { if (Application.isPlaying) { UnityEngine.Object.Destroy(this.starQuad[j].mesh); } else { UnityEngine.Object.DestroyImmediate(this.starQuad[j].mesh); } } this.starQuad.Clear(); mesh.Optimize(); mesh.bounds = new Bounds(Vector3.zero, Vector3.one * 2E+09f); return(mesh); }
/// <summary> /// Initializes translation-specific manipulator data and functions /// </summary> private void InitTranslation() { Dictionary <AxisFlags, Matrix> axis_transforms = new Dictionary <AxisFlags, Matrix>(); axis_transforms[AxisFlags.X] = Matrix.CreateRotationZ(-MathHelper.PiOver2); axis_transforms[AxisFlags.Y] = Matrix.Identity; axis_transforms[AxisFlags.Z] = Matrix.CreateRotationX(MathHelper.PiOver2); axis_transforms[AxisFlags.X | AxisFlags.Y] = Matrix.Identity; axis_transforms[AxisFlags.X | AxisFlags.Z] = Matrix.CreateRotationX(MathHelper.PiOver2); axis_transforms[AxisFlags.Y | AxisFlags.Z] = Matrix.CreateRotationY(-MathHelper.PiOver2); // the base draw handler for single-axis draw calls Action <Matrix> base_draw_axis = new Action <Matrix>(delegate(Matrix transform) { GraphicsDevice device = mGraphics.GraphicsDevice; ManipulatorSettings.TranslationSettings settings = mSettings.Translation; // draw the axis cylinder to represent the axis itself if ((settings.AxisDrawMode & AxisDirections.Positive) == AxisDirections.Positive) { XPrimitives.DrawCylinder(device, Vector3.UnitY * settings.AxisExtent * 0.5f, settings.AxisExtent * 0.5f, settings.AxisRadius, 8, transform); XPrimitives.DrawCone(device, Vector3.UnitY * settings.AxisExtent, settings.ConeRadius, settings.ConeHeight, 8, transform); } if ((settings.AxisDrawMode & AxisDirections.Negative) == AxisDirections.Negative) { Matrix y_invert = Matrix.CreateRotationX(MathHelper.Pi); XPrimitives.DrawCylinder(device, -Vector3.UnitY * settings.AxisExtent * 0.5f, settings.AxisExtent * 0.5f, settings.AxisRadius, 8, transform); XPrimitives.DrawCone(device, Vector3.UnitY * settings.AxisExtent, settings.ConeRadius, settings.ConeHeight, 8, y_invert * transform); } }); // use the base single axis draw function for each of the main axes, and // transform using the appropriate axis transform from the array defined aboved mDrawFunctions[TransformationMode.TranslationAxis][AxisFlags.X] = mDrawFunctions[TransformationMode.TranslationAxis][AxisFlags.Y] = mDrawFunctions[TransformationMode.TranslationAxis][AxisFlags.Z] = delegate(AxisFlags axis) { base_draw_axis(axis_transforms[axis]); }; Action <Matrix> base_draw_plane = new Action <Matrix>(delegate(Matrix transform) { GraphicsDevice device = mGraphics.GraphicsDevice; ManipulatorSettings.TranslationSettings settings = mSettings.Translation; Vector3 up = Vector3.UnitY * settings.PlaneQuadrantSize; Vector3 right = Vector3.UnitX * settings.PlaneQuadrantSize; bool draw_pos = (settings.AxisDrawMode & AxisDirections.Positive) == AxisDirections.Positive; bool draw_neg = (settings.AxisDrawMode & AxisDirections.Negative) == AxisDirections.Negative; if (draw_pos) { XPrimitives.DrawTriangle(device, up, right, Vector3.Zero, transform); } if (draw_neg) { XPrimitives.DrawTriangle(device, -up, -right, Vector3.Zero, transform); } if (draw_pos && draw_neg) { XPrimitives.DrawTriangle(device, -up, right, Vector3.Zero, transform); XPrimitives.DrawTriangle(device, up, -right, Vector3.Zero, transform); } }); mDrawFunctions[TransformationMode.TranslationPlane][AxisFlags.X | AxisFlags.Y] = mDrawFunctions[TransformationMode.TranslationPlane][AxisFlags.X | AxisFlags.Z] = mDrawFunctions[TransformationMode.TranslationPlane][AxisFlags.Y | AxisFlags.Z] = delegate(AxisFlags axis) { base_draw_plane(axis_transforms[axis]); }; // all single-axis translations will use the same manip function mManipFunctions[TransformationMode.TranslationAxis][AxisFlags.X] = mManipFunctions[TransformationMode.TranslationAxis][AxisFlags.Y] = mManipFunctions[TransformationMode.TranslationAxis][AxisFlags.Z] = delegate() { // get the unit version of the seclected axis Vector3 axis = GetUnitAxis(mSelectedAxes); // we need to project using the translation component of the current // ITransform in order to obtain a projected unit axis originating // from the transform's position Matrix translation = Matrix.CreateTranslation(mTransform.Translation); // project the origin onto the screen at the transform's position Vector3 start_position = Viewport.Project(Vector3.Zero, ProjectionMatrix, ViewMatrix, translation); // project the unit axis onto the screen at the transform's position Vector3 end_position = Viewport.Project(axis, ProjectionMatrix, ViewMatrix, translation); // calculate the normalized direction vector of the unit axis in screen space Vector3 screen_direction = Vector3.Normalize(end_position - start_position); // calculate the projected mouse delta along the screen direction vector end_position = start_position + (screen_direction * (Vector3.Dot(new Vector3(mInput.Delta, 0f), screen_direction))); // unproject the screen points back into world space using the translation transform // to get the world space start and end positions in regard to the mouse delta along // the mouse direction vector start_position = Viewport.Unproject(start_position, ProjectionMatrix, ViewMatrix, translation); end_position = Viewport.Unproject(end_position, ProjectionMatrix, ViewMatrix, translation); // calculate the difference vector between the world space start and end points Vector3 difference = end_position - start_position; // create a view frustum based on the current view and projection matrices BoundingFrustum frust = new BoundingFrustum(ViewMatrix * ProjectionMatrix); // if the new translation position is within the current frustum, then add the difference // to the current transform's translation component, otherwise the transform would be outside of // the screen if (frust.Contains(mTransform.Translation + difference) == ContainmentType.Contains) { mTransform.Translation += difference; } }; // all planetranslations will use the same manip function mManipFunctions[TransformationMode.TranslationPlane][AxisFlags.X | AxisFlags.Y] = mManipFunctions[TransformationMode.TranslationPlane][AxisFlags.X | AxisFlags.Z] = mManipFunctions[TransformationMode.TranslationPlane][AxisFlags.Y | AxisFlags.Z] = delegate() { // get the plane representing the two selected axes Plane p = GetPlane(mSelectedAxes); // cast rays into the scene from the mouse start and end points Ray sray = GetPickRay(mInput.Start); Ray eray = GetPickRay(mInput.End); // intersect the pick rays with the dual axis plane we want to move along float?sisect = sray.Intersects(p); float?eisect = eray.Intersects(p); // if either of the intersections is invalid then bail out as it would // be impossible to calculate the difference if (!sisect.HasValue || !eisect.HasValue) { return; } // obtain the intersection points of each ray with the dual axis plane Vector3 spos = sray.Position + (sray.Direction * sisect.Value); Vector3 epos = eray.Position + (eray.Direction * eisect.Value); // calculate the difference between the intersection points Vector3 diff = epos - spos; // obtain the current view frustum using the camera's view and projection matrices BoundingFrustum frust = new BoundingFrustum(ViewMatrix * ProjectionMatrix); // if the new translation is within the current camera frustum, then add the difference // to the current transformation's translation component if (frust.Contains(mTransform.Translation + diff) == ContainmentType.Contains) { mTransform.Translation += diff; } }; }
// Update is called once per frame void Update() { if (fpsOn) { return; } if (Time.timeScale == 1) { deltaT = Time.deltaTime; } else if (Time.timeScale > 1) { deltaT = Time.deltaTime / Time.timeScale; } else { deltaT = 0.015f; } #if UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY if (enableTouchPan) { Quaternion camDir = Quaternion.Euler(0, transform.eulerAngles.y, 0); if (Input.touchCount == 1) { Touch touch = Input.touches[0]; if (touch.phase == TouchPhase.Moved) { Vector3 deltaPos = touch.position; if (lastTouchPos != new Vector3(9999, 9999, 9999)) { deltaPos = deltaPos - lastTouchPos; moveDir = new Vector3(deltaPos.x, 0, deltaPos.y).normalized *-1; } lastTouchPos = touch.position; } } else { lastTouchPos = new Vector3(9999, 9999, 9999); } Vector3 dir = thisT.InverseTransformDirection(camDir * moveDir) * 1.5f; thisT.Translate(dir * panSpeed * deltaT); moveDir = moveDir * (1 - deltaT * 5); } if (enableTouchZoom) { if (Input.touchCount == 2) { Touch touch1 = Input.touches[0]; Touch touch2 = Input.touches[1]; //~ Vector3 zoomScreenPos=(touch1.position+touch2.position)/2; if (touch1.phase == TouchPhase.Moved && touch1.phase == TouchPhase.Moved) { Vector3 dirDelta = (touch1.position - touch1.deltaPosition) - (touch2.position - touch2.deltaPosition); Vector3 dir = touch1.position - touch2.position; float dot = Vector3.Dot(dirDelta.normalized, dir.normalized); if (Mathf.Abs(dot) > 0.7f) { touchZoomSpeed = dir.magnitude - dirDelta.magnitude; } } } if (touchZoomSpeed < 0) { if (Vector3.Distance(camT.position, thisT.position) < maxZoomDistance) { camT.Translate(Vector3.forward * Time.deltaTime * zoomSpeed * touchZoomSpeed); currentZoom += Time.deltaTime * zoomSpeed * touchZoomSpeed; } } else if (touchZoomSpeed > 0) { if (Vector3.Distance(camT.position, thisT.position) > minZoomDistance) { camT.Translate(Vector3.forward * Time.deltaTime * zoomSpeed * touchZoomSpeed); currentZoom += Time.deltaTime * zoomSpeed * touchZoomSpeed; } } touchZoomSpeed = touchZoomSpeed * (1 - Time.deltaTime * 5); } if (enableTouchRotate) { if (Input.touchCount == 2) { Touch touch1 = Input.touches[0]; Touch touch2 = Input.touches[1]; Vector2 delta1 = touch1.deltaPosition.normalized; Vector2 delta2 = touch2.deltaPosition.normalized; Vector2 delta = (delta1 + delta2) / 2; float rotX = thisT.rotation.eulerAngles.x - delta.y * rotationSpeed; float rotY = thisT.rotation.eulerAngles.y + delta.x * rotationSpeed; rotX = Mathf.Clamp(rotX, minRotateAngle, maxRotateAngle); //~ Quaternion rot=Quaternion.Euler(delta.y, delta.x, 0); //Debug.Log(rotX+" "+rotY); thisT.rotation = Quaternion.Euler(rotX, rotY, 0); //thisT.rotation*=rot; } } #endif #if UNITY_EDITOR || !(UNITY_IPHONE && UNITY_ANDROID && UNITY_WP8 && UNITY_BLACKBERRY) //mouse and keyboard if (enableMouseRotate) { if (Input.GetMouseButtonDown(1)) { initialMousePosX = Input.mousePosition.x; initialMousePosY = Input.mousePosition.y; initialRotX = thisT.eulerAngles.y; initialRotY = thisT.eulerAngles.x; } if (Input.GetMouseButton(1)) { float deltaX = Input.mousePosition.x - initialMousePosX; float deltaRotX = (.1f * (initialRotX / Screen.width)); float rotX = deltaX + deltaRotX; float deltaY = initialMousePosY - Input.mousePosition.y; float deltaRotY = -(.1f * (initialRotY / Screen.height)); float rotY = deltaY + deltaRotY; float y = rotY + initialRotY; //limit the rotation if (y > maxRotateAngle) { initialRotY -= (rotY + initialRotY) - maxRotateAngle; y = maxRotateAngle; } else if (y < minRotateAngle) { initialRotY += minRotateAngle - (rotY + initialRotY); y = minRotateAngle; } thisT.rotation = Quaternion.Euler(y, rotX + initialRotX, 0); } } Quaternion direction = Quaternion.Euler(0, thisT.eulerAngles.y, 0); if (enableKeyPanning) { if (Input.GetButton("Horizontal")) { Vector3 dir = transform.InverseTransformDirection(direction * Vector3.right); thisT.Translate(dir * panSpeed * deltaT * Input.GetAxisRaw("Horizontal")); } if (Input.GetButton("Vertical")) { Vector3 dir = transform.InverseTransformDirection(direction * Vector3.forward); thisT.Translate(dir * panSpeed * deltaT * Input.GetAxisRaw("Vertical")); } } if (enableMousePanning) { Vector3 mousePos = Input.mousePosition; Vector3 dirHor = transform.InverseTransformDirection(direction * Vector3.right); if (mousePos.x <= 0) { thisT.Translate(dirHor * panSpeed * deltaT * -3); } else if (mousePos.x <= mousePanningZoneWidth) { thisT.Translate(dirHor * panSpeed * deltaT * -1); } else if (mousePos.x >= Screen.width) { thisT.Translate(dirHor * panSpeed * deltaT * 3); } else if (mousePos.x > Screen.width - mousePanningZoneWidth) { thisT.Translate(dirHor * panSpeed * deltaT * 1); } Vector3 dirVer = transform.InverseTransformDirection(direction * Vector3.forward); if (mousePos.y <= 0) { thisT.Translate(dirVer * panSpeed * deltaT * -3); } else if (mousePos.y <= mousePanningZoneWidth) { thisT.Translate(dirVer * panSpeed * deltaT * -1); } else if (mousePos.y >= Screen.height) { thisT.Translate(dirVer * panSpeed * deltaT * 3); } else if (mousePos.y > Screen.height - mousePanningZoneWidth) { thisT.Translate(dirVer * panSpeed * deltaT * 1); } } if (enableMouseZoom) { float zoomInput = Input.GetAxis("Mouse ScrollWheel"); if (zoomInput != 0) { currentZoom += zoomSpeed * zoomInput; currentZoom = Mathf.Clamp(currentZoom, -maxZoomDistance, -minZoomDistance); } } #endif if (avoidClipping) { Vector3 aPos = thisT.TransformPoint(new Vector3(0, 0, currentZoom)); Vector3 dirC = aPos - thisT.position; float dist = Vector3.Distance(aPos, thisT.position); RaycastHit hit; obstacle = Physics.Raycast(thisT.position, dirC, out hit, dist); if (!obstacle) { float camZ = Mathf.Lerp(camT.localPosition.z, currentZoom, Time.deltaTime * 4); camT.localPosition = new Vector3(camT.localPosition.x, camT.localPosition.y, camZ); } else { dist = Vector3.Distance(hit.point, thisT.position) * 0.85f; float camZ = Mathf.Lerp(camT.localPosition.z, -dist, Time.deltaTime * 50); camT.localPosition = new Vector3(camT.localPosition.x, camT.localPosition.y, camZ); } } else { float camZ = Mathf.Lerp(camT.localPosition.z, currentZoom, Time.deltaTime * 4); camT.localPosition = new Vector3(camT.localPosition.x, camT.localPosition.y, camZ); } float x = Mathf.Clamp(thisT.position.x, minPosX, maxPosX); float z = Mathf.Clamp(thisT.position.z, minPosZ, maxPosZ); thisT.position = new Vector3(x, thisT.position.y, z); }
/// <summary> /// Compares if a and b are nearly on the same axis and will probably return a zero vector from a cross product /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="epsilon"></param> /// <returns></returns> public static bool NearSameAxis(Vector3 a, Vector3 b, float epsilon = MathUtil.EPSILON) { return MathUtil.FuzzyEqual(Mathf.Abs(Vector3.Dot(a.normalized, b.normalized)), 1.0f, epsilon); }
/// <summary> /// The Unity Update() method. /// </summary> public void Update() { // To use Recording API: // 1. Create an instance of ARCoreRecordingConfig. The Mp4DatasetFilepath needs to // be accessible by the app, e.g. Application.persistentDataPath, or you can request // the permission of external storage. // 2. Call Session.StartRecording(ARCoreRecordingConfig) when a valid ARCore session // is available. // 3. Call Session.StopRecording() to end the recording. When // ARCoreRecordingConfig.AutoStopOnPause is true, it can also stop recording when // the ARCoreSession component is disabled. // To use Playback API: // 1. Pause the session by disabling ARCoreSession component. // 2. In the next frame or later, call Session.SetPlaybackDataset(datasetFilepath) // where the datasetFilepath is the same one used by Recording API. // 3. In the next frame or later, resume the session by enabling ARCoreSession component // and the app will play the recorded camera stream install of using the real time // camera stream. UpdateApplicationLifecycle(); // If the player has not touched the screen, we are done with this update. Touch touch; if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began) { return; } // Should not handle input if the player is pointing on UI. if (EventSystem.current.IsPointerOverGameObject(touch.fingerId)) { return; } // Raycast against the location the player touched to search for planes. TrackableHit hit; bool foundHit = false; if (InstantPlacementMenu.IsInstantPlacementEnabled()) { foundHit = Frame.RaycastInstantPlacement( touch.position.x, touch.position.y, 1.0f, out hit); } else { TrackableHitFlags raycastFilter = TrackableHitFlags.PlaneWithinPolygon | TrackableHitFlags.FeaturePointWithSurfaceNormal; foundHit = Frame.Raycast( touch.position.x, touch.position.y, raycastFilter, out hit); } if (foundHit) { // Use hit pose and camera pose to check if hittest is from the // back of the plane, if it is, no need to create the anchor. if ((hit.Trackable is DetectedPlane) && Vector3.Dot(FirstPersonCamera.transform.position - hit.Pose.position, hit.Pose.rotation * Vector3.up) < 0) { Debug.Log("Hit at back of the current DetectedPlane"); } else { if (DepthMenu != null) { // Show depth card window if necessary. DepthMenu.ConfigureDepthBeforePlacingFirstAsset(); } // Choose the prefab based on the Trackable that got hit. GameObject prefab; if (hit.Trackable is InstantPlacementPoint) { prefab = InstantPlacementPrefab; } else if (hit.Trackable is FeaturePoint) { prefab = GameObjectPointPrefab; } else if (hit.Trackable is DetectedPlane) { DetectedPlane detectedPlane = hit.Trackable as DetectedPlane; if (detectedPlane.PlaneType == DetectedPlaneType.Vertical) { prefab = GameObjectVerticalPlanePrefab; } else { prefab = GameObjectHorizontalPlanePrefab; } } else { prefab = GameObjectHorizontalPlanePrefab; } // Instantiate prefab at the hit pose. var gameObject = Instantiate(prefab, hit.Pose.position, hit.Pose.rotation); // Compensate for the hitPose rotation facing away from the raycast (i.e. // camera). gameObject.transform.Rotate(0, _prefabRotation, 0, Space.Self); // Create an anchor to allow ARCore to track the hitpoint as understanding of // the physical world evolves. var anchor = hit.Trackable.CreateAnchor(hit.Pose); // Make game object a child of the anchor. gameObject.transform.parent = anchor.transform; // Initialize Instant Placement Effect. if (hit.Trackable is InstantPlacementPoint) { gameObject.GetComponentInChildren <InstantPlacementEffect>() .InitializeWithTrackable(hit.Trackable); } } } }
/// 法線と一点から平面を作成 public GeometryPlane( Vector3 prmNor, Vector3 pos ) { Nor = prmNor.Normalize(); D = prmNor.Dot( pos ) * -1; }
/// <summary> /// Gets weighting values from anipal's Eye module when enable eye callback function. /// </summary> /// <param name="shapes">Weighting values obtained from anipal's Eye module.</param> /// <param name="eye_data">ViveSR.anipal.Eye.EyeData. </param> /// <returns>Indicates whether the values received are new.</returns>\ /// public static bool GetEyeWeightings(out Dictionary <EyeShape, float> shapes, EyeData eye_data) { float[] openness = new float[2]; bool[] valid = new bool[2]; Vector2[] pupilPosition = new Vector2[2]; foreach (EyeIndex index in (EyeIndex[])Enum.GetValues(typeof(EyeIndex))) { GetEyeOpenness(index, out openness[(int)index], eye_data); valid[(int)index] = GetPupilPosition(index, out pupilPosition[(int)index]); } float[] weighting_up = new float[3] { Mathf.Max(pupilPosition[(int)GazeIndex.LEFT].y, 0f), Mathf.Max(pupilPosition[(int)GazeIndex.RIGHT].y, 0f), 0 }; float[] weighting_down = new float[3] { Mathf.Max(-pupilPosition[(int)GazeIndex.LEFT].y, 0f), Mathf.Max(-pupilPosition[(int)GazeIndex.RIGHT].y, 0f), 0 }; float[] weighting_left = new float[3] { Mathf.Max(-pupilPosition[(int)GazeIndex.LEFT].x, 0f), Mathf.Max(-pupilPosition[(int)GazeIndex.RIGHT].x, 0f), 0 }; float[] weighting_right = new float[3] { Mathf.Max(pupilPosition[(int)GazeIndex.LEFT].x, 0f), Mathf.Max(pupilPosition[(int)GazeIndex.RIGHT].x, 0f), 0 }; weighting_up[(int)GazeIndex.COMBINE] = (weighting_up[(int)GazeIndex.LEFT] + weighting_up[(int)GazeIndex.RIGHT]) / 2; weighting_down[(int)GazeIndex.COMBINE] = (weighting_down[(int)GazeIndex.LEFT] + weighting_down[(int)GazeIndex.RIGHT]) / 2; weighting_left[(int)GazeIndex.COMBINE] = (weighting_left[(int)GazeIndex.LEFT] + weighting_left[(int)GazeIndex.RIGHT]) / 2; weighting_right[(int)GazeIndex.COMBINE] = (weighting_right[(int)GazeIndex.LEFT] + weighting_right[(int)GazeIndex.RIGHT]) / 2; foreach (EyeShape index in (EyeShape[])Enum.GetValues(typeof(EyeShape))) { Weightings[index] = 0; } Weightings[EyeShape.Eye_Left_Blink] = 1 - openness[(int)EyeIndex.LEFT]; Weightings[EyeShape.Eye_Right_Blink] = 1 - openness[(int)EyeIndex.RIGHT]; if (valid[(int)EyeIndex.LEFT] && valid[(int)EyeIndex.RIGHT]) { Ray gaze_ray = new Ray(); GetGazeRay(GazeIndex.COMBINE, out gaze_ray, eye_data); Vector3 gaze_direction = gaze_ray.direction - gaze_ray.origin; gaze_direction.x = 0.0f; Vector3 gaze_direction_normalized = gaze_direction.normalized; Vector3 gaze_axis_z = Vector3.forward; float y_weight = Mathf.Acos(Vector3.Dot(gaze_direction_normalized, gaze_axis_z)); Weightings[EyeShape.Eye_Left_Up] = gaze_direction_normalized.y < 0 ? 0 : y_weight; Weightings[EyeShape.Eye_Left_Down] = gaze_direction_normalized.y < 0 ? y_weight : 0; Weightings[EyeShape.Eye_Left_Left] = weighting_left[(int)GazeIndex.COMBINE]; Weightings[EyeShape.Eye_Left_Right] = weighting_right[(int)GazeIndex.COMBINE]; Weightings[EyeShape.Eye_Left_Wide] = Weightings[EyeShape.Eye_Left_Up]; Weightings[EyeShape.Eye_Right_Up] = gaze_direction_normalized.y < 0 ? 0 : y_weight; Weightings[EyeShape.Eye_Right_Down] = gaze_direction_normalized.y < 0 ? y_weight : 0; Weightings[EyeShape.Eye_Right_Left] = weighting_left[(int)GazeIndex.COMBINE]; Weightings[EyeShape.Eye_Right_Right] = weighting_right[(int)GazeIndex.COMBINE]; Weightings[EyeShape.Eye_Right_Wide] = Weightings[EyeShape.Eye_Right_Up]; } else if (valid[(int)EyeIndex.LEFT]) { Ray gaze_ray = new Ray(); GetGazeRay(GazeIndex.LEFT, out gaze_ray, eye_data); Vector3 gaze_direction = gaze_ray.direction - gaze_ray.origin; gaze_direction.x = 0.0f; Vector3 gaze_direction_normalized = gaze_direction.normalized; Vector3 gaze_axis_z = Vector3.forward; float y_weight = Mathf.Acos(Vector3.Dot(gaze_direction_normalized, gaze_axis_z)); Weightings[EyeShape.Eye_Left_Up] = gaze_direction_normalized.y < 0 ? 0 : y_weight; Weightings[EyeShape.Eye_Left_Down] = gaze_direction_normalized.y < 0 ? y_weight : 0; Weightings[EyeShape.Eye_Left_Left] = weighting_left[(int)GazeIndex.LEFT]; Weightings[EyeShape.Eye_Left_Right] = weighting_right[(int)GazeIndex.LEFT]; Weightings[EyeShape.Eye_Left_Wide] = Weightings[EyeShape.Eye_Left_Up]; } else if (valid[(int)EyeIndex.RIGHT]) { Ray gaze_ray = new Ray(); GetGazeRay(GazeIndex.RIGHT, out gaze_ray, eye_data); Vector3 gaze_direction = gaze_ray.direction - gaze_ray.origin; gaze_direction.x = 0.0f; Vector3 gaze_direction_normalized = gaze_direction.normalized; Vector3 gaze_axis_z = Vector3.forward; float y_weight = Mathf.Acos(Vector3.Dot(gaze_direction_normalized, gaze_axis_z)); Weightings[EyeShape.Eye_Right_Up] = gaze_direction_normalized.y < 0 ? 0 : y_weight; Weightings[EyeShape.Eye_Right_Down] = gaze_direction_normalized.y < 0 ? y_weight : 0; Weightings[EyeShape.Eye_Right_Left] = weighting_left[(int)GazeIndex.RIGHT]; Weightings[EyeShape.Eye_Right_Right] = weighting_right[(int)GazeIndex.RIGHT]; Weightings[EyeShape.Eye_Right_Wide] = Weightings[EyeShape.Eye_Right_Up]; } shapes = Weightings; return(true); }
private static bool RayEnters(Vector3 rayN, Vector3 triN) { if (rayN.Dot(triN) < 0) return true; return false; }
/// <summary> /// Query the possible connections for this field /// </summary> /// <param name="match">Out parameter that signifies the type of match (ignore, reject or connect)</param> /// <param name="bothkinds">Optional boolean to specify whether we want to check for both connection field kinds</param> /// <param name="onlyConnectTo">An optional filter field if you only want to check connections on specific fields</param> /// <returns>A list of tuples for the possible connections</returns> public HashSet <(Connection, Connection)> QueryConnections(out Connection.ConnectionMatch match, bool bothkinds = false, ICollection <ConnectionField> onlyConnectTo = null) { LayerMask mask; if (bothkinds) { mask = LayerMask.GetMask(GetLayer(FieldKind.receptor), GetLayer(FieldKind.connector)); } else { var opposite = kind == FieldKind.connector ? FieldKind.receptor : FieldKind.connector; mask = LayerMask.GetMask(GetLayer(opposite)); } HashSet <(Connection, Connection)> validConnections = new HashSet <(Connection, Connection)>(); match = Connection.ConnectionMatch.ignore; // PhysicsScene var physicsScene = gameObject.scene.GetPhysicsScene(); var size = new Vector3((gridSize.x + 1) * BrickBuildingUtility.LU_5, BrickBuildingUtility.LU_1 * 2, (gridSize.y + 1) * BrickBuildingUtility.LU_5); var center = new Vector3((size.x - BrickBuildingUtility.LU_5) * -0.5f, 0.0f, (size.z - BrickBuildingUtility.LU_5) * 0.5f); var hits = physicsScene.OverlapBox(transform.TransformPoint(center), size * 0.5f, BrickBuildingUtility.colliderBuffer, transform.rotation, mask, QueryTriggerInteraction.Collide); for (var i = 0; i < hits; i++) { var overlap = BrickBuildingUtility.colliderBuffer[i]; var field = overlap.GetComponent <ConnectionField>(); if (field == null || field == this) { continue; } if (onlyConnectTo != null && !onlyConnectTo.Contains(field)) { continue; } if (Mathf.Abs(Vector3.Dot(field.transform.up, transform.up)) < 0.95f) { continue; } if (!GetOverlap(field, this, out Vector2Int min, out Vector2Int max)) { continue; } for (var x = min.x; x < max.x + 1; x++) { for (var z = min.y; z < max.y + 1; z++) { var localPos = new Vector3(x * BrickBuildingUtility.LU_5, 0.0f, z * BrickBuildingUtility.LU_5); var fieldConnection = field.GetConnectionAt(ConnectionField.ToGridPos(localPos)); if (fieldConnection != null && !field.HasConnection(fieldConnection)) { var worldPos = field.GetPosition(fieldConnection); var connection = GetConnectionAt(worldPos); if (connection != null && !HasConnection(connection)) { // Note: ConnectionValid checks both rejection and distance (position + rotation) so we need // to make sure we take care of both in case of false. if (!Connection.ConnectionValid(fieldConnection, connection, out Connection.ConnectionMatch pairMatch)) { if (pairMatch != Connection.ConnectionMatch.reject) { continue; } else { match = pairMatch; validConnections.Clear(); return(validConnections); } } if (pairMatch == Connection.ConnectionMatch.connect) { validConnections.Add((connection, fieldConnection)); } } } } } } match = Connection.ConnectionMatch.connect; return(validConnections); }
public static void Reflect(ref Vector3 vector, ref Vector3 planeNormal, out Vector3 result) { result = vector - (planeNormal * vector.Dot(planeNormal) * 2); }
public void VoxelizeInput(Pathfinding.Util.GraphTransform graphTransform, Bounds graphSpaceBounds) { AstarProfiler.StartProfile("Build Navigation Mesh"); AstarProfiler.StartProfile("Voxelizing - Step 1"); // Transform from voxel space to graph space. // then scale from voxel space (one unit equals one voxel) // Finally add min Matrix4x4 voxelMatrix = Matrix4x4.TRS(graphSpaceBounds.min, Quaternion.identity, Vector3.one) * Matrix4x4.Scale(new Vector3(cellSize, cellHeight, cellSize)); transformVoxel2Graph = new Pathfinding.Util.GraphTransform(voxelMatrix); // Transform from voxel space to world space // add half a voxel to fix rounding transform = graphTransform * voxelMatrix * Matrix4x4.TRS(new Vector3(0.5f, 0, 0.5f), Quaternion.identity, Vector3.one); int maximumVoxelYCoord = (int)(graphSpaceBounds.size.y / cellHeight); AstarProfiler.EndProfile("Voxelizing - Step 1"); AstarProfiler.StartProfile("Voxelizing - Step 2 - Init"); // Cosine of the slope limit in voxel space (some tweaks are needed because the voxel space might be stretched out along the y axis) float slopeLimit = Mathf.Cos(Mathf.Atan(Mathf.Tan(maxSlope * Mathf.Deg2Rad) * (cellSize / cellHeight))); // Temporary arrays used for rasterization var clipperOrig = new VoxelPolygonClipper(3); var clipperX1 = new VoxelPolygonClipper(7); var clipperX2 = new VoxelPolygonClipper(7); var clipperZ1 = new VoxelPolygonClipper(7); var clipperZ2 = new VoxelPolygonClipper(7); if (inputMeshes == null) { throw new System.NullReferenceException("inputMeshes not set"); } // Find the largest lengths of vertex arrays and check for meshes which can be skipped int maxVerts = 0; for (int m = 0; m < inputMeshes.Count; m++) { maxVerts = System.Math.Max(inputMeshes[m].vertices.Length, maxVerts); } // Create buffer, here vertices will be stored multiplied with the local-to-voxel-space matrix var verts = new Vector3[maxVerts]; AstarProfiler.EndProfile("Voxelizing - Step 2 - Init"); AstarProfiler.StartProfile("Voxelizing - Step 2"); // This loop is the hottest place in the whole rasterization process // it usually accounts for around 50% of the time for (int m = 0; m < inputMeshes.Count; m++) { RasterizationMesh mesh = inputMeshes[m]; var meshMatrix = mesh.matrix; // Flip the orientation of all faces if the mesh is scaled in such a way // that the face orientations would change // This happens for example if a mesh has a negative scale along an odd number of axes // e.g it happens for the scale (-1, 1, 1) but not for (-1, -1, 1) or (1,1,1) var flipOrientation = VectorMath.ReversesFaceOrientations(meshMatrix); Vector3[] vs = mesh.vertices; int[] tris = mesh.triangles; int trisLength = mesh.numTriangles; // Transform vertices first to world space and then to voxel space for (int i = 0; i < vs.Length; i++) { verts[i] = transform.InverseTransform(meshMatrix.MultiplyPoint3x4(vs[i])); } int mesharea = mesh.area; for (int i = 0; i < trisLength; i += 3) { Vector3 p1 = verts[tris[i]]; Vector3 p2 = verts[tris[i + 1]]; Vector3 p3 = verts[tris[i + 2]]; if (flipOrientation) { var tmp = p1; p1 = p3; p3 = tmp; } int minX = (int)(Utility.Min(p1.x, p2.x, p3.x)); int minZ = (int)(Utility.Min(p1.z, p2.z, p3.z)); int maxX = (int)System.Math.Ceiling(Utility.Max(p1.x, p2.x, p3.x)); int maxZ = (int)System.Math.Ceiling(Utility.Max(p1.z, p2.z, p3.z)); minX = Mathf.Clamp(minX, 0, voxelArea.width - 1); maxX = Mathf.Clamp(maxX, 0, voxelArea.width - 1); minZ = Mathf.Clamp(minZ, 0, voxelArea.depth - 1); maxZ = Mathf.Clamp(maxZ, 0, voxelArea.depth - 1); // Check if the mesh is completely out of bounds if (minX >= voxelArea.width || minZ >= voxelArea.depth || maxX <= 0 || maxZ <= 0) { continue; } Vector3 normal; int area; //AstarProfiler.StartProfile ("Rasterize..."); normal = Vector3.Cross(p2 - p1, p3 - p1); float cosSlopeAngle = Vector3.Dot(normal.normalized, Vector3.up); if (cosSlopeAngle < slopeLimit) { area = UnwalkableArea; } else { area = 1 + mesharea; } clipperOrig[0] = p1; clipperOrig[1] = p2; clipperOrig[2] = p3; clipperOrig.n = 3; for (int x = minX; x <= maxX; x++) { clipperOrig.ClipPolygonAlongX(ref clipperX1, 1f, -x + 0.5f); if (clipperX1.n < 3) { continue; } clipperX1.ClipPolygonAlongX(ref clipperX2, -1F, x + 0.5F); if (clipperX2.n < 3) { continue; } float clampZ1 = clipperX2.z[0]; float clampZ2 = clipperX2.z[0]; for (int q = 1; q < clipperX2.n; q++) { float val = clipperX2.z[q]; clampZ1 = System.Math.Min(clampZ1, val); clampZ2 = System.Math.Max(clampZ2, val); } int clampZ1I = Mathf.Clamp((int)System.Math.Round(clampZ1), 0, voxelArea.depth - 1); int clampZ2I = Mathf.Clamp((int)System.Math.Round(clampZ2), 0, voxelArea.depth - 1); for (int z = clampZ1I; z <= clampZ2I; z++) { clipperX2.ClipPolygonAlongZWithYZ(ref clipperZ1, 1F, -z + 0.5F); if (clipperZ1.n < 3) { continue; } clipperZ1.ClipPolygonAlongZWithY(ref clipperZ2, -1F, z + 0.5F); if (clipperZ2.n < 3) { continue; } float sMin = clipperZ2.y[0]; float sMax = clipperZ2.y[0]; for (int q = 1; q < clipperZ2.n; q++) { float val = clipperZ2.y[q]; sMin = System.Math.Min(sMin, val); sMax = System.Math.Max(sMax, val); } int maxi = (int)System.Math.Ceiling(sMax); // Skip span if below or above the bounding box if (maxi >= 0 && sMin <= maximumVoxelYCoord) { // Make sure mini >= 0 int mini = System.Math.Max(0, (int)sMin); // Make sure the span is at least 1 voxel high maxi = System.Math.Max(mini + 1, maxi); voxelArea.AddLinkedSpan(z * voxelArea.width + x, (uint)mini, (uint)maxi, area, voxelWalkableClimb); } } } } //AstarProfiler.EndFastProfile(0); //AstarProfiler.EndProfile ("Rasterize..."); } AstarProfiler.EndProfile("Voxelizing - Step 2"); }
internal void TransformPlane( float[] norm, ref float dist ) { TransformVector( norm, true ); dist *= this.options.scale; var normal = new Vector3( norm[ 0 ], norm[ 1 ], norm[ 2 ] ); Vector3 point = normal*dist; point += this.options.move; dist = normal.Dot( point ); }
static void SmoothNormalToColor() { string NewMeshPath = "Assets/Models/Yuanshen/";; var trans = Selection.activeTransform; NewMeshPath += trans.name + "_" + System.DateTime.Now.ToString("yyyyMMddhhmmss") + ".asset"; // 获取Mesh Mesh mesh = new Mesh(); if (trans.GetComponent <SkinnedMeshRenderer>()) { mesh = trans.GetComponent <SkinnedMeshRenderer>().sharedMesh; } if (trans.GetComponent <MeshFilter>()) { mesh = trans.GetComponent <MeshFilter>().sharedMesh; } Debug.Log(mesh.name); // 计算进度 int sum = 6 * (mesh.vertices.Length / 3) + mesh.normals.Length; int count = 0; // 声明一个Vector3数组,长度与mesh.normals一样,用于存放 // 与mesh.vertices中顶点一一对应的光滑处理后的法线值 Vector3[] smoothedNormals = new Vector3[mesh.normals.Length]; // 空间换时间 (存下每个法线的相同的顶点索引) 其实就是真正的共享顶点 立方体的话因该是24 / 3=8个共享顶点。 // 这里用到了hash表 (可以去领扣刷刷hash表相关的题,游戏还是会用到的) Dictionary <Vector3, List <int> > vertexDic = new Dictionary <Vector3, List <int> >(); for (int i = 0; i < mesh.vertices.Length; i++) { float jd = count++ / (float)sum; EditorUtility.DisplayProgressBar("smooth", count.ToString(), jd); if (!vertexDic.ContainsKey(mesh.vertices[i])) { List <int> vertexIndexs = new List <int>(); vertexIndexs.Add(i); vertexDic.Add(mesh.vertices[i], vertexIndexs); } else { vertexDic[mesh.vertices[i]].Add(i); } } // 平均化每个顶点 foreach (var item in vertexDic) { float jd = count++ / (float)sum; EditorUtility.DisplayProgressBar("smooth", count.ToString(), jd); Vector3 smoothedNormal = new Vector3(0, 0, 0); foreach (var index in item.Value) { smoothedNormal += mesh.normals[index]; } smoothedNormal.Normalize(); foreach (var index in item.Value) { smoothedNormals[index] = smoothedNormal; } } // 新建一个颜色数组把光滑处理后的法线值存入其中 Color[] meshColors = new Color[smoothedNormals.Length]; for (int i = 0; i < smoothedNormals.Length; i++) { float jd = count++ / (float)sum; EditorUtility.DisplayProgressBar("smooth", count.ToString(), jd); // 构建模型空间→切线空间的转换矩阵 Vector3[] OtoTMatrix = new Vector3[3]; OtoTMatrix[0] = new Vector3(mesh.tangents[i].x, mesh.tangents[i].y, mesh.tangents[i].z); OtoTMatrix[1] = Vector3.Cross(mesh.normals[i], OtoTMatrix[0]) * mesh.tangents[i].w; OtoTMatrix[2] = mesh.normals[i]; // 将meshNormals数组中的法线值一一与矩阵相乘,求得切线空间下的法线值 Vector3 tNormal; tNormal = Vector3.zero; tNormal.x = Vector3.Dot(OtoTMatrix[0], smoothedNormals[i]); tNormal.y = Vector3.Dot(OtoTMatrix[1], smoothedNormals[i]); tNormal.z = Vector3.Dot(OtoTMatrix[2], smoothedNormals[i]); smoothedNormals[i] = tNormal; meshColors[i].r = smoothedNormals[i].x * 0.5f + 0.5f; meshColors[i].g = smoothedNormals[i].y * 0.5f + 0.5f; meshColors[i].b = smoothedNormals[i].z * 0.5f + 0.5f; if (mesh.colors.Length != 0) { meshColors[i].a = mesh.colors[i].a; } } //新建一个mesh,将之前mesh的所有信息copy过去 Mesh newMesh = Object.Instantiate(mesh) as Mesh; //将新模型的颜色赋值为计算好的颜色 newMesh.colors = meshColors; //newMesh.colors32 = mesh.colors32; //将新mesh保存为.asset文件,路径可以是"Assets/Character/Shader/VertexColorTest/TestMesh2.asset" AssetDatabase.CreateAsset(newMesh, NewMeshPath); AssetDatabase.SaveAssets(); Debug.Log("Done"); EditorUtility.ClearProgressBar(); }
/// <summary> /// Construct a plane from 3 coplanar points. /// </summary> /// <param name="point0">First point.</param> /// <param name="point1">Second point.</param> /// <param name="point2">Third point.</param> public Plane(Vector3 point0, Vector3 point1, Vector3 point2) { Vector3 edge1 = point1 - point0; Vector3 edge2 = point2 - point0; Normal = edge1.Cross(edge2); Normal.Normalize(); D = -Normal.Dot(point0); }
public static Vector3 GetIntersectionRayPlane(FPlane plane, FRay ray) { Vector3 result; Vector3 planeNormal = new Vector3(plane.X, plane.Y, plane.Z); float timeParam = (plane.D + (Vector3.Dot(planeNormal, ray.StartPosition))) / Vector3.Dot(planeNormal, ray.Direction); result = ray.StartPosition + ray.Direction * timeParam; return(result); }
/// <summary> /// Draw the on-screen selection, knobs, and handle all interaction logic. /// </summary> public void OnSceneGUI() { if (Selection.objects.Length > 1) { return; } NGUIEditorTools.HideMoveTool(true); if (!UIWidget.showHandles) { return; } mWidget = target as UIWidget; Transform t = mWidget.cachedTransform; Event e = Event.current; int id = GUIUtility.GetControlID(s_Hash, FocusType.Passive); EventType type = e.GetTypeForControl(id); Action actionUnderMouse = mAction; Vector3[] handles = GetHandles(mWidget.worldCorners); NGUIHandles.DrawShadowedLine(handles, handles[0], handles[1], handlesColor); NGUIHandles.DrawShadowedLine(handles, handles[1], handles[2], handlesColor); NGUIHandles.DrawShadowedLine(handles, handles[2], handles[3], handlesColor); NGUIHandles.DrawShadowedLine(handles, handles[0], handles[3], handlesColor); // If the widget is anchored, draw the anchors if (mWidget.isAnchored) { DrawAnchorHandle(mWidget.leftAnchor, mWidget.cachedTransform, handles, 0, id); DrawAnchorHandle(mWidget.topAnchor, mWidget.cachedTransform, handles, 1, id); DrawAnchorHandle(mWidget.rightAnchor, mWidget.cachedTransform, handles, 2, id); DrawAnchorHandle(mWidget.bottomAnchor, mWidget.cachedTransform, handles, 3, id); } if (type == EventType.Repaint) { bool showDetails = (mAction == UIWidgetInspector.Action.Scale) || NGUISettings.drawGuides; if (mAction == UIWidgetInspector.Action.None && e.modifiers == EventModifiers.Control) { showDetails = true; } if (NGUITools.GetActive(mWidget) && mWidget.parent == null) { showDetails = true; } if (showDetails) { NGUIHandles.DrawSize(handles, mWidget.width, mWidget.height); } } // Presence of the legacy stretch component prevents resizing bool canResize = (mWidget.GetComponent <UIStretch>() == null); bool[] resizable = new bool[8]; resizable[4] = canResize; // left resizable[5] = canResize; // top resizable[6] = canResize; // right resizable[7] = canResize; // bottom UILabel lbl = mWidget as UILabel; if (lbl != null) { if (lbl.overflowMethod == UILabel.Overflow.ResizeFreely) { resizable[4] = false; // left resizable[5] = false; // top resizable[6] = false; // right resizable[7] = false; // bottom } else if (lbl.overflowMethod == UILabel.Overflow.ResizeHeight) { resizable[5] = false; // top resizable[7] = false; // bottom } } if (mWidget.keepAspectRatio == UIWidget.AspectRatioSource.BasedOnHeight) { resizable[4] = false; resizable[6] = false; } else if (mWidget.keepAspectRatio == UIWidget.AspectRatioSource.BasedOnWidth) { resizable[5] = false; resizable[7] = false; } resizable[0] = resizable[7] && resizable[4]; // bottom-left resizable[1] = resizable[5] && resizable[4]; // top-left resizable[2] = resizable[5] && resizable[6]; // top-right resizable[3] = resizable[7] && resizable[6]; // bottom-right UIWidget.Pivot pivotUnderMouse = GetPivotUnderMouse(handles, e, resizable, true, ref actionUnderMouse); switch (type) { case EventType.Repaint: { Vector3 v0 = HandleUtility.WorldToGUIPoint(handles[0]); Vector3 v2 = HandleUtility.WorldToGUIPoint(handles[2]); if ((v2 - v0).magnitude > 60f) { Vector3 v1 = HandleUtility.WorldToGUIPoint(handles[1]); Vector3 v3 = HandleUtility.WorldToGUIPoint(handles[3]); Handles.BeginGUI(); { for (int i = 0; i < 4; ++i) { DrawKnob(handles[i], mWidget.pivot == pivotPoints[i], resizable[i], id); } if ((v1 - v0).magnitude > 80f) { if (mWidget.leftAnchor.target == null || mWidget.leftAnchor.absolute != 0) { DrawKnob(handles[4], mWidget.pivot == pivotPoints[4], resizable[4], id); } if (mWidget.rightAnchor.target == null || mWidget.rightAnchor.absolute != 0) { DrawKnob(handles[6], mWidget.pivot == pivotPoints[6], resizable[6], id); } } if ((v3 - v0).magnitude > 80f) { if (mWidget.topAnchor.target == null || mWidget.topAnchor.absolute != 0) { DrawKnob(handles[5], mWidget.pivot == pivotPoints[5], resizable[5], id); } if (mWidget.bottomAnchor.target == null || mWidget.bottomAnchor.absolute != 0) { DrawKnob(handles[7], mWidget.pivot == pivotPoints[7], resizable[7], id); } } } Handles.EndGUI(); } } break; case EventType.MouseDown: { if (actionUnderMouse != Action.None) { mStartMouse = e.mousePosition; mAllowSelection = true; if (e.button == 1) { if (e.modifiers == 0) { GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } else if (e.button == 0 && actionUnderMouse != Action.None && Raycast(handles, out mStartDrag)) { mWorldPos = t.position; mLocalPos = t.localPosition; mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; mStartWidth = mWidget.width; mStartHeight = mWidget.height; mStartLeft.x = mWidget.leftAnchor.relative; mStartLeft.y = mWidget.leftAnchor.absolute; mStartRight.x = mWidget.rightAnchor.relative; mStartRight.y = mWidget.rightAnchor.absolute; mStartBottom.x = mWidget.bottomAnchor.relative; mStartBottom.y = mWidget.bottomAnchor.absolute; mStartTop.x = mWidget.topAnchor.relative; mStartTop.y = mWidget.topAnchor.absolute; mDragPivot = pivotUnderMouse; mActionUnderMouse = actionUnderMouse; GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } } break; case EventType.MouseDrag: { // Prevent selection once the drag operation begins bool dragStarted = (e.mousePosition - mStartMouse).magnitude > 3f; if (dragStarted) { mAllowSelection = false; } if (GUIUtility.hotControl == id) { e.Use(); if (mAction != Action.None || mActionUnderMouse != Action.None) { Vector3 pos; if (Raycast(handles, out pos)) { if (mAction == Action.None && mActionUnderMouse != Action.None) { // Wait until the mouse moves by more than a few pixels if (dragStarted) { if (mActionUnderMouse == Action.Move) { NGUISnap.Recalculate(mWidget); } else if (mActionUnderMouse == Action.Rotate) { mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; } else if (mActionUnderMouse == Action.Scale) { mStartWidth = mWidget.width; mStartHeight = mWidget.height; mDragPivot = pivotUnderMouse; } mAction = actionUnderMouse; } } if (mAction != Action.None) { NGUIEditorTools.RegisterUndo("Change Rect", t); NGUIEditorTools.RegisterUndo("Change Rect", mWidget); // Reset the widget before adjusting anything t.position = mWorldPos; mWidget.width = mStartWidth; mWidget.height = mStartHeight; mWidget.leftAnchor.Set(mStartLeft.x, mStartLeft.y); mWidget.rightAnchor.Set(mStartRight.x, mStartRight.y); mWidget.bottomAnchor.Set(mStartBottom.x, mStartBottom.y); mWidget.topAnchor.Set(mStartTop.x, mStartTop.y); if (mAction == Action.Move) { // Move the widget t.position = mWorldPos + (pos - mStartDrag); Vector3 after = t.localPosition; bool snapped = false; Transform parent = t.parent; if (parent != null) { UIGrid grid = parent.GetComponent <UIGrid>(); if (grid != null && grid.arrangement == UIGrid.Arrangement.CellSnap) { snapped = true; if (grid.cellWidth > 0) { after.x = Mathf.Round(after.x / grid.cellWidth) * grid.cellWidth; } if (grid.cellHeight > 0) { after.y = Mathf.Round(after.y / grid.cellHeight) * grid.cellHeight; } } } if (!snapped) { // Snap the widget after = NGUISnap.Snap(after, mWidget.localCorners, e.modifiers != EventModifiers.Control); } // Calculate the final delta Vector3 localDelta = (after - mLocalPos); // Restore the position t.position = mWorldPos; // Adjust the widget by the delta NGUIMath.MoveRect(mWidget, localDelta.x, localDelta.y); } else if (mAction == Action.Rotate) { Vector3 dir = pos - t.position; float angle = Vector3.Angle(mStartDir, dir); if (angle > 0f) { float dot = Vector3.Dot(Vector3.Cross(mStartDir, dir), t.forward); if (dot < 0f) { angle = -angle; } angle = mStartRot.z + angle; angle = (NGUISnap.allow && e.modifiers != EventModifiers.Control) ? Mathf.Round(angle / 15f) * 15f : Mathf.Round(angle); t.localRotation = Quaternion.Euler(mStartRot.x, mStartRot.y, angle); } } else if (mAction == Action.Scale) { // Move the widget t.position = mWorldPos + (pos - mStartDrag); // Calculate the final delta Vector3 localDelta = (t.localPosition - mLocalPos); // Restore the position t.position = mWorldPos; // Adjust the widget's position and scale based on the delta, restricted by the pivot NGUIMath.ResizeWidget(mWidget, mDragPivot, localDelta.x, localDelta.y, 2, 2); ReEvaluateAnchorType(); } } } } } } break; case EventType.MouseUp: { if (e.button == 2) { break; } if (GUIUtility.hotControl == id) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; if (e.button < 2) { bool handled = false; if (e.button == 1) { // Right-click: Open a context menu listing all widgets underneath NGUIEditorTools.ShowSpriteSelectionMenu(e.mousePosition); handled = true; } else if (mAction == Action.None) { if (mAllowSelection) { // Left-click: Select the topmost widget NGUIEditorTools.SelectWidget(e.mousePosition); handled = true; } } else { // Finished dragging something Vector3 pos = t.localPosition; pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); pos.z = Mathf.Round(pos.z); t.localPosition = pos; handled = true; } if (handled) { e.Use(); } } // Clear the actions mActionUnderMouse = Action.None; mAction = Action.None; } else if (mAllowSelection) { List <UIWidget> widgets = NGUIEditorTools.SceneViewRaycast(e.mousePosition); if (widgets.Count > 0) { Selection.activeGameObject = widgets[0].gameObject; } } mAllowSelection = true; } break; case EventType.KeyDown: { if (e.keyCode == KeyCode.UpArrow) { NGUIEditorTools.RegisterUndo("Nudge Rect", t); NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget); NGUIMath.MoveRect(mWidget, 0f, 1f); e.Use(); } else if (e.keyCode == KeyCode.DownArrow) { NGUIEditorTools.RegisterUndo("Nudge Rect", t); NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget); NGUIMath.MoveRect(mWidget, 0f, -1f); e.Use(); } else if (e.keyCode == KeyCode.LeftArrow) { NGUIEditorTools.RegisterUndo("Nudge Rect", t); NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget); NGUIMath.MoveRect(mWidget, -1f, 0f); e.Use(); } else if (e.keyCode == KeyCode.RightArrow) { NGUIEditorTools.RegisterUndo("Nudge Rect", t); NGUIEditorTools.RegisterUndo("Nudge Rect", mWidget); NGUIMath.MoveRect(mWidget, 1f, 0f); e.Use(); } else if (e.keyCode == KeyCode.Escape) { if (GUIUtility.hotControl == id) { if (mAction != Action.None) { Undo.PerformUndo(); } GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; mActionUnderMouse = Action.None; mAction = Action.None; e.Use(); } else { Selection.activeGameObject = null; } } } break; } }
public static void half_diff_coords_to_std_coords( double _ThetaHalf, double _PhiHalf, double _ThetaDiff, double _PhiDiff, ref Vector3 _In, ref Vector3 _Out ) { double SinTheta_half = Math.Sin( _ThetaHalf ); Half.Set( Math.Cos( _PhiHalf ) * SinTheta_half, Math.Sin( _PhiHalf ) * SinTheta_half, Math.Cos( _ThetaHalf ) ); // Build the 2 vectors representing the frame in which we can use the diff angles Vector3 OrthoX; Half.Cross( ref Normal, out OrthoX ); if ( OrthoX.LengthSq() < 1e-6 ) OrthoX.Set( 1, 0, 0 ); else OrthoX.Normalize(); Vector3 OrthoY; Half.Cross( ref OrthoX, out OrthoY ); // Rotate using diff angles to retrieve incoming direction Half.Rotate( ref OrthoX, -_ThetaDiff, out Temp ); Temp.Rotate( ref Half, _PhiDiff, out _In ); // ...or by mirroring in "Half tangent space" double MirrorX = -_In.Dot( ref OrthoX ); double MirrorY = -_In.Dot( ref OrthoY ); double z = _In.Dot( ref Half ); _Out.Set( MirrorX*OrthoX.x + MirrorY*OrthoY.x + z*Half.x, MirrorX*OrthoX.y + MirrorY*OrthoY.y + z*Half.y, MirrorX*OrthoX.z + MirrorY*OrthoY.z + z*Half.z ); // if ( _In.z < -0.5 || _Out.z < -0.5 ) // throw new Exception( "RHA MAIS MERDE!" ); }
/// <summary> /// Gets the shortest arc quaternion to rotate this vector to the destination vector. /// </summary> /// <remarks> /// Don't call this if you think the dest vector can be close to the inverse /// of this vector, since then ANY axis of rotation is ok. /// </remarks> public Quaternion GetRotationTo(Vector3 destination) { // Based on Stan Melax's article in Game Programming Gems Quaternion q = new Quaternion(); Vector3 v0 = new Vector3(this.x, this.y, this.z); Vector3 v1 = destination; // normalize both vectors v0.Normalize(); v1.Normalize(); // get the cross product of the vectors Vector3 c = v0.Cross(v1); // If the cross product approaches zero, we get unstable because ANY axis will do // when v0 == -v1 float d = v0.Dot(v1); // If dot == 1, vectors are the same if (d >= 1.0f) { return Quaternion.Identity; } float s = MathUtil.Sqrt( (1+d) * 2 ); float inverse = 1 / s; q.x = c.x * inverse; q.y = c.y * inverse; q.z = c.z * inverse; q.w = s * 0.5f; return q; }
/// <summary> /// ホイールの移動量から /// ロータリーエンコーダ 回転パルス値を計算 /// </summary> public void CalcWheelPosToREPulse() { const double WheelSize = 175;//172; // ホイール直径 const double OneRotValue = 240; // 1回転分の分解能 Vector3 wheelLmov, wheelRmov; Real signL, signR; // 移動量と移動方向(+,-)を求める { Quaternion rotQt = new Quaternion(); Vector3 moveVec = new Vector3(); rotQt.RollInDegrees = wdCarAng; moveVec.y = 1.0; moveVec = rotQt.ToRotationMatrix() * moveVec; // 移動差分から、移動量を求める wheelLmov = new Vector3(wdRL.x - wdRLOld.x, wdRL.y - wdRLOld.y, wdRL.z - wdRLOld.z); wheelRmov = new Vector3(wdRR.x - wdRROld.x, wdRR.y - wdRROld.y, wdRR.z - wdRROld.z); if (moveVec.Dot(wheelLmov) > 0.0) signL = -1.0; else signL = 1.0; if (moveVec.Dot(wheelRmov) > 0.0) signR = -1.0; else signR = 1.0; } // 移動量(長さ) / ホイール1回転の長さ * 1回転のパルス数 wheelPulseL += (wheelLmov.Length / (WheelSize * Math.PI) * OneRotValue) * signL; wheelPulseR += (wheelRmov.Length / (WheelSize * Math.PI) * OneRotValue) * signR; }
Vector3 CalcViewBox(Vector3 center, Vector3 up, Vector3 forward) { /* * Debug.DrawLine (v3FrontTopLeft, v3FrontTopRight, Color.yellow); * Debug.DrawLine (v3FrontTopRight, v3FrontBottomRight, Color.yellow); * Debug.DrawLine (v3FrontBottomRight, v3FrontBottomLeft, Color.yellow); * Debug.DrawLine (v3FrontBottomLeft, v3FrontTopLeft, Color.yellow); */ /* * Debug.DrawLine (v3FrontTopLeft, v3BackTopLeft, Color.yellow); //cross member * Debug.DrawLine (v3FrontTopRight, v3BackTopRight, Color.yellow); //cross member * Debug.DrawLine (v3FrontBottomRight, v3BackBottomRight, Color.yellow); //cross member * Debug.DrawLine (v3FrontBottomLeft, v3BackBottomLeft, Color.yellow); //cross member */ /* * Debug.DrawLine (v3BackTopLeft, v3BackTopRight, Color.yellow); * Debug.DrawLine (v3BackTopRight, v3BackBottomRight, Color.yellow); * Debug.DrawLine (v3BackBottomRight, v3BackBottomLeft, Color.yellow); * Debug.DrawLine (v3BackBottomLeft, v3BackTopLeft, Color.yellow); */ var right = Quaternion.Euler(up * 90) * forward; //compute a right vecotr orthagonal to the camera and scene object facing vector //Front Top var dotXFTL = (Vector3.Dot(right, v3FrontTopLeft - center)); var dotXFTR = (Vector3.Dot(right, v3FrontTopRight - center)); var dotYFTL = (Vector3.Dot(up, v3FrontTopLeft - center)); var dotYFTR = (Vector3.Dot(up, v3FrontTopRight - center)); var dotZFTL = (Vector3.Dot(forward, v3FrontTopLeft - center)); var dotZFTR = (Vector3.Dot(forward, v3FrontTopRight - center)); //Front Bot var dotXFBL = (Vector3.Dot(right, v3FrontBottomLeft - center)); var dotXFBR = (Vector3.Dot(right, v3FrontBottomRight - center)); var dotYFBL = (Vector3.Dot(up, v3FrontBottomLeft - center)); var dotYFBR = (Vector3.Dot(up, v3FrontBottomRight - center)); var dotZFBL = (Vector3.Dot(forward, v3FrontBottomLeft - center)); var dotZFBR = (Vector3.Dot(forward, v3FrontBottomRight - center)); //Back Top var dotXBTL = (Vector3.Dot(right, v3BackTopLeft - center)); var dotXBTR = (Vector3.Dot(right, v3BackTopRight - center)); var dotYBTL = (Vector3.Dot(up, v3BackTopLeft - center)); var dotYBTR = (Vector3.Dot(up, v3BackTopRight - center)); var dotZBTL = (Vector3.Dot(forward, v3BackTopLeft - center)); var dotZBTR = (Vector3.Dot(forward, v3BackTopRight - center)); //Back Bot var dotXBBL = (Vector3.Dot(right, v3BackBottomLeft - center)); var dotXBBR = (Vector3.Dot(right, v3BackBottomRight - center)); var dotYBBL = (Vector3.Dot(up, v3BackBottomLeft - center)); var dotYBBR = (Vector3.Dot(up, v3BackBottomRight - center)); var dotZBBL = (Vector3.Dot(forward, v3BackBottomLeft - center)); var dotZBBR = (Vector3.Dot(forward, v3BackBottomRight - center)); //Find the longest vector for each axis var maxX = Mathf.Max(dotXFTL, dotXFTR, dotXFBL, dotXFBR, dotXBTL, dotXBTR, dotXBBL, dotXBBR); //Debug.DrawRay(center, right * maxX, Color.red); //draw the ray that lies on the outter most extent for this axis var maxY = Mathf.Max(dotYFTL, dotYFTR, dotYFBL, dotYFBR, dotYBTL, dotYBTR, dotYBBL, dotYBBR); //Debug.DrawRay(center, up * maxY, Color.green); //draw the ray that lies on the outter most extent for this axis var maxZ = Mathf.Max(dotZFTL, dotZFTR, dotZFBL, dotZFBR, dotZBTL, dotZBTR, dotZBBL, dotZBBR); //Debug.DrawRay(center, forward * maxZ, Color.blue); //draw the ray that lies on the outter most extent for this axis return(new Vector3(maxX, maxY, maxZ)); //the vectors local to camera which represent the visible bounds for the rotated object(s) }
public static Vector3 SetLengthOnAxis(this Vector3 v, Vector3 axis, float len) { axis.Normalize(); var d = len - Vector3.Dot(v, axis); return v + axis * d; }
static Vector3 IntersectionPoint(Vector3 vNormal, Vector3[] vLine, double distance) { Vector3 vPoint = new Vector3(); Vector3 vLineDir = new Vector3(); double Numerator = 0.0, Denominator = 0.0, dist = 0.0; vLineDir = (vLine[1] - vLine[0]); vLineDir = vLineDir.Normalized; Numerator = - (vNormal.X * vLine[0].X + vNormal.Y * vLine[0].Y + vNormal.Z * vLine[0].Z + distance); Denominator = vNormal.Dot(vLineDir); if( Denominator == 0.0) return vLine[0]; dist = Numerator / Denominator; vPoint.X = (float)(vLine[0].X + (vLineDir.X * dist)); vPoint.Y = (float)(vLine[0].Y + (vLineDir.Y * dist)); vPoint.Z = (float)(vLine[0].Z + (vLineDir.Z * dist)); return vPoint; }
void OnScrollDragging(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) { m_HierarchyUI.listView.scrollOffset -= Vector3.Dot(eventData.deltaPosition, handle.transform.forward) / this.GetViewerScale(); }
private static Point3 GetAtmosphereIntersection( Vector3 pt, Vector3 vec, float radius ) { float a0 = pt.Dot( pt ) - ( radius * radius ); float a1 = vec.Dot( pt ); float d = ( a1 * a1 ) - a0; float root = ( float )Math.Sqrt( d ); float t0 = -a1 - root; float t1 = -a1 + root; float closestT = ( t0 < t1 ) ? t0 : t1; return ( pt + vec * closestT ).ToPoint3( ); }
private static float PlaneDistance(Vector3 planeCenter, Vector3 planeNormal, Vector3 point) { return(Vector3.Dot(point - planeCenter, planeNormal)); }
/// <summary> /// 2つのベクトルがなす角をかえす /// </summary> /// <param name="vecA"></param> /// <param name="vecB"></param> /// <returns></returns> public double VecToRad(Vector3 vecA, Vector3 vecB) { vecA.Normalize(); vecB.Normalize(); double rad = vecA.Dot(vecB); if (rad > 1.0) rad = 1.0; double dir = (double)(Math.Asin(rad) - (Math.PI / 2.0)); if (double.IsNaN(dir)) { Debug.Write("NAn"); } Vector3 resVec = vecA.Cross(vecB); if (resVec.z > 0) dir = -dir; return dir; }
static float AALinePlaneIntersection(int lineAxis, Vector3 lineLoc, Face face) { lineLoc[lineAxis] = 0; return(Vector3.Dot(face.normal, face.vertices[0] - lineLoc) / face.normal[lineAxis]); }
public void Dot() { var vector1 = new Vector3(2.0f, 3.0f, 4.0f); var vector2 = new Vector3(5.0f, 6.0f, 7.0f); var result = vector1.Dot(vector2); Assert.AreEqual(2 * 5 + 3 * 6 + 4 * 7, result); }
/// <summary> /// Method to curve text along a Unity animation curve. /// </summary> /// <param name="textComponent"></param> /// <returns></returns> IEnumerator WarpText() { VertexCurve.preWrapMode = WrapMode.Clamp; VertexCurve.postWrapMode = WrapMode.Clamp; //Mesh mesh = m_TextComponent.textInfo.meshInfo[0].mesh; Vector3[] vertices; Matrix4x4 matrix; m_TextComponent.havePropertiesChanged = true; // Need to force the TextMeshPro Object to be updated. CurveScale *= 10; float old_CurveScale = CurveScale; float old_ShearValue = ShearAmount; AnimationCurve old_curve = CopyAnimationCurve(VertexCurve); while (true) { if (!m_TextComponent.havePropertiesChanged && old_CurveScale == CurveScale && old_curve.keys[1].value == VertexCurve.keys[1].value && old_ShearValue == ShearAmount) { yield return(null); continue; } old_CurveScale = CurveScale; old_curve = CopyAnimationCurve(VertexCurve); old_ShearValue = ShearAmount; m_TextComponent .ForceMeshUpdate(); // Generate the mesh and populate the textInfo with data we can use and manipulate. TMP_TextInfo textInfo = m_TextComponent.textInfo; int characterCount = textInfo.characterCount; if (characterCount == 0) { continue; } //vertices = textInfo.meshInfo[0].vertices; //int lastVertexIndex = textInfo.characterInfo[characterCount - 1].vertexIndex; float boundsMinX = m_TextComponent.bounds.min.x; //textInfo.meshInfo[0].mesh.bounds.min.x; float boundsMaxX = m_TextComponent.bounds.max.x; //textInfo.meshInfo[0].mesh.bounds.max.x; for (int i = 0; i < characterCount; i++) { if (!textInfo.characterInfo[i].isVisible) { continue; } int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the index of the mesh used by this character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; // Compute the baseline mid point for each character Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine); //float offsetY = VertexCurve.Evaluate((float)i / characterCount + loopCount / 50f); // Random.Range(-0.25f, 0.25f); // Apply offset to adjust our pivot point. vertices[vertexIndex + 0] += -offsetToMidBaseline; vertices[vertexIndex + 1] += -offsetToMidBaseline; vertices[vertexIndex + 2] += -offsetToMidBaseline; vertices[vertexIndex + 3] += -offsetToMidBaseline; // Apply the Shearing FX float shear_value = ShearAmount * 0.01f; Vector3 topShear = new Vector3( shear_value * (textInfo.characterInfo[i].topRight.y - textInfo.characterInfo[i].baseLine), 0, 0); Vector3 bottomShear = new Vector3( shear_value * (textInfo.characterInfo[i].baseLine - textInfo.characterInfo[i].bottomRight.y), 0, 0); vertices[vertexIndex + 0] += -bottomShear; vertices[vertexIndex + 1] += topShear; vertices[vertexIndex + 2] += topShear; vertices[vertexIndex + 3] += -bottomShear; // Compute the angle of rotation for each character based on the animation curve float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh. float x1 = x0 + 0.0001f; float y0 = VertexCurve.Evaluate(x0) * CurveScale; float y1 = VertexCurve.Evaluate(x1) * CurveScale; Vector3 horizontal = new Vector3(1, 0, 0); //Vector3 normal = new Vector3(-(y1 - y0), (x1 * (boundsMaxX - boundsMinX) + boundsMinX) - offsetToMidBaseline.x, 0); Vector3 tangent = new Vector3(x1 * (boundsMaxX - boundsMinX) + boundsMinX, y1) - new Vector3(offsetToMidBaseline.x, y0); float dot = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * 57.2957795f; Vector3 cross = Vector3.Cross(horizontal, tangent); float angle = cross.z > 0 ? dot : 360 - dot; matrix = Matrix4x4.TRS(new Vector3(0, y0, 0), Quaternion.Euler(0, 0, angle), Vector3.one); vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]); vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]); vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]); vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]); vertices[vertexIndex + 0] += offsetToMidBaseline; vertices[vertexIndex + 1] += offsetToMidBaseline; vertices[vertexIndex + 2] += offsetToMidBaseline; vertices[vertexIndex + 3] += offsetToMidBaseline; } // Upload the mesh with the revised information m_TextComponent.UpdateVertexData(); yield return(null); // new WaitForSeconds(0.025f); } }
public void Update() { _UpdateApplicationLifecycle(); // Hide snackbar when currently tracking at least one plane. Session.GetTrackables <DetectedPlane>(m_AllPlanes); bool showSearchingUI = true; for (int i = 0; i < m_AllPlanes.Count; i++) { if (m_AllPlanes[i].TrackingState == TrackingState.Tracking) { showSearchingUI = false; break; } } SearchingForPlaneUI.SetActive(showSearchingUI); // If the player has not touched the screen, we are done with this update. Touch touch; if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began) { return; } // Raycast against the location the player touched to search for planes. TrackableHit hit; TrackableHitFlags raycastFilter = TrackableHitFlags.PlaneWithinPolygon | TrackableHitFlags.FeaturePointWithSurfaceNormal; if (Frame.Raycast(touch.position.x, touch.position.y, raycastFilter, out hit) && spawned == false) { spawned = true; // Use hit pose and camera pose to check if hittest is from the // back of the plane, if it is, no need to create the anchor. if ((hit.Trackable is DetectedPlane) && Vector3.Dot(FirstPersonCamera.transform.position - hit.Pose.position, hit.Pose.rotation * Vector3.up) < 0) { Debug.Log("Hit at back of the current DetectedPlane"); } else { // Instantiate Andy model at the hit pose. var andyObject = Instantiate(AndyAndroidPrefab, hit.Pose.position, hit.Pose.rotation); // Compensate for the hitPose rotation facing away from the raycast (i.e. camera). andyObject.transform.Rotate(0, k_ModelRotation, 0, Space.Self); // Create an anchor to allow ARCore to track the hitpoint as understanding of the physical // world evolves. var anchor = hit.Trackable.CreateAnchor(hit.Pose); dragonControls.Dragon = andyObject.transform; dragonControls.Dragon.localEulerAngles = new Vector3(0, 360, 0); dragonControls.gameObject.SetActive(true); // Make Andy model a child of the anchor. andyObject.transform.parent = anchor.transform; } } }
public bool WithinVisionCone(BaseEntity other) { return((double)Vector3.Dot(this.eyes.BodyForward(), Vector3Ex.Direction(((Component)other).get_transform().get_position(), ((Component)this).get_transform().get_position())) >= (double)this.visionCone); }
private bool GetRayAtmosphereIntersection( Point3 origin, Vector3 dir, out Point3 intPt ) { intPt = origin; float factor = 0.0001f; float fRadius = m_OuterSphere.Radius * factor; float fSqrRadius = fRadius * fRadius; Vector3 originToCentre = new Vector3( origin.X * factor, origin.Y * factor, origin.Z * factor ); float a0 = originToCentre.SqrLength - fSqrRadius; if ( a0 > 0 ) { return false; } // 1 intersection: The origin of the ray is inside the sphere float a1 = dir.Dot( originToCentre ); float discriminant = ( a1 * a1 ) - a0; float t = -a1 + Functions.Sqrt( discriminant ); intPt = origin + dir * ( t / factor ); return true; }
// compact triangles, compute edge error and build reference list void Update_mesh(int iteration) { if (iteration > 0) // compact triangles { int dst = 0; for (int i = 0; i < triangles.Count; i++) { if (triangles[i].deleted == 0) { triangles[dst++] = triangles[i]; } } } // // Init Quadrics by Plane & Edge Errors // // required at the beginning ( iteration == 0 ) // recomputing during the simplification is not required, // but mostly improves the result for closed meshes // if (iteration == 0) { for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; v.q = new SymetricMatrix(0.0); vertices[i] = v; } for (int i = 0; i < triangles.Count; i++) { Triangle t = triangles[i]; Vector3 n = new Vector3(); Vector3[] p = new Vector3[3]; for (int j = 0; j < 3; j++) { p[j] = vertices[t.v[j]].p; } n = Vector3.Cross(p[1] - p[0], p[2] - p[0]); n.Normalize(); t.n = n; for (int j = 0; j < 3; j++) { Vertex v = vertices[t.v[j]]; v.q = vertices[t.v[j]].q + new SymetricMatrix(n.X, n.Y, n.Z, -Vector3.Dot(n, p[0])); vertices[t.v[j]] = v; } triangles[i] = t; } for (int i = 0; i < triangles.Count; i++) { // Calc Edge Error Triangle t = triangles[i]; Vector3 p = new Vector3(); for (int j = 0; j < 3; j++) { t.err[j] = Calculate_error(t.v[j], t.v[(j + 1) % 3], ref p); } t.err[3] = Math.Min(t.err[0], Math.Min(t.err[1], t.err[2])); triangles[i] = t; } } // Init Reference ID list for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; v.tstart = 0; v.tcount = 0; vertices[i] = v; } for (int i = 0; i < triangles.Count; i++) { Triangle t = triangles[i]; for (int j = 0; j < 3; i++) { Vertex v = vertices[t.v[j]]; v.tcount++; vertices[t.v[j]] = v; } } int tstart = 0; for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; v.tstart = tstart; tstart += v.tcount; v.tcount = 0; vertices[i] = v; } // Write References for (int i = 0; i < triangles.Count; i++) { Triangle t = triangles[i]; for (int j = 0; j < 3; j++) { Vertex v = vertices[t.v[j]]; Ref r = refs[v.tstart + v.tcount]; r.tid = i; r.tvertex = j; refs[v.tstart + v.tcount] = r; v.tcount++; vertices[t.v[j]] = v; } triangles[i] = t; } // Identify boundary : vertices[].border=0,1 if (iteration == 0) { ListHelper <int> vcount = new ListHelper <int>(); ListHelper <int> vids = new ListHelper <int>(); for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; v.border = 0; vertices[i] = v; } for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; vcount.Clear(); vids.Clear(); for (int j = 0; j < v.tcount; j++) { int kb = refs[v.tstart + j].tid; Triangle t = triangles[kb]; for (int k = 0; k < 3; k++) { int ofs = 0, id = t.v[k]; while (ofs < vcount.Count) { if (vids[ofs] == id) { break; } ofs++; } if (ofs == vcount.Count) { vcount.Add(1); vids.Add(id); } else { vcount[ofs]++; } } triangles[kb] = t; } for (int j = 0; j < vcount.Count; j++) { if (vcount[j] == 1) { Vertex vt = vertices[vids[j]]; vt.border = 1; vertices[vids[j]] = vt; } } } } }
public static void InersectPlane(ref Vector3 vector, ref Vector3 planeNormal, out Vector3 result) { result = vector - (planeNormal * vector.Dot(planeNormal)); }
void Update() { if (Time.time < delay) { return; } // if target is exist. if (target) { // rotation facing to the target. Quaternion targetlook = Quaternion.LookRotation(target.transform.position - this.transform.position); this.transform.rotation = Quaternion.Lerp(this.transform.rotation, targetlook, Time.deltaTime * 3); // find a direction from the target Vector3 dir = (target.transform.position - transform.position).normalized; float direction = Vector3.Dot(dir, transform.forward); // check if in front direction if (direction > 0.9f) { if (weapon) { // shooting!!. weapon.LaunchWeapon(indexWeapon); } } // AI attack the target for a while (3 sec) if (Time.time > timeAIattack + 3) { target = null; // AI forget this target and try to looking new target } } else { for (int t = 0; t < TargetTag.Length; t++) { // AI find target only in TargetTag list if (GameObject.FindGameObjectsWithTag(TargetTag[t]).Length > 0) { // find all objects in Tags list. GameObject[] objs = GameObject.FindGameObjectsWithTag(TargetTag[t]); float distance = int.MaxValue; for (int i = 0; i < objs.Length; i++) { // find the distance from the target. float dis = Vector3.Distance(objs[i].transform.position, transform.position); // check if in ranged. if (distance > dis) { // Select closer target distance = dis; target = objs[i]; if (weapon) { // random weapons indexWeapon = Random.Range(0, weapon.WeaponLists.Length); } timeAIattack = Time.time; } } } } } }
public void Calculate_dot_product() { var firstOperand = new Vector3(1, 5, 6); var secondOperand = new Vector3(4, 9, 1); var actual = firstOperand.Dot(secondOperand); Assert.AreEqual(actual, 55); }
public void WidenRectByVector( Vector3 vec, Rectangle inRect, Real minHeight, Real maxHeight, ref Rectangle outRect ) { outRect = inRect; var p = new Plane(); switch ( Alignment ) { case Alignment.Align_X_Y: p.Redefine( Vector3.UnitZ, new Vector3( 0, 0, vec.z < 0.0f ? minHeight : maxHeight ) ); break; case Alignment.Align_X_Z: p.Redefine( Vector3.UnitY, new Vector3( 0, vec.y < 0.0f ? minHeight : maxHeight, 0 ) ); break; case Alignment.Align_Y_Z: p.Redefine( Vector3.UnitX, new Vector3( vec.x < 0.0f ? minHeight : maxHeight, 0, 0 ) ); break; } var verticalVal = vec.Dot( p.Normal ); if ( Utility.RealEqual( verticalVal, 0.0f ) ) { return; } var corners = new Vector3[4]; var startHeight = verticalVal < 0.0f ? maxHeight : minHeight; GetPoint( inRect.Left, inRect.Top, startHeight, ref corners[ 0 ] ); GetPoint( inRect.Right - 1, inRect.Top, startHeight, ref corners[ 1 ] ); GetPoint( inRect.Left, inRect.Bottom - 1, startHeight, ref corners[ 2 ] ); GetPoint( inRect.Right - 1, inRect.Bottom - 1, startHeight, ref corners[ 3 ] ); for ( int i = 0; i < 4; ++i ) { var ray = new Ray( corners[ i ] + this.mPos, vec ); var rayHit = ray.Intersects( p ); if ( rayHit.Hit ) { var pt = ray.GetPoint( rayHit.Distance ); // convert back to terrain point var terrainHitPos = Vector3.Zero; GetTerrainPosition( pt, ref terrainHitPos ); // build rectangle which has rounded down & rounded up values // remember right & bottom are exclusive var mergeRect = new Rectangle( (long)terrainHitPos.x*( this.mSize - 1 ), (long)terrainHitPos.y*( this.mSize - 1 ), (long)( terrainHitPos.x*(float)( this.mSize - 1 ) + 0.5f ) + 1, (long)( terrainHitPos.y*(float)( this.mSize - 1 ) + 0.5f ) + 1 ); outRect.Merge( mergeRect ); } } }
private void UpdateFunction() { // We copy the actual velocity into a temporary variable that we can manipulate. Vector3 velocity = movement.velocity; // Update velocity based on input velocity = ApplyInputVelocityChange(velocity); // Apply gravity and jumping force velocity = ApplyGravityAndJumping(velocity); // Moving platform support Vector3 moveDistance = Vector3.zero; if (MoveWithPlatform()) { Vector3 newGlobalPoint = movingPlatform.activePlatform.TransformPoint(movingPlatform.activeLocalPoint); moveDistance = (newGlobalPoint - movingPlatform.activeGlobalPoint); if (moveDistance != Vector3.zero) { controller.Move(moveDistance); } // Support moving platform rotation as well: Quaternion newGlobalRotation = movingPlatform.activePlatform.rotation * movingPlatform.activeLocalRotation; Quaternion rotationDiff = newGlobalRotation * Quaternion.Inverse(movingPlatform.activeGlobalRotation); float yRotation = rotationDiff.eulerAngles.y; if (yRotation != 0) { // Prevent rotation of the local up vector tr.Rotate(0, yRotation, 0); } } // Save lastPosition for velocity calculation. Vector3 lastPosition = tr.position; // We always want the movement to be framerate independent. Multiplying by Time.deltaTime does this. Vector3 currentMovementOffset = velocity * Time.deltaTime; // Find out how much we need to push towards the ground to avoid loosing grouning // when walking down a step or over a sharp change in slope. float pushDownOffset = Mathf.Max(controller.stepOffset, new Vector3(currentMovementOffset.x, 0, currentMovementOffset.z).magnitude); if (grounded) { currentMovementOffset -= pushDownOffset * Vector3.up; } // Reset variables that will be set by collision function movingPlatform.hitPlatform = null; groundNormal = Vector3.zero; // Move our character! movement.collisionFlags = controller.Move(currentMovementOffset); movement.lastHitPoint = movement.hitPoint; lastGroundNormal = groundNormal; if (movingPlatform.enabled && movingPlatform.activePlatform != movingPlatform.hitPlatform) { if (movingPlatform.hitPlatform != null) { movingPlatform.activePlatform = movingPlatform.hitPlatform; movingPlatform.lastMatrix = movingPlatform.hitPlatform.localToWorldMatrix; movingPlatform.newPlatform = true; } } // Calculate the velocity based on the current and previous position. // This means our velocity will only be the amount the character actually moved as a result of collisions. Vector3 oldHVelocity = new Vector3(velocity.x, 0, velocity.z); movement.velocity = (tr.position - lastPosition) / Time.deltaTime; Vector3 newHVelocity = new Vector3(movement.velocity.x, 0, movement.velocity.z); // The CharacterController can be moved in unwanted directions when colliding with things. // We want to prevent this from influencing the recorded velocity. if (oldHVelocity == Vector3.zero) { movement.velocity = new Vector3(0, movement.velocity.y, 0); } else { float projectedNewVelocity = Vector3.Dot(newHVelocity, oldHVelocity) / oldHVelocity.sqrMagnitude; movement.velocity = oldHVelocity * Mathf.Clamp01(projectedNewVelocity) + movement.velocity.y * Vector3.up; } if (movement.velocity.y < velocity.y - 0.001f) { if (movement.velocity.y < 0) { // Something is forcing the CharacterController down faster than it should. // Ignore this movement.velocity.y = velocity.y; } else { // The upwards movement of the CharacterController has been blocked. // This is treated like a ceiling collision - stop further jumping here. jumping.holdingJumpButton = false; } } // We were grounded but just loosed grounding if (grounded && !IsGroundedTest()) { grounded = false; // Apply inertia from platform if (movingPlatform.enabled && (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer || movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer)) { movement.frameVelocity = movingPlatform.platformVelocity; movement.velocity += movingPlatform.platformVelocity; } SendMessage("OnFall", SendMessageOptions.DontRequireReceiver); // We pushed the character down to ensure it would stay on the ground if there was any. // But there wasn't so now we cancel the downwards offset to make the fall smoother. tr.position += pushDownOffset * Vector3.up; } // We were not grounded but just landed on something else if (!grounded && IsGroundedTest()) { grounded = true; jumping.jumping = false; SubtractNewPlatformVelocity(); SendMessage("OnLand", SendMessageOptions.DontRequireReceiver); } // Moving platforms support if (MoveWithPlatform()) { // Use the center of the lower half sphere of the capsule as reference point. // This works best when the character is standing on moving tilting platforms. movingPlatform.activeGlobalPoint = tr.position + Vector3.up * (controller.center.y - controller.height * 0.5f + controller.radius); movingPlatform.activeLocalPoint = movingPlatform.activePlatform.InverseTransformPoint(movingPlatform.activeGlobalPoint); // Support moving platform rotation as well: movingPlatform.activeGlobalRotation = tr.rotation; movingPlatform.activeLocalRotation = Quaternion.Inverse(movingPlatform.activePlatform.rotation) * movingPlatform.activeGlobalRotation; } }
public Plane(Vector3 normal, Vector3 point) { this.Normal = normal; this.D = -normal.Dot(point); }
public override bool scatter(Ray rayIn, HitRecord record, ref Color attenuation, ref Ray scattered) { Vector3 outNormal; // reflect 中实际上是点乘 因此第一个参数是否归一化理论不影响 Vector3 reflected = _M.reflect(rayIn.normalDirection, record.normal); //透明的物体当然不会吸收任何光线 attenuation = Color.white; float ni_no = 1f; Vector3 refracted = Vector3.zero; float cos = 0; //反射比 float reflect_prob = 0; //回忆一下二次公式 最常见的情况 一个光束 和 球 有两个交点 //假如光线是从介质内向介质外传播,那么法线就要反转一下 // 点积 a.b < 0 则 ab 是钝角(基本不同方向) // 注意一下 record的法线都是外表面的法线 // 当光线和外表面法线几乎同方向的时候 // 表示从光线正从球内射出 if (Vector3.Dot(rayIn.direction, record.normal) > 0) { // 那么法线就要反转一下 outNormal = -record.normal; ni_no = ref_idx;//相对空气折射率 // 斯涅尔定律 // n1*sinθ1 = n2*sinθ2 // θ1是入射角 θ2是折射角 // n1 n2 分别是折射率 cos = ni_no * Vector3.Dot(rayIn.normalDirection, record.normal); } else { outNormal = record.normal; ni_no = 1f / ref_idx; cos = -Vector3.Dot(rayIn.normalDirection, record.normal); } //如果没发生折射,就用反射 if (_M.refract(rayIn.direction, outNormal, ni_no, ref refracted)) { reflect_prob = _M.schlick(cos, ref_idx); } else { //此时反射比为100% // reflect_prob = 1; reflect_prob = _M.schlick(cos, ref_idx); } //因为一条光线只会采样一个点,所以这里就用蒙特卡洛模拟的方法,用概率去决定数值 if (_M.R() <= reflect_prob) { scattered = new Ray(record.p, reflected); } else { scattered = new Ray(record.p, refracted); } return(true); }
public static float ProjectVectorOnUnnormalizedVector(Vector3 projectedV, Vector3 projectOnV) { return(Vector3.Dot(projectedV, projectOnV) / projectOnV.Length); }