public static NPVoxCoord GetNearbyCoord(NPVoxModel model, Vector3 saveCoord, ResolveConflictMethodType resolveConflictMethod) { NPVoxCoord favoriteCoord = NPVoxCoordUtil.ToCoord(saveCoord); if (model.HasVoxelFast(favoriteCoord)) { NPVoxBox box = new NPVoxBox(favoriteCoord - NPVoxCoord.ONE, favoriteCoord + NPVoxCoord.ONE); favoriteCoord = NPVoxCoord.INVALID; float nearestDistance = 9999f; int favoriteEnclosingVoxelCount = -1; foreach (NPVoxCoord currentTestCoord in box.Enumerate()) { if (model.IsInside(currentTestCoord) && !model.HasVoxelFast(currentTestCoord)) { if (resolveConflictMethod == ResolveConflictMethodType.CLOSEST) { float distance = Vector3.Distance(NPVoxCoordUtil.ToVector(currentTestCoord), saveCoord); if (distance < nearestDistance) { nearestDistance = distance; favoriteCoord = currentTestCoord; } } else { int enclosingVoxelCount = 0; NPVoxBox enclosingBoxCheck = new NPVoxBox(currentTestCoord - NPVoxCoord.ONE, currentTestCoord + NPVoxCoord.ONE); foreach (NPVoxCoord enclosingTestCoord in enclosingBoxCheck.Enumerate()) { if (model.IsInside(currentTestCoord) && model.HasVoxelFast(currentTestCoord)) { enclosingVoxelCount++; } } if (enclosingVoxelCount > favoriteEnclosingVoxelCount) { enclosingVoxelCount = favoriteEnclosingVoxelCount; favoriteCoord = currentTestCoord; } } } } } return(favoriteCoord); }
public static NPVoxModel Transform(NPVoxModel sourceModel, NPVoxBox affectedArea, Matrix4x4 transformMatrix, ResolveConflictMethodType resolveConflictMethod = ResolveConflictMethodType.CLOSEST, NPVoxModel reuse = null) { NPVoxBox clampedBox = sourceModel.Clamp(affectedArea); // calculate size & offset for new model NPVoxCoord size = sourceModel.Size; NPVoxCoord offset = NPVoxCoord.ZERO; { NPVoxBox parentBounds = sourceModel.BoundingBox; NPVoxBox thisBounds = parentBounds.Clone(); // transform voxels foreach (NPVoxCoord coord in clampedBox.Enumerate()) { Vector3 saveCoord = transformMatrix.MultiplyPoint(NPVoxCoordUtil.ToVector(coord)); NPVoxCoord newCoord = NPVoxCoordUtil.ToCoord(saveCoord); if (!sourceModel.IsInside(newCoord)) { thisBounds.EnlargeToInclude(newCoord); } } // transform sockets foreach (NPVoxSocket socket in sourceModel.Sockets) { NPVoxCoord newCoord = NPVoxCoordUtil.ToCoord(transformMatrix.MultiplyPoint(NPVoxCoordUtil.ToVector(socket.Anchor))); if (clampedBox.Contains(socket.Anchor) && !sourceModel.IsInside(newCoord)) { thisBounds.EnlargeToInclude(newCoord); } } CalculateResizeOffset(parentBounds, thisBounds, out offset, out size); } bool hasVoxelGroups = sourceModel.HasVoxelGroups(); NPVoxBoneModel sourceBoneModel = sourceModel as NPVoxBoneModel; bool hasBoneGropus = sourceBoneModel != null; NPVoxModel transformedModel = NPVoxModel.NewInstance(sourceModel, size, reuse); NPVoxBoneModel transformedBoneModel = transformedModel as NPVoxBoneModel; if (hasVoxelGroups) { transformedModel.InitVoxelGroups(); transformedModel.NumVoxelGroups = sourceModel.NumVoxelGroups; } if (hasBoneGropus) { transformedBoneModel.AllBones = NPVoxBone.CloneBones(sourceBoneModel.AllBones); } // 1. copy all voxels over that are not affected by the transformation transformedModel.NumVoxels = sourceModel.NumVoxels; transformedModel.Colortable = sourceModel.Colortable; foreach (NPVoxCoord coord in sourceModel.EnumerateVoxels()) { NPVoxCoord movedCoord = coord + offset; if (!clampedBox.Contains(coord)) { transformedModel.SetVoxel(movedCoord, sourceModel.GetVoxel(coord)); if (hasVoxelGroups) { transformedModel.SetVoxelGroup(movedCoord, sourceModel.GetVoxelGroup(coord)); } if (hasBoneGropus) { transformedBoneModel.SetBoneMask(movedCoord, sourceBoneModel.GetBoneMask(coord)); } } } // 2. copy all voxels that can be tranformed without conflict, Dictionary <NPVoxCoord, Vector3> conflictVoxels = new Dictionary <NPVoxCoord, Vector3>(); foreach (NPVoxCoord sourceCoord in clampedBox.Enumerate()) { if (sourceModel.HasVoxelFast(sourceCoord)) { Vector3 saveCoord = transformMatrix.MultiplyPoint(NPVoxCoordUtil.ToVector(sourceCoord)); Vector3 targetCoordSave = saveCoord + NPVoxCoordUtil.ToVector(offset); NPVoxCoord targetCoord = NPVoxCoordUtil.ToCoord(targetCoordSave); if (!transformedModel.HasVoxelFast(targetCoord)) { transformedModel.SetVoxel(targetCoord, sourceModel.GetVoxel(sourceCoord)); if (hasVoxelGroups) { transformedModel.SetVoxelGroup(targetCoord, sourceModel.GetVoxelGroup(sourceCoord)); } if (hasBoneGropus) { transformedBoneModel.SetBoneMask(targetCoord, sourceBoneModel.GetBoneMask(sourceCoord)); } } else { conflictVoxels[sourceCoord] = targetCoordSave; } } } // 3. try to fit in voxels that had conflicts int numberOfConflictsSolved = 0; if (resolveConflictMethod != ResolveConflictMethodType.NONE) { foreach (NPVoxCoord sourceCoord in conflictVoxels.Keys) { if (sourceModel.HasVoxelFast(sourceCoord)) { Vector3 targetSaveCoord = conflictVoxels[sourceCoord]; NPVoxCoord nearbyCoord = GetNearbyCoord(transformedModel, targetSaveCoord, resolveConflictMethod); if (!nearbyCoord.Equals(NPVoxCoord.INVALID)) { transformedModel.SetVoxel(nearbyCoord, sourceModel.GetVoxel(sourceCoord)); if (hasVoxelGroups) { transformedModel.SetVoxelGroup(nearbyCoord, sourceModel.GetVoxelGroup(sourceCoord)); } if (hasBoneGropus) { transformedBoneModel.SetBoneMask(nearbyCoord, sourceBoneModel.GetBoneMask(sourceCoord)); } numberOfConflictsSolved++; } } } if (numberOfConflictsSolved != conflictVoxels.Count) { Debug.Log(string.Format("transformation has resolved {0}/{1} conflicting voxels", numberOfConflictsSolved, conflictVoxels.Count)); } } // 4. transform all sockets NPVoxSocket[] sockets = new NPVoxSocket[sourceModel.Sockets.Length]; for (int i = 0; i < sockets.Length; i++) { NPVoxSocket socket = sourceModel.Sockets[i]; if (clampedBox.Contains(socket.Anchor)) { // transform anchor Vector3 saveOriginalAnchor = NPVoxCoordUtil.ToVector(socket.Anchor); Vector3 saveTargetAnchor = transformMatrix.MultiplyPoint(saveOriginalAnchor) + NPVoxCoordUtil.ToVector(offset); socket.Anchor = NPVoxCoordUtil.ToCoord(saveTargetAnchor); // transform Quaternion Quaternion originalRotation = Quaternion.Euler(socket.EulerAngles); Matrix4x4 rotated = (Matrix4x4.TRS(Vector3.zero, originalRotation, Vector3.one) * transformMatrix); socket.EulerAngles = Matrix4x4Util.GetRotation(rotated).eulerAngles; } else { socket.Anchor = socket.Anchor + offset; } sockets[i] = socket; } transformedModel.Sockets = sockets; // 5. count all voxels transformedModel.NumVoxels = transformedModel.NumVoxels - (conflictVoxels.Count - numberOfConflictsSolved); transformedModel.RecalculateNumVoxels(true); return(transformedModel); }