// Initialization void Start() { // Create empty array to store target objects, which will have been built from source ones targets = new GameObject[sources.Length]; transformations = new Transformation[sources.Length]; // Process given source objects for (int index = 0; index < sources.Length; ++index) { // Store rotation, position and scaling of the source transformations[index].sourceRotation = sources[index].transform.localRotation; transformations[index].sourcePosition = sources[index].transform.localPosition; transformations[index].sourceScaling = sources[index].transform.localScale; // Try to get voxel rasterizer component for current source object Voxels.Rasterizer rasterizer = sources[index].GetComponent <Voxels.Rasterizer>(); if (rasterizer != null) { // Start processing rasterizer.Process(ActOnCreation, sources[index]); } else { // Use source as target object targets[index] = sources[index]; transformations[index].targetRotation = sources[index].transform.localRotation; transformations[index].targetPosition = sources[index].transform.localPosition; transformations[index].targetScaling = sources[index].transform.localScale; } // Deactive unselected source object if (selectedTarget != index) { sources[index].SetActive(false); } } currentTarget = selectedTarget; }
// Show and process inspector public override void OnInspectorGUI() { string controlText; Bounds targetBounds = new Bounds(); Vector3 vector3, voxelSize; Vector volumeResolution; int width, height, depth; Rasterizer voxelConverter = (Rasterizer)target; //Rect rect = GUILayoutUtility.GetLastRect(); //EditorGUI.DropShadowLabel(rect, "Voxels for Unity"); //EditorGUILayout.GetControlRect(); //GUIContent content = EditorGUIUtility.ObjectContent(null, typeof(ConverterEditor)); //if (content != null) //{ // content.image = null; //} Vector3 minimum = voxelConverter.minimumBound; Vector3 maximum = voxelConverter.maximumBound; // Button to recompute scan area EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel("Boundaries:"); if (GUILayout.Button("Adopt from object") || (voxelConverter.minimumBound == Vector3.one && voxelConverter.maximumBound == -Vector3.one)) { Undo.RecordObject(voxelConverter, "Bound Adoption"); voxelConverter.RecomputeBounds(); minimum = voxelConverter.minimumBound; maximum = voxelConverter.maximumBound; } EditorGUILayout.EndHorizontal(); // Add title to bar Rect rect = GUILayoutUtility.GetLastRect(); rect.x += EditorGUIUtility.currentViewWidth * 0.5f; rect.y -= rect.height; EditorGUI.LabelField(rect, Information.Title); // Fields to change boundaries EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(" Minimum", GUILayout.MaxWidth(96)); minimum = EditorGUILayout.Vector3Field("", minimum); maximum = Vector3.Max(minimum, maximum); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(" Maximum", GUILayout.MaxWidth(96)); maximum = EditorGUILayout.Vector3Field("", maximum); minimum = Vector3.Min(minimum, maximum); EditorGUILayout.EndHorizontal(); // Sort components vector3 = Vector3.Min(minimum, maximum); minimum = vector3; // Store new boundaries if (minimum != voxelConverter.minimumBound) { Undo.RecordObject(voxelConverter, "Minimum Bound"); voxelConverter.minimumBound = minimum; } if (maximum != voxelConverter.maximumBound) { Undo.RecordObject(voxelConverter, "Maximum Bound"); voxelConverter.maximumBound = maximum; } // Compute center and size targetBounds.center = (minimum + maximum) * 0.5f; targetBounds.extents = maximum - minimum; // Get voxel size voxelSize = voxelConverter.GetVoxelSize(targetBounds.extents); // Field to change size of one voxel EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Voxel Size", GUILayout.MaxWidth(96)); vector3 = EditorGUILayout.Vector3Field("", voxelSize); EditorGUILayout.EndHorizontal(); // Store voxel size, if it has been changed if (vector3 != voxelSize) { Undo.RecordObject(voxelConverter, "Voxel Size Change"); if (voxelConverter.SetVoxelSize(vector3.x, vector3.y, vector3.z)) { voxelSize = vector3; } } // Compute volume resolution, if it is not set volumeResolution = voxelConverter.GetVolumeResolution(targetBounds.extents); // Edit number of voxels EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Voxel Counts", GUILayout.MaxWidth(96)); //EditorGUILayout.LabelField("X", GUILayout.MaxWidth(12)); width = EditorGUILayout.IntField(volumeResolution.x, GUILayout.MinWidth(32)); //EditorGUILayout.LabelField("Y", GUILayout.MaxWidth(12)); height = EditorGUILayout.IntField(volumeResolution.y, GUILayout.MinWidth(32)); //EditorGUILayout.LabelField("Z", GUILayout.MaxWidth(12)); depth = EditorGUILayout.IntField(volumeResolution.z, GUILayout.MinWidth(32)); EditorGUILayout.EndHorizontal(); // Store volume resolution, if it has been changed if (width != volumeResolution.x || height != volumeResolution.y || depth != volumeResolution.z) { Undo.RecordObject(voxelConverter, "Voxel Resolution Change"); if (voxelConverter.SetVolumeResolution(width, height, depth)) { volumeResolution = new Vector(width, height, depth); } } // Determine maximum sampling int samplingLimit = Rasterizer.Engine.TextureSizeLimit / Mathf.Max(Mathf.Max(volumeResolution.x, volumeResolution.y), volumeResolution.z); // Build resolution vector, sampling slider, color baking toggle mode with combo box int samplingResolution = EditorGUILayout.IntSlider("Sampling Resolution", voxelConverter.samplingResolution, 1, samplingLimit); if (voxelConverter.samplingResolution != samplingResolution) { Undo.RecordObject(voxelConverter, "Sampling Resolution Change"); voxelConverter.samplingResolution = samplingResolution; } float oldVoxelOverscan = voxelConverter.voxelOverscan * 100.0f; float newVoxelOverscan = NonLinearHorizontalSlider("Voxel Overscan", oldVoxelOverscan, ref overscanInput, "%", overscanSliderSteps); //// Create own combination of edit field and non-linear slider //EditorGUILayout.BeginHorizontal(); //EditorGUILayout.LabelField("Voxel Overscan", GUILayout.MinWidth(108), GUILayout.MaxWidth(116)); //int oldVoxelOverscan = (int)(voxelConverter.voxelOverscan * 100.0f + 0.5f); //int newVoxelOverscan = EditorGUILayout.IntField(oldVoxelOverscan, GUILayout.MinWidth(24), GUILayout.MaxWidth(48)); //EditorGUILayout.LabelField("%", GUILayout.MinWidth(20), GUILayout.MaxWidth(24)); //newVoxelOverscan = (int)(SliderToValue(GUILayout.HorizontalSlider(ValueToSlider(newVoxelOverscan, overscanSliderSteps), 0, ValueToSlider(1000000, overscanSliderSteps)), overscanSliderSteps)); //EditorGUILayout.EndHorizontal(); // Store new value if (oldVoxelOverscan != newVoxelOverscan) { Undo.RecordObject(voxelConverter, "Voxel Overscan Change"); voxelConverter.voxelOverscan = (float)newVoxelOverscan * 0.01f; } BakingOperation bakingOperationMode = (BakingOperation)EditorGUILayout.IntPopup("Baking Mode", (int)voxelConverter.bakingOperationMode, Rasterizer.BakingOperationModeNames, Rasterizer.BakingOperationModes); if (voxelConverter.bakingOperationMode != bakingOperationMode) { Undo.RecordObject(voxelConverter, "Baking Operation Mode Change"); voxelConverter.bakingOperationMode = bakingOperationMode; } switch (bakingOperationMode) { case BakingOperation.OriginalMaterial: break; default: // Object selection of materials to use for opaque and transparent voxels EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.MaxWidth(16)); Material templateMaterial = (Material)EditorGUILayout.ObjectField("Opaque Template", voxelConverter.opaqueTemplate, typeof(Material), true); if (voxelConverter.opaqueTemplate != templateMaterial) { Undo.RecordObject(voxelConverter, "Opaque Template Material Change"); voxelConverter.opaqueTemplate = templateMaterial; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.MaxWidth(16)); templateMaterial = (Material)EditorGUILayout.ObjectField("Transparent Template", voxelConverter.transparentTemplate, typeof(Material), true); if (voxelConverter.transparentTemplate != templateMaterial) { Undo.RecordObject(voxelConverter, "Transparent Template Material Change"); voxelConverter.transparentTemplate = templateMaterial; } EditorGUILayout.EndHorizontal(); // Flags to modulate material components EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.MaxWidth(16)); bool mainColorModulation = EditorGUILayout.ToggleLeft("Main Color", voxelConverter.mainColorModulation, GUILayout.MaxWidth(128)); if (voxelConverter.mainColorModulation != mainColorModulation) { Undo.RecordObject(voxelConverter, "Main Color Flag Change"); voxelConverter.mainColorModulation = mainColorModulation; } bool specularColorModulation = EditorGUILayout.ToggleLeft("Specular Color", voxelConverter.specularColorModulation, GUILayout.MaxWidth(128)); if (voxelConverter.specularColorModulation != specularColorModulation) { Undo.RecordObject(voxelConverter, "Specular Color Flag Change"); voxelConverter.specularColorModulation = specularColorModulation; } bool emissiveColorModulation = EditorGUILayout.ToggleLeft("Emissive Color", voxelConverter.emissiveColorModulation, GUILayout.MaxWidth(128)); if (voxelConverter.emissiveColorModulation != emissiveColorModulation) { Undo.RecordObject(voxelConverter, "Emissive Color Flag Change"); voxelConverter.emissiveColorModulation = emissiveColorModulation; } EditorGUILayout.EndHorizontal(); //if (mainColorModulation || specularColorModulation || emissiveColorModulation) { // Fields for color modulation EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.MaxWidth(32)); float saturationFactor = EditorGUILayout.FloatField("Saturation", voxelConverter.saturationFactor, GUILayout.MaxWidth(320)); if (GUILayout.Button("Reset")) { saturationFactor = 1; } if (voxelConverter.saturationFactor != saturationFactor) { Undo.RecordObject(voxelConverter, "Color Saturation Change"); voxelConverter.saturationFactor = saturationFactor; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.MaxWidth(32)); float brightnessFactor = EditorGUILayout.FloatField("Brightness", voxelConverter.brightnessFactor, GUILayout.MaxWidth(320)); if (GUILayout.Button("Reset")) { brightnessFactor = 1; } if (voxelConverter.brightnessFactor != brightnessFactor) { Undo.RecordObject(voxelConverter, "Color Brightness Change"); voxelConverter.brightnessFactor = brightnessFactor; } EditorGUILayout.EndHorizontal(); } break; } // Get current processing state processingProgress = voxelConverter.GetProgress(); // Check if game is not running if (!Application.isPlaying) { // Processing button with dynamic text depending on current progress controlText = processingProgress > 1 ? "Waiting... [" + (int)processingProgress + "]" : processingProgress >= 0 ? "Processing... [" + (int)((1 - processingProgress) * 100) + " %]" : "Process"; if (GUILayout.Button(controlText)) { // Check if object is already being processed or will be if (processingProgress >= 0) { // Stop processing if (voxelConverter.Stop()) { // Unset progress processingProgress = -1; } } else { // Start processing if (voxelConverter.Process()) { // Add update callback EditorApplication.update += OnUpdate; } } } } else { // Check if object is already being processed or will be if (processingProgress >= 0) { controlText = processingProgress > 1 ? "Waiting... [" + (int)processingProgress + "]" : "Processing... [" + (int)((1 - processingProgress) * 100) + " %]"; // Output progress GUILayout.Space(EditorGUIUtility.standardVerticalSpacing); Rect rectangle = EditorGUILayout.BeginVertical(); EditorGUI.ProgressBar(rectangle, processingProgress == 1 ? 0 : 1 - processingProgress % 1, controlText); GUILayout.Space(EditorGUIUtility.singleLineHeight); EditorGUILayout.EndVertical(); GUILayout.Space(EditorGUIUtility.standardVerticalSpacing); EditorUtility.SetDirty(voxelConverter); } } int oldValue, newValue; // Read current frame time target from preferences oldValue = (int)(EditorPrefs.GetFloat("VoxelConvertBudgetTime", voxelConverter.budgetTime) * 1000.0f + 0.5f); //oldValue = (int)(Converter.budgetTime * 1000.0f + 0.5f); //// Convert value to string //if (oldValue >= timeSliderSteps[timeSliderSteps.Length - 1].limit) //{ // controlText = "max"; //} //else //{ // controlText = oldValue.ToString(); //} //// Create own combination of edit field and non-linear slider //EditorGUILayout.BeginHorizontal(); //EditorGUILayout.LabelField("Frame Time Target", GUILayout.MinWidth(108), GUILayout.MaxWidth(116)); //if (!int.TryParse(controlText = GUILayout.TextField(controlText, GUILayout.MinWidth(24), GUILayout.MaxWidth(48)), out newValue)) //{ // // Convert text to new value // if (controlText.ToLower() == "max") // { // newValue = (int)timeSliderSteps[timeSliderSteps.Length - 1].limit; // } // else if (controlText.Length == 0) // { // newValue = 0; // } // else // { // newValue = oldValue; // } //} //EditorGUILayout.LabelField("ms", GUILayout.MinWidth(20), GUILayout.MaxWidth(24)); //int intermediateValue = (int)SliderToValue(ValueToSlider(newValue, timeSliderSteps), timeSliderSteps); //int temporaryValue = (int)(SliderToValue(GUILayout.HorizontalSlider(ValueToSlider(newValue, timeSliderSteps), 0, ValueToSlider(1000000, timeSliderSteps)), timeSliderSteps)); //EditorGUILayout.EndHorizontal(); //// Store value to instance and preferences, if it has been changed //if (intermediateValue != temporaryValue) //{ // newValue = temporaryValue; //} newValue = (int)(NonLinearHorizontalSlider("Frame Time Target", oldValue, ref frametimeTargetInput, "ms", timeSliderSteps, false, true, true) + 0.5f); if (oldValue != newValue) { Undo.RecordObject(voxelConverter, "Frame Time Target Change"); voxelConverter.budgetTime = (float)newValue * 0.001f; EditorPrefs.SetFloat("VoxelConvertBudgetTime", voxelConverter.budgetTime); } bool oldFlag = EditorPrefs.GetBool("VoxelConvertMultiThreading", voxelConverter.multiThreading); bool newFlag; // Create toggle for multi-threading EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Multi Threading", GUILayout.MinWidth(108), GUILayout.MaxWidth(116)); newFlag = EditorGUILayout.Toggle(oldFlag); EditorGUILayout.EndHorizontal(); if (newFlag != oldFlag) { Undo.RecordObject(voxelConverter, "Multi Threading Change"); voxelConverter.multiThreading = newFlag; EditorPrefs.SetBool("VoxelConvertMultiThreading", voxelConverter.multiThreading); } long sampledWidth, sampledHeight, sampledDepth, size; // Compute total size of the volume including sampling sampledWidth = volumeResolution.x * voxelConverter.samplingResolution; sampledHeight = volumeResolution.y * voxelConverter.samplingResolution; sampledDepth = volumeResolution.z * voxelConverter.samplingResolution; // Estimate highest amount of memory, which is required to store information to all possible voxels size = Storage.ComputeMaximumSize(width, height, depth, voxelConverter.samplingResolution, voxelConverter.bakingOperationMode == BakingOperation.OriginalMaterial); // Output information controlText = string.Format("Object Extent: {0:F} x {1:F} x {2:F}" + "\nRasterization: {3:##,#} x {5:##,#} x {7:##,#}" // [{4:##,#} x {6:##,#} x {8:##,#}]" + "\nVoxels Count: {12}{9:##,#}" // [{10:##,#}]" , targetBounds.extents.x, targetBounds.extents.y, targetBounds.extents.z , width, sampledWidth, height, sampledHeight, depth, sampledDepth , width * height * depth, sampledWidth * sampledHeight * sampledDepth , size , "max. ", "max. " ); EditorGUILayout.HelpBox(controlText, MessageType.None); }