/** * Cast a ray (in model space) against a mesh. */ public static bool MeshRaycast(Ray InRay, Vector3[] vertices, int[] triangles, out z_RaycastHit hit, float distance = Mathf.Infinity, Culling cullingMode = Culling.Front) { // float dot; // vars used in loop float hitDistance = Mathf.Infinity; Vector3 hitNormal = new Vector3(0f, 0f, 0f); // vars used in loop Vector3 a, b, c; int hitFace = -1; Vector3 o = InRay.origin, d = InRay.direction; /** * Iterate faces, testing for nearest hit to ray origin. */ for (int CurTri = 0; CurTri < triangles.Length; CurTri += 3) { a = vertices[triangles[CurTri + 0]]; b = vertices[triangles[CurTri + 1]]; c = vertices[triangles[CurTri + 2]]; if (z_Math.RayIntersectsTriangle2(o, d, a, b, c, ref distance, ref hitNormal)) { hitFace = CurTri / 3; hitDistance = distance; break; } } hit = new z_RaycastHit(hitDistance, InRay.GetPoint(hitDistance), hitNormal, hitFace); return(hitFace > -1); }
private void PlaceGameObject(z_RaycastHit hit, GameObject prefab, z_BrushTarget target, z_BrushSettings settings) { if (prefab == null) { return; } Ray ray = RandomRay(hit.position, hit.normal, settings.radius, settings.falloff, settings.falloffCurve); z_RaycastHit rand_hit; Vector3[] vertices = target.editableObject.editMesh.vertices; int[] triangles = target.editableObject.editMesh.GetTriangles(); if (z_SceneUtility.MeshRaycast(ray, vertices, triangles, out rand_hit)) { float pivotOffset = placeWithPivot ? 0f : GetPivotOffset(prefab); Quaternion rotation = Quaternion.FromToRotation(Vector3.up, target.transform.TransformDirection(rand_hit.normal)); Quaternion random = Quaternion.AngleAxis(Random.Range(0f, 360f), Vector3.up); #pragma warning disable 0618 GameObject inst = PrefabUtility.ConnectGameObjectToPrefab(Instantiate(prefab), prefab); #pragma warning restore 0618 inst.transform.localPosition = target.transform.TransformPoint(rand_hit.position); inst.transform.localRotation = rotation * random; inst.name = FormatInstanceName(prefab); inst.transform.position = inst.transform.position + inst.transform.up * pivotOffset; if (avoidOverlappingGameObjects && TestIntersection(inst)) { Object.DestroyImmediate(inst); return; } if (hitSurfaceIsParent) { inst.transform.SetParent(target.transform); } PrefabUtility.RecordPrefabInstancePropertyModifications(inst); instances.Add(inst); Undo.RegisterCreatedObjectUndo(inst, UndoMessage); } }
private void RemoveGameObjects(z_RaycastHit hit, z_BrushTarget target, z_BrushSettings settings) { Vector3 worldHitPosition = target.editableObject.transform.TransformPoint(hit.position); int count = instances.Count; for (int i = 0; i < count; i++) { if (instances[i] != null && Vector3.Distance(worldHitPosition, instances[i].transform.position) < settings.radius) { GameObject go = instances[i]; instances.RemoveAt(i); count--; Undo.DestroyObjectImmediate(go); } } }
/** * Find the nearest triangle intersected by InWorldRay on this mesh. InWorldRay is in world space. * @hit contains information about the hit point. @distance limits how far from @InWorldRay.origin the hit * point may be. @cullingMode determines what face orientations are tested (Culling.Front only tests front * faces, Culling.Back only tests back faces, and Culling.FrontBack tests both). * Ray origin and position values are in local space. */ public static bool WorldRaycast(Ray InWorldRay, Transform transform, Vector3[] vertices, int[] triangles, out z_RaycastHit hit, float distance = Mathf.Infinity, Culling cullingMode = Culling.Front) { Ray ray = transform.InverseTransformRay(InWorldRay); //commented out code was ommited here }
public override void OnBrushApply(z_BrushTarget target, z_BrushSettings settings) { int rayCount = target.raycastHits.Count; if (rayCount < 1) { return; } Vector3 n = direction.ToVector3(); float scale = 1f / (Vector3.Scale(target.transform.lossyScale, n).magnitude); float sign = Event.current.shift ? -1f : 1f; float maxMoveDistance = settings.strength * STRENGTH_MODIFIER * sign * brushStrength; int vertexCount = target.editableObject.vertexCount; z_Mesh mesh = target.editableObject.editMesh; for (int ri = 0; ri < rayCount; ri++) { z_RaycastHit hit = target.raycastHits[ri]; if (hit.weights == null || hit.weights.Length < vertexCount) { continue; } if (direction == z_Direction.BrushNormal) { if (brushNormalIsSticky) { n = brushNormalOnBeginApply[ri]; } else { n = target.raycastHits[ri].normal; } scale = 1f / (Vector3.Scale(target.transform.lossyScale, n).magnitude); } for (int i = 0; i < commonVertexCount; i++) { int index = commonVertices[i][0]; if (hit.weights[index] < .0001f || (ignoreNonManifoldIndices && nonManifoldIndices.Contains(index))) { continue; } if (direction == z_Direction.VertexNormal) { n = normalLookup[index]; scale = 1f / (Vector3.Scale(target.transform.lossyScale, n).magnitude); } Vector3 pos = vertices[index] + n * (hit.weights[index] * maxMoveDistance * scale); List <int> indices = commonVertices[i]; for (int it = 0; it < indices.Count; it++) { vertices[indices[it]] = pos; } } } mesh.vertices = vertices; // different than setting weights on temp component, // which is what z_BrushModeMesh.OnBrushApply does. if (tempComponent != null) { tempComponent.OnVerticesMoved(mesh); } base.OnBrushApply(target, settings); }
/** * Find the nearest triangle intersected by InWorldRay on this mesh. InWorldRay is in world space. * @hit contains information about the hit point. @distance limits how far from @InWorldRay.origin the hit * point may be. @cullingMode determines what face orientations are tested (Culling.Front only tests front * faces, Culling.Back only tests back faces, and Culling.FrontBack tests both). * Ray origin and position values are in local space. */ public static bool WorldRaycast(Ray InWorldRay, Transform transform, Vector3[] vertices, int[] triangles, out z_RaycastHit hit, float distance = Mathf.Infinity, Culling cullingMode = Culling.Front) { Ray ray = transform.InverseTransformRay(InWorldRay); return(MeshRaycast(ray, vertices, triangles, out hit, distance, cullingMode)); }
/** * Cast a ray (in model space) against a mesh. */ public static bool MeshRaycast(Ray InRay, MeshFilter meshFilter, out z_RaycastHit hit, float distance, Culling cullingMode) { Mesh mesh = meshFilter.sharedMesh; float dist = 0f; Vector3 point = Vector3.zero; float OutHitPoint = Mathf.Infinity; float dot; // vars used in loop Vector3 nrm; // vars used in loop int OutHitFace = -1; Vector3 OutNrm = Vector3.zero; /** * Iterate faces, testing for nearest hit to ray origin. Optionally ignores backfaces. */ Vector3[] vertices = mesh.vertices; int[] triangles = mesh.triangles; for(int CurTri = 0; CurTri < triangles.Length; CurTri += 3) { Vector3 a = vertices[triangles[CurTri+0]]; Vector3 b = vertices[triangles[CurTri+1]]; Vector3 c = vertices[triangles[CurTri+2]]; nrm = Vector3.Cross(b-a, c-a); dot = Vector3.Dot(InRay.direction, nrm); bool ignore = false; switch(cullingMode) { case Culling.Front: if(dot > 0f) ignore = true; break; case Culling.Back: if(dot < 0f) ignore = true; break; } if(!ignore && z_Math.RayIntersectsTriangle(InRay, a, b, c, out dist, out point)) { if(dist > OutHitPoint || dist > distance) continue; OutNrm = nrm; OutHitFace = CurTri / 3; OutHitPoint = dist; continue; } } hit = new z_RaycastHit( OutHitPoint, InRay.GetPoint(OutHitPoint), OutNrm, OutHitFace); return OutHitFace > -1; }
/** * Find the nearest triangle intersected by InWorldRay on this mesh. InWorldRay is in world space. * @hit contains information about the hit point. @distance limits how far from @InWorldRay.origin the hit * point may be. @cullingMode determines what face orientations are tested (Culling.Front only tests front * faces, Culling.Back only tests back faces, and Culling.FrontBack tests both). * Ray origin and position values are in local space. */ public static bool WorldRaycast(Ray InWorldRay, MeshFilter meshFilter, out z_RaycastHit hit, float distance, Culling cullingMode) { Ray ray = meshFilter.transform.InverseTransformRay(InWorldRay); return MeshRaycast(ray, meshFilter, out hit, distance, cullingMode); }
/** * Find a triangle intersected by InRay on InMesh. InRay is in world space. * Returns the index in mesh.faces of the hit face, or -1. Optionally can ignore * backfaces. */ public static bool WorldRaycast(Ray InWorldRay, MeshFilter meshFilter, out z_RaycastHit hit) { return WorldRaycast(InWorldRay, meshFilter, out hit, Mathf.Infinity, Culling.Front); }
private void PlaceGameObject(z_RaycastHit hit, GameObject prefab, z_BrushTarget target, z_BrushSettings settings) { if(prefab == null) return; Ray ray = RandomRay(hit.position, hit.normal, settings.radius, settings.falloff, settings.falloffCurve); Debug.DrawRay( target.transform.TransformPoint(ray.origin), target.transform.TransformDirection(ray.direction), Color.red); z_RaycastHit rand_hit; if( z_SceneUtility.MeshRaycast(ray, target.editableObject.meshFilter, out rand_hit) ) { float pivotOffset = placeWithPivot ? 0f : GetPivotOffset(prefab); Quaternion rotation = Quaternion.FromToRotation(Vector3.up, target.transform.TransformDirection(rand_hit.normal)); Quaternion random = Quaternion.AngleAxis(Random.Range(0f, 360f), Vector3.up); GameObject inst = (GameObject) GameObject.Instantiate( prefab, target.transform.TransformPoint(rand_hit.position), rotation * random); inst.transform.position = inst.transform.position + inst.transform.up * pivotOffset; if(hitTransformIsParent) inst.transform.SetParent(target.transform); Undo.RegisterCreatedObjectUndo(inst, UndoMessage); } }
public override void OnBrushApply(z_BrushTarget target, z_BrushSettings settings) { int rayCount = target.raycastHits.Count; Vector3[] normals = (direction == z_Direction.BrushNormal) ? target.editableObject.editMesh.normals : null; Vector3 v, t, avg, dirVec = direction.ToVector3(); Plane plane = new Plane(Vector3.up, Vector3.zero); z_Mesh mesh = target.editableObject.editMesh; int vertexCount = mesh.vertexCount; // don't use target.GetAllWeights because brush normal needs // to know which ray to use for normal for (int ri = 0; ri < rayCount; ri++) { z_RaycastHit hit = target.raycastHits[ri]; if (hit.weights == null || hit.weights.Length < vertexCount) { continue; } for (int i = 0; i < commonVertexCount; i++) { int index = commonVertices[i][0]; if (hit.weights[index] < .0001f || (ignoreNonManifoldIndices && nonManifoldIndices.Contains(index))) { continue; } v = vertices[index]; if (direction == z_Direction.VertexNormal) { avg = z_Math.Average(vertices, neighborLookup[index]); } else { avg = z_Math.WeightedAverage(vertices, neighborLookup[index], hit.weights); if (direction == z_Direction.BrushNormal) { if (brushNormalIsSticky) { dirVec = brushNormalOnBeginApply[ri]; } else { dirVec = z_Math.WeightedAverage(normals, neighborLookup[index], hit.weights).normalized; } } plane.SetNormalAndPosition(dirVec, avg); avg = v - dirVec * plane.GetDistanceToPoint(v); } t = Vector3.Lerp(v, avg, hit.weights[index]); List <int> indices = commonVertices[i]; Vector3 pos = v + (t - v) * settings.strength * SMOOTH_STRENGTH_MODIFIER; for (int n = 0; n < indices.Count; n++) { vertices[indices[n]] = pos; } } } mesh.vertices = vertices; if (tempComponent != null) { tempComponent.OnVerticesMoved(mesh); } base.OnBrushApply(target, settings); }