├── .gitignore ├── Assets ├── HeadScan_Texture3D.asset ├── HeadScan_Texture3D.asset.meta ├── Texture3D preview in Inspector.unity ├── Texture3D preview in Inspector.unity.meta ├── Texture3DPreview.meta ├── Texture3DPreview │ ├── Attributes.meta │ ├── Attributes │ │ ├── Texture3DPreviewAttribute.cs │ │ └── Texture3DPreviewAttribute.cs.meta │ ├── Editor.meta │ └── Editor │ │ ├── Drawers.meta │ │ ├── Drawers │ │ ├── Texture3DPreviewDrawer.cs │ │ └── Texture3DPreviewDrawer.cs.meta │ │ ├── Editors.meta │ │ ├── Editors │ │ ├── Texture3DEditor.cs │ │ └── Texture3DEditor.cs.meta │ │ ├── Extensions.meta │ │ ├── Extensions │ │ ├── Texture3DExtensions.cs │ │ └── Texture3DExtensions.cs.meta │ │ ├── Helpers.meta │ │ ├── Helpers │ │ ├── MeshHelpers.cs │ │ ├── MeshHelpers.cs.meta │ │ ├── PreviewRenderUtilityHelpers.cs │ │ └── PreviewRenderUtilityHelpers.cs.meta │ │ ├── Shaders.meta │ │ └── Shaders │ │ ├── Texture3DPreviewShader.shader │ │ └── Texture3DPreviewShader.shader.meta ├── Texture3DPreviewInInspector.cs └── Texture3DPreviewInInspector.cs.meta ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Visual Studio 2015 cache directory 9 | /.vs/ 10 | 11 | # Autogenerated VS/MD/Consulo solution and project files 12 | ExportedObj/ 13 | .consulo/ 14 | *.csproj 15 | *.unityproj 16 | *.sln 17 | *.suo 18 | *.tmp 19 | *.user 20 | *.userprefs 21 | *.pidb 22 | *.booproj 23 | *.svd 24 | *.pdb 25 | 26 | # Unity3D generated meta files 27 | *.pidb.meta 28 | 29 | # Unity3D Generated File On Crash Reports 30 | sysinfo.txt 31 | 32 | # Builds 33 | *.apk 34 | *.unitypackage 35 | -------------------------------------------------------------------------------- /Assets/HeadScan_Texture3D.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 64677355665b5684c822c245cb6a495b 3 | timeCreated: 1507629404 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | externalObjects: {} 7 | mainObjectFileID: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3D preview in Inspector.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 8 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} 42 | --- !u!157 &3 43 | LightmapSettings: 44 | m_ObjectHideFlags: 0 45 | serializedVersion: 11 46 | m_GIWorkflowMode: 0 47 | m_GISettings: 48 | serializedVersion: 2 49 | m_BounceScale: 1 50 | m_IndirectOutputScale: 1 51 | m_AlbedoBoost: 1 52 | m_TemporalCoherenceThreshold: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 1 56 | m_LightmapEditorSettings: 57 | serializedVersion: 9 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_TextureWidth: 1024 61 | m_TextureHeight: 1024 62 | m_AO: 0 63 | m_AOMaxDistance: 1 64 | m_CompAOExponent: 1 65 | m_CompAOExponentDirect: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 0 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 500 79 | m_PVRBounces: 2 80 | m_PVRFilterTypeDirect: 0 81 | m_PVRFilterTypeIndirect: 0 82 | m_PVRFilterTypeAO: 0 83 | m_PVRFilteringMode: 1 84 | m_PVRCulling: 1 85 | m_PVRFilteringGaussRadiusDirect: 1 86 | m_PVRFilteringGaussRadiusIndirect: 5 87 | m_PVRFilteringGaussRadiusAO: 2 88 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 89 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 90 | m_PVRFilteringAtrousPositionSigmaAO: 1 91 | m_LightingDataAsset: {fileID: 0} 92 | m_UseShadowmask: 1 93 | --- !u!196 &4 94 | NavMeshSettings: 95 | serializedVersion: 2 96 | m_ObjectHideFlags: 0 97 | m_BuildSettings: 98 | serializedVersion: 2 99 | agentTypeID: 0 100 | agentRadius: 0.5 101 | agentHeight: 2 102 | agentSlope: 45 103 | agentClimb: 0.4 104 | ledgeDropHeight: 0 105 | maxJumpAcrossDistance: 0 106 | minRegionArea: 2 107 | manualCellSize: 0 108 | cellSize: 0.16666667 109 | manualTileSize: 0 110 | tileSize: 256 111 | accuratePlacement: 0 112 | debug: 113 | m_Flags: 0 114 | m_NavMeshData: {fileID: 0} 115 | --- !u!1 &1729229721 116 | GameObject: 117 | m_ObjectHideFlags: 0 118 | m_PrefabParentObject: {fileID: 0} 119 | m_PrefabInternal: {fileID: 0} 120 | serializedVersion: 5 121 | m_Component: 122 | - component: {fileID: 1729229723} 123 | - component: {fileID: 1729229722} 124 | m_Layer: 0 125 | m_Name: Texture3D preview in Inspector 126 | m_TagString: Untagged 127 | m_Icon: {fileID: 3936346786652291628, guid: 0000000000000000d000000000000000, type: 0} 128 | m_NavMeshLayer: 0 129 | m_StaticEditorFlags: 0 130 | m_IsActive: 1 131 | --- !u!114 &1729229722 132 | MonoBehaviour: 133 | m_ObjectHideFlags: 0 134 | m_PrefabParentObject: {fileID: 0} 135 | m_PrefabInternal: {fileID: 0} 136 | m_GameObject: {fileID: 1729229721} 137 | m_Enabled: 1 138 | m_EditorHideFlags: 0 139 | m_Script: {fileID: 11500000, guid: 308d5e80d1df35543bd2ec9636edd96a, type: 3} 140 | m_Name: 141 | m_EditorClassIdentifier: 142 | texture3D: {fileID: 11700000, guid: 64677355665b5684c822c245cb6a495b, type: 2} 143 | --- !u!4 &1729229723 144 | Transform: 145 | m_ObjectHideFlags: 0 146 | m_PrefabParentObject: {fileID: 0} 147 | m_PrefabInternal: {fileID: 0} 148 | m_GameObject: {fileID: 1729229721} 149 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 150 | m_LocalPosition: {x: 0, y: 0, z: 0} 151 | m_LocalScale: {x: 1, y: 1, z: 1} 152 | m_Children: [] 153 | m_Father: {fileID: 0} 154 | m_RootOrder: 0 155 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 156 | -------------------------------------------------------------------------------- /Assets/Texture3D preview in Inspector.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: febdae0f126b8174e86af88be2bbfdc2 3 | timeCreated: 1507537286 4 | licenseType: Pro 5 | DefaultImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d16d2cfdf00294d4eb7065e758b27a24 3 | folderAsset: yes 4 | timeCreated: 1507536992 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Attributes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17cf46f2ccde500418af03434fb6629d 3 | folderAsset: yes 4 | timeCreated: 1507549806 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Attributes/Texture3DPreviewAttribute.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | /// 4 | /// Attribute enabling Texture3D preview in a Monobehaviour component in the Inspector 5 | /// 6 | public class Texture3DPreviewAttribute : PropertyAttribute 7 | { 8 | #region Members 9 | /// 10 | /// Allows to show the field (when user drags/drops another Texture3D for example) or not (when Texture3D is changed in code only for example) 11 | /// 12 | public readonly bool showField; 13 | #endregion 14 | 15 | #region Constructor 16 | /// 17 | /// Declare this attribute in front of the Texture3D field to enable previewing in a Monobehaviour component in the Inspector 18 | /// 19 | /// Shows or not the Texture3D field on top of the preview (default = true) 20 | public Texture3DPreviewAttribute(bool showField = true) 21 | { 22 | this.showField = showField; 23 | } 24 | #endregion 25 | } -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Attributes/Texture3DPreviewAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 655fce24071158842896531956f42d6f 3 | timeCreated: 1507549815 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a90d828c78ec4c45af1a8fc441309e8 3 | folderAsset: yes 4 | timeCreated: 1507537066 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Drawers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7fb0cffe903e81840976ed03aaca4141 3 | folderAsset: yes 4 | timeCreated: 1507550383 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Drawers/Texture3DPreviewDrawer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | /// 6 | /// Custom drawer for Texture3DPreview attribute 7 | /// 8 | [CustomPropertyDrawer(typeof(Texture3DPreviewAttribute))] 9 | internal sealed class Texture3DPreviewDrawer : PropertyDrawer 10 | { 11 | #region Members 12 | /// 13 | /// Maximum preview size in the Inspector 14 | /// 15 | private const int _maxSize = 512; 16 | /// 17 | /// The material which the preview will be rendered with 18 | /// 19 | private static Material _material; 20 | /// 21 | /// String to show if the field is not a Texture3D 22 | /// 23 | private const string _notObjectOrTexture3DString = "Texture3DPreview attribute can only be used with Texture3D fields."; 24 | /// 25 | /// The angle of the camera preview 26 | /// 27 | private Vector2 _cameraAngle = new Vector2(127.5f, -22.5f); 28 | /// 29 | /// The raymarch interations 30 | /// 31 | private int _samplingIterations = 64; 32 | /// 33 | /// The factor of the Texture3D 34 | /// 35 | private float _density = 1; 36 | #endregion 37 | 38 | #region Functions 39 | /// 40 | /// Gets if the Texture3D should be displayed 41 | /// 42 | private bool ShowField 43 | { 44 | get 45 | { 46 | return ((Texture3DPreviewAttribute)attribute).showField; 47 | } 48 | } 49 | 50 | /// 51 | /// Checks if the drawn property is a UnityEngine.Object derived type 52 | /// 53 | /// The drawn object 54 | /// True if the drawn object is a UnityEngine.Object derived type, false otherwise 55 | private bool CheckIfObjectType(SerializedProperty property) 56 | { 57 | return property.propertyType == SerializedPropertyType.ObjectReference; 58 | } 59 | 60 | /// 61 | /// Checks if the drawn property is a Texture3D 62 | /// 63 | /// The drawn object 64 | /// True if the drawn object is a Texture3D, false otherwise 65 | private bool CheckIfTexture3D(SerializedProperty property) 66 | { 67 | return property.objectReferenceValue.GetType() == typeof(Texture3D); 68 | } 69 | 70 | /// 71 | /// Checks if the drawn property is null 72 | /// 73 | /// The drawn object 74 | /// True if the drawn object is null, false otherwise 75 | private bool CheckIfNull(SerializedProperty property) 76 | { 77 | return property.objectReferenceValue == null; 78 | } 79 | 80 | /// 81 | /// Computes the size of the preview accordingly to the Inspector width 82 | /// 83 | /// The margin reserved on the right of the preview 84 | /// The size of the preview 85 | private int ComputePreviewSize(int rightMargin) 86 | { 87 | int size = Mathf.FloorToInt(EditorGUIUtility.currentViewWidth) - rightMargin; 88 | size = Mathf.Min(size, Texture3DPreviewDrawer._maxSize); 89 | 90 | return size; 91 | } 92 | 93 | /// 94 | /// Sets back the camera angle 95 | /// 96 | public void ResetPreviewCameraAngle() 97 | { 98 | _cameraAngle = new Vector2(127.5f, -22.5f); 99 | } 100 | #endregion 101 | 102 | #region Overriden base class functions (https://docs.unity3d.com/ScriptReference/PropertyDrawer.html) 103 | /// 104 | /// Sets the height of the custom drawer 105 | /// 106 | /// The drawn object 107 | /// The "made readable" name of the object (as would be seen in the Insprector) 108 | /// 109 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) 110 | { 111 | float size = 0; 112 | 113 | if (CheckIfObjectType(property)) 114 | { 115 | if (ShowField) 116 | { 117 | size += EditorGUIUtility.singleLineHeight; 118 | } 119 | 120 | if (!CheckIfNull(property)) 121 | { 122 | if (CheckIfTexture3D(property)) 123 | { 124 | size += EditorGUIUtility.singleLineHeight; 125 | size += ComputePreviewSize((int)EditorGUIUtility.singleLineHeight); 126 | size += EditorGUIUtility.singleLineHeight; 127 | } 128 | else 129 | { 130 | size += EditorGUIUtility.singleLineHeight; 131 | } 132 | } 133 | else 134 | { 135 | size += EditorGUIUtility.singleLineHeight; 136 | } 137 | } 138 | else 139 | { 140 | size += EditorGUIUtility.singleLineHeight; 141 | } 142 | 143 | return size; 144 | } 145 | 146 | /// 147 | /// Fills drawer area 148 | /// 149 | /// The area of the drawer 150 | /// The drawn object 151 | /// The "made readable" name of the object (as would be seen in the Insprector) 152 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 153 | { 154 | if(CheckIfObjectType(property)) 155 | { 156 | if(ShowField) 157 | { 158 | Rect rect = position; 159 | rect.height = EditorGUIUtility.singleLineHeight; 160 | EditorGUI.ObjectField(rect, property, typeof(Texture3D)); 161 | position.y += EditorGUIUtility.singleLineHeight; 162 | } 163 | 164 | if(!CheckIfNull(property)) 165 | { 166 | if(CheckIfTexture3D(property)) 167 | { 168 | if (Event.current.type == EventType.Layout) 169 | { 170 | return; 171 | } 172 | 173 | position.y += EditorGUIUtility.singleLineHeight; 174 | 175 | int size = ComputePreviewSize((int)position.x * 2); 176 | Rect drawArea = position; 177 | drawArea.width = size; 178 | drawArea.height = drawArea.width; 179 | drawArea.x += position.width * 0.5f - drawArea.width * 0.5f; 180 | 181 | _cameraAngle = PreviewRenderUtilityHelpers.DragToAngles(_cameraAngle, drawArea); 182 | if (Event.current.type == EventType.Repaint) 183 | { 184 | GUI.Box(drawArea, ((Texture3D)property.objectReferenceValue).RenderTexture3DPreview(drawArea, _cameraAngle, 6.5f /*TODO : Find distance with fov and boundingsphere, when non uniform size will be supported*/, _samplingIterations, _density)); 185 | } 186 | 187 | Rect rect = drawArea; 188 | rect.y += drawArea.height; 189 | rect.height = EditorGUIUtility.singleLineHeight; 190 | rect.width = 100; // TODO : not use magic numbers 191 | if (GUI.Button(rect, "Reset Camera", EditorStyles.miniButton)) 192 | { 193 | ResetPreviewCameraAngle(); 194 | } 195 | rect.x += rect.width; 196 | rect.width = 60; // TODO : not use magic numbers 197 | EditorGUI.LabelField(rect, "Quality :"); 198 | rect.x += rect.width; 199 | _samplingIterations = EditorGUI.IntPopup(rect, _samplingIterations, new string[] { "16", "32", "64", "128", "256", "512" }, new int[] { 16, 32, 64, 128, 256, 512 }); 200 | rect.x += rect.width; 201 | rect.width = 60; // TODO : not use magic numbers 202 | EditorGUI.LabelField(rect, "Density :"); 203 | rect.x += rect.width; 204 | rect.width = drawArea.width - 280; // TODO : not use magic numbers 205 | _density = EditorGUI.Slider(rect, _density, 0, 5); 206 | } 207 | else 208 | { 209 | EditorGUI.LabelField(position, label.text, _notObjectOrTexture3DString, EditorStyles.boldLabel); 210 | } 211 | } 212 | else 213 | { 214 | EditorGUI.LabelField(position, label.text, "Texture3D field is empty.", EditorStyles.boldLabel); 215 | } 216 | } 217 | else 218 | { 219 | EditorGUI.LabelField(position, label.text, _notObjectOrTexture3DString, EditorStyles.boldLabel); 220 | } 221 | } 222 | #endregion 223 | } 224 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Drawers/Texture3DPreviewDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 52365bda6b1ad8945b713f96ada31cf3 3 | timeCreated: 1507550391 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Editors.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd30b7eb46077044b84d3daf863dada2 3 | folderAsset: yes 4 | timeCreated: 1507537074 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Editors/Texture3DEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | /// 5 | /// Draws a custom Inspector for Texture3D assets 6 | /// Actually, we will draw the default inspector but use the ability to draw a custom preview and render a custom asset's thumbnail 7 | /// 8 | [CustomEditor(typeof(Texture3D))] 9 | public class Texture3DEditor : Editor 10 | { 11 | #region Members 12 | /// 13 | /// The angle of the camera preview 14 | /// 15 | private Vector2 _cameraAngle = new Vector2(127.5f, -22.5f); // This default value will be used when rendering the asset thumbnail (see RenderStaticPreview) 16 | /// 17 | /// The raymarch interations 18 | /// 19 | private int _samplingIterations = 64; 20 | /// 21 | /// The factor of the Texture3D 22 | /// 23 | private float _density = 1; 24 | 25 | //// TODO : Investigate to access those variables as the default inspector is ugly 26 | //private SerializedProperty wrapModeProperty; 27 | //private SerializedProperty filterModeProperty; 28 | //private SerializedProperty anisotropyLevelProperty; 29 | #endregion 30 | 31 | #region Functions 32 | /// 33 | /// Sets back the camera angle 34 | /// 35 | public void ResetPreviewCameraAngle() 36 | { 37 | _cameraAngle = new Vector2(127.5f, -22.5f); 38 | } 39 | #endregion 40 | 41 | #region Overriden base class functions (https://docs.unity3d.com/ScriptReference/Editor.html) 42 | /// 43 | /// Draws the content of the Inspector 44 | /// 45 | public override void OnInspectorGUI() 46 | { 47 | serializedObject.Update(); 48 | 49 | //// Had to disable the default Inspector as it makes preview lag 50 | //DrawDefaultInspector(); 51 | 52 | serializedObject.ApplyModifiedProperties(); 53 | } 54 | 55 | #region Preview 56 | /// 57 | /// Tells if the Object has a custom preview 58 | /// 59 | public override bool HasPreviewGUI() 60 | { 61 | return true; 62 | } 63 | 64 | /// 65 | /// Draws the toolbar area on top of the preview window 66 | /// 67 | public override void OnPreviewSettings() 68 | { 69 | EditorGUILayout.BeginHorizontal(); 70 | if (GUILayout.Button("Reset Camera", EditorStyles.miniButton)) 71 | { 72 | ResetPreviewCameraAngle(); 73 | } 74 | EditorGUILayout.LabelField("Quality", GUILayout.MaxWidth(50)); 75 | _samplingIterations = EditorGUILayout.IntPopup(_samplingIterations, new string[] { "16", "32", "64", "128", "256", "512" }, new int[] { 16, 32, 64, 128, 256, 512 }, GUILayout.MaxWidth(50)); 76 | EditorGUILayout.LabelField("Density", GUILayout.MaxWidth(50)); 77 | _density = EditorGUILayout.Slider(_density, 0, 5, GUILayout.MaxWidth(200)); 78 | EditorGUILayout.EndHorizontal(); 79 | } 80 | 81 | /// 82 | /// Draws the preview area 83 | /// 84 | /// The area of the preview window 85 | /// The default GUIStyle used for preview windows 86 | public override void OnPreviewGUI(Rect rect, GUIStyle backgroundStyle) 87 | { 88 | _cameraAngle = PreviewRenderUtilityHelpers.DragToAngles(_cameraAngle, rect); 89 | 90 | if (Event.current.type == EventType.Repaint) 91 | { 92 | GUI.DrawTexture(rect, ((Texture3D)serializedObject.targetObject).RenderTexture3DPreview(rect, _cameraAngle, 6.5f /*TODO : Find distance with fov and boundingsphere, when non uniform size will be supported*/, _samplingIterations, _density), ScaleMode.StretchToFill, true); 93 | } 94 | } 95 | 96 | /// 97 | /// Draws the custom preview thumbnail for the asset in the Project window 98 | /// 99 | /// Path of the asset 100 | /// Array of children assets 101 | /// Width of the rendered thumbnail 102 | /// Height of the rendered thumbnail 103 | /// 104 | public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height) 105 | { 106 | return ((Texture3D)serializedObject.targetObject).RenderTexture3DStaticPreview(new Rect(0, 0, width, height), _cameraAngle, 6.5f /*TODO : Find distance with fov and boundingsphere, when non uniform size will be supported*/, _samplingIterations, _density); 107 | } 108 | 109 | /// 110 | /// Allows to give a custom title to the preview window 111 | /// 112 | /// 113 | public override GUIContent GetPreviewTitle() 114 | { 115 | return new GUIContent(serializedObject.targetObject.name + " preview"); 116 | } 117 | #endregion 118 | #endregion 119 | } 120 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Editors/Texture3DEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b71d02dbf285e334299bd880fb64ed52 3 | timeCreated: 1507537081 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d07e2e4489933074dbe6743c8bb470f5 3 | folderAsset: yes 4 | timeCreated: 1507540102 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Extensions/Texture3DExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | /// 6 | /// Extensions for Texture3D object so we can just invoke functions on them 7 | /// 8 | public static class Texture3DExtensions 9 | { 10 | #region Members 11 | /// 12 | /// The material used to render the Texture3D 13 | /// 14 | private static Material _previewTexture3dMaterial; 15 | /// 16 | /// The texture that will be used for the background 17 | /// 18 | private static Texture2D _backgroundTexture; 19 | /// 20 | /// The GUIStyle that will be used for the background 21 | /// 22 | private static GUIStyle _backgroundGuiStyle; 23 | #endregion 24 | 25 | #region Functions 26 | /// 27 | /// Accessor to the material used to render the Texture3D 28 | /// 29 | private static Material PreviewTexture3dMaterial 30 | { 31 | get 32 | { 33 | if (_previewTexture3dMaterial == null) 34 | { 35 | _previewTexture3dMaterial = new Material(Shader.Find("Hidden/Texture3DPreview")); 36 | } 37 | 38 | return _previewTexture3dMaterial; 39 | } 40 | } 41 | 42 | /// 43 | /// Accessor to the static background texture 44 | /// 45 | public static Texture2D BackgroundTexture 46 | { 47 | get 48 | { 49 | if (_backgroundTexture == null) 50 | { 51 | _backgroundTexture = new Texture2D(1, 1); 52 | _backgroundTexture.SetPixel(0, 0, Color.gray * 0.5f); 53 | _backgroundTexture.Apply(); 54 | } 55 | 56 | return _backgroundTexture; 57 | } 58 | } 59 | 60 | /// 61 | /// Accessor to the static background GUIStyle 62 | /// 63 | public static GUIStyle BackgroundGuiStyle 64 | { 65 | get 66 | { 67 | _backgroundGuiStyle = new GUIStyle(); 68 | _backgroundGuiStyle.active.background = BackgroundTexture; 69 | _backgroundGuiStyle.focused.background = BackgroundTexture; 70 | _backgroundGuiStyle.hover.background = BackgroundTexture; 71 | _backgroundGuiStyle.normal.background = BackgroundTexture; 72 | 73 | return _backgroundGuiStyle; 74 | } 75 | } 76 | 77 | /// 78 | /// Sets the parameters to the PreviewRenderUtility and calls the rendering 79 | /// 80 | /// The Texture3D to preview 81 | /// The camera angle 82 | /// The distance of the camera to the preview cube 83 | /// The amount of slices used to raymarch in the Texture3D 84 | /// A linear factor to multiply the Texture3D with 85 | private static void RenderInPreviewRenderUtility(Texture3D texture3D, Vector2 angle, float distance, int samplingIterations, float density) 86 | { 87 | PreviewTexture3dMaterial.SetInt("_SamplingQuality", samplingIterations); 88 | PreviewTexture3dMaterial.SetTexture("_MainTex", texture3D); 89 | PreviewTexture3dMaterial.SetFloat("_Density", density); 90 | 91 | PreviewRenderUtilityHelpers.Instance.DrawMesh(MeshHelpers.Cube, Matrix4x4.identity, PreviewTexture3dMaterial, 0); 92 | 93 | PreviewRenderUtilityHelpers.Instance.camera.transform.position = Vector2.zero; 94 | PreviewRenderUtilityHelpers.Instance.camera.transform.rotation = Quaternion.Euler(new Vector3(-angle.y, -angle.x, 0)); 95 | PreviewRenderUtilityHelpers.Instance.camera.transform.position = PreviewRenderUtilityHelpers.Instance.camera.transform.forward * -distance; 96 | PreviewRenderUtilityHelpers.Instance.camera.Render(); 97 | } 98 | 99 | /// 100 | /// Renders a preview of the Texture3D 101 | /// 102 | /// The Texture3D to preview 103 | /// The area where the preview is located 104 | /// The camera angle 105 | /// The distance of the camera to the preview cube 106 | /// The amount of slices used to raymarch in the Texture3D 107 | /// A linear factor to multiply the Texture3D with 108 | /// A Texture with the preview 109 | public static Texture RenderTexture3DPreview(this Texture3D texture3D, Rect rect, Vector2 angle, float distance, int samplingIterations, float density) 110 | { 111 | PreviewRenderUtilityHelpers.Instance.BeginPreview(rect, BackgroundGuiStyle); 112 | 113 | RenderInPreviewRenderUtility(texture3D, angle, distance, samplingIterations, density); 114 | 115 | return PreviewRenderUtilityHelpers.Instance.EndPreview(); 116 | } 117 | 118 | /// 119 | /// Renders a thumbnail of the Texture3D 120 | /// 121 | /// The Texture3D to preview 122 | /// The area where the preview is located 123 | /// The camera angle 124 | /// The distance of the camera to the preview cube 125 | /// The amount of slices used to raymarch in the Texture3D 126 | /// A linear factor to multiply the Texture3D with 127 | /// A Texture2D with the thumbnail 128 | public static Texture2D RenderTexture3DStaticPreview(this Texture3D texture3D, Rect rect, Vector2 angle, float distance, int samplingIterations, float density) 129 | { 130 | PreviewRenderUtilityHelpers.Instance.BeginStaticPreview(rect); 131 | 132 | RenderInPreviewRenderUtility(texture3D, angle, distance, samplingIterations, density); 133 | 134 | return PreviewRenderUtilityHelpers.Instance.EndStaticPreview(); 135 | } 136 | #endregion 137 | } 138 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Extensions/Texture3DExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ab2bc92cbdc8a1c4db19522e6c7e69ed 3 | timeCreated: 1507540112 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Helpers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 166ca2da427c87f4695ac884e6b27357 3 | folderAsset: yes 4 | timeCreated: 1507538041 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Helpers/MeshHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | /// 6 | /// Collection of function/variables related to the Mesh class 7 | /// 8 | public static class MeshHelpers 9 | { 10 | #region Members 11 | /// 12 | /// Just a Cube 13 | /// 14 | private static Mesh _cube; 15 | #endregion 16 | 17 | #region Functions 18 | /// 19 | /// Accessor to the Cube mesh 20 | /// 21 | public static Mesh Cube 22 | { 23 | get 24 | { 25 | if (_cube == null) 26 | { 27 | _cube = CreateCubeMesh(1, 1, 1); 28 | } 29 | 30 | return _cube; 31 | } 32 | } 33 | 34 | /// 35 | /// Creates a scaled Cube (http://wiki.unity3d.com/index.php/ProceduralPrimitives) 36 | /// 37 | /// Size of the cube along the width 38 | /// Size of the cube along the height 39 | /// Size of the cube along the length 40 | /// A mesh representing the scaled cube 41 | public static Mesh CreateCubeMesh(float width, float height, float length) 42 | { 43 | #region Vertices 44 | Vector3 p0 = new Vector3(-width * .5f, -height * .5f, length * .5f); 45 | Vector3 p1 = new Vector3(width * .5f, -height * .5f, length * .5f); 46 | Vector3 p2 = new Vector3(width * .5f, -height * .5f, -length * .5f); 47 | Vector3 p3 = new Vector3(-width * .5f, -height * .5f, -length * .5f); 48 | 49 | Vector3 p4 = new Vector3(-width * .5f, height * .5f, length * .5f); 50 | Vector3 p5 = new Vector3(width * .5f, height * .5f, length * .5f); 51 | Vector3 p6 = new Vector3(width * .5f, height * .5f, -length * .5f); 52 | Vector3 p7 = new Vector3(-width * .5f, height * .5f, -length * .5f); 53 | 54 | Vector3[] vertices = new Vector3[] 55 | { 56 | // Bottom 57 | p0, p1, p2, p3, 58 | // Left 59 | p7, p4, p0, p3, 60 | // Front 61 | p4, p5, p1, p0, 62 | // Back 63 | p6, p7, p3, p2, 64 | // Right 65 | p5, p6, p2, p1, 66 | // Top 67 | p7, p6, p5, p4 68 | }; 69 | #endregion 70 | 71 | #region Normales 72 | Vector3 up = Vector3.up; 73 | Vector3 down = Vector3.down; 74 | Vector3 front = Vector3.forward; 75 | Vector3 back = Vector3.back; 76 | Vector3 left = Vector3.left; 77 | Vector3 right = Vector3.right; 78 | 79 | Vector3[] normales = new Vector3[] 80 | { 81 | // Bottom 82 | down, down, down, down, 83 | // Left 84 | left, left, left, left, 85 | // Front 86 | front, front, front, front, 87 | // Back 88 | back, back, back, back, 89 | // Right 90 | right, right, right, right, 91 | // Top 92 | up, up, up, up 93 | }; 94 | #endregion 95 | 96 | #region UVs 97 | Vector2 _00 = new Vector2(0f, 0f); 98 | Vector2 _10 = new Vector2(1f, 0f); 99 | Vector2 _01 = new Vector2(0f, 1f); 100 | Vector2 _11 = new Vector2(1f, 1f); 101 | 102 | Vector2[] uvs = new Vector2[] 103 | { 104 | // Bottom 105 | _11, _01, _00, _10, 106 | // Left 107 | _11, _01, _00, _10, 108 | // Front 109 | _11, _01, _00, _10, 110 | // Back 111 | _11, _01, _00, _10, 112 | // Right 113 | _11, _01, _00, _10, 114 | // Top 115 | _11, _01, _00, _10, 116 | }; 117 | #endregion 118 | 119 | #region Triangles 120 | int[] triangles = new int[] 121 | { 122 | // Bottom 123 | 3, 1, 0, 124 | 3, 2, 1, 125 | // Left 126 | 3 + 4 * 1, 1 + 4 * 1, 0 + 4 * 1, 127 | 3 + 4 * 1, 2 + 4 * 1, 1 + 4 * 1, 128 | // Front 129 | 3 + 4 * 2, 1 + 4 * 2, 0 + 4 * 2, 130 | 3 + 4 * 2, 2 + 4 * 2, 1 + 4 * 2, 131 | // Back 132 | 3 + 4 * 3, 1 + 4 * 3, 0 + 4 * 3, 133 | 3 + 4 * 3, 2 + 4 * 3, 1 + 4 * 3, 134 | // Right 135 | 3 + 4 * 4, 1 + 4 * 4, 0 + 4 * 4, 136 | 3 + 4 * 4, 2 + 4 * 4, 1 + 4 * 4, 137 | // Top 138 | 3 + 4 * 5, 1 + 4 * 5, 0 + 4 * 5, 139 | 3 + 4 * 5, 2 + 4 * 5, 1 + 4 * 5, 140 | }; 141 | #endregion 142 | 143 | Mesh mesh = new Mesh 144 | { 145 | vertices = vertices, 146 | normals = normales, 147 | uv = uvs, 148 | triangles = triangles 149 | }; 150 | mesh.RecalculateBounds(); 151 | 152 | return mesh; 153 | } 154 | #endregion 155 | } 156 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Helpers/MeshHelpers.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e35bd3904b6535e44bb0bd59ea64f34f 3 | timeCreated: 1507538546 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Helpers/PreviewRenderUtilityHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | /// 7 | /// Collection of function/variables related to the PreviewRenderUtility class 8 | /// 9 | public static class PreviewRenderUtilityHelpers 10 | { 11 | #region Members 12 | /// 13 | /// A static copy of the PreviewRenderUtility class 14 | /// 15 | private static PreviewRenderUtility _instance; 16 | #endregion 17 | 18 | #region Functions 19 | /// 20 | /// Accessor to the PreviewRenderUtility instance 21 | /// 22 | public static PreviewRenderUtility Instance 23 | { 24 | get 25 | { 26 | if(_instance == null) 27 | { 28 | _instance = new PreviewRenderUtility(); 29 | } 30 | 31 | return _instance; 32 | } 33 | } 34 | 35 | /// 36 | /// Transforms the drag delta of the mouse on the UI into Euler angles 37 | /// 38 | /// Input angles 39 | /// The area where the mouse will be watched 40 | /// The modified angles 41 | public static Vector2 DragToAngles(Vector2 angles, Rect position) 42 | { 43 | int controlID = GUIUtility.GetControlID("DragToAngles".GetHashCode(), FocusType.Passive); 44 | Event current = Event.current; 45 | switch (current.GetTypeForControl(controlID)) 46 | { 47 | case EventType.MouseDown: 48 | if (position.Contains(current.mousePosition)) 49 | { 50 | GUIUtility.hotControl = controlID; 51 | current.Use(); 52 | EditorGUIUtility.SetWantsMouseJumping(1); 53 | } 54 | break; 55 | case EventType.MouseUp: 56 | if (GUIUtility.hotControl == controlID) 57 | { 58 | GUIUtility.hotControl = 0; 59 | } 60 | EditorGUIUtility.SetWantsMouseJumping(0); 61 | break; 62 | case EventType.MouseDrag: 63 | if (GUIUtility.hotControl == controlID) 64 | { 65 | angles -= current.delta / Mathf.Min(position.width, position.height) * 180; 66 | current.Use(); 67 | GUI.changed = true; 68 | } 69 | break; 70 | } 71 | return angles; 72 | } 73 | #endregion 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Helpers/PreviewRenderUtilityHelpers.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0300ebf5601e3b42b54edeff31038d2 3 | timeCreated: 1507538086 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 53e29d572e55dff45a7c43459f77ba28 3 | folderAsset: yes 4 | timeCreated: 1507540236 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Shaders/Texture3DPreviewShader.shader: -------------------------------------------------------------------------------- 1 | Shader "Hidden/Texture3DPreview" 2 | { 3 | SubShader 4 | { 5 | Tags 6 | { 7 | "Queue" = "Transparent" 8 | } 9 | 10 | CGINCLUDE 11 | #include "UnityCG.cginc" 12 | 13 | int _SamplingQuality; 14 | sampler3D _MainTex; 15 | float _Density; 16 | 17 | struct v2f 18 | { 19 | float4 pos : SV_POSITION; 20 | float3 localPos : TEXCOORD0; 21 | float4 screenPos : TEXCOORD1; 22 | float3 worldPos : TEXCOORD2; 23 | }; 24 | 25 | v2f vert(appdata_base v) 26 | { 27 | v2f OUT; 28 | OUT.pos = UnityObjectToClipPos(v.vertex); 29 | OUT.localPos = v.vertex.xyz; 30 | OUT.screenPos = ComputeScreenPos(OUT.pos); 31 | COMPUTE_EYEDEPTH(OUT.screenPos.z); 32 | OUT.worldPos = mul(unity_ObjectToWorld, v.vertex); 33 | return OUT; 34 | } 35 | 36 | // usual ray/cube intersection algorithm 37 | struct Ray 38 | { 39 | float3 origin; 40 | float3 direction; 41 | }; 42 | bool IntersectBox(Ray ray, out float entryPoint, out float exitPoint) 43 | { 44 | float3 invR = 1.0 / ray.direction; 45 | float3 tbot = invR * (float3(-0.5, -0.5, -0.5) - ray.origin); 46 | float3 ttop = invR * (float3(0.5, 0.5, 0.5) - ray.origin); 47 | float3 tmin = min(ttop, tbot); 48 | float3 tmax = max(ttop, tbot); 49 | float2 t = max(tmin.xx, tmin.yz); 50 | entryPoint = max(t.x, t.y); 51 | t = min(tmax.xx, tmax.yz); 52 | exitPoint = min(t.x, t.y); 53 | return entryPoint <= exitPoint; 54 | } 55 | 56 | float4 frag(v2f IN) : COLOR 57 | { 58 | float3 localCameraPosition = UNITY_MATRIX_IT_MV[3].xyz; 59 | 60 | Ray ray; 61 | ray.origin = localCameraPosition; 62 | ray.direction = normalize(IN.localPos - localCameraPosition); 63 | 64 | float entryPoint, exitPoint; 65 | IntersectBox(ray, entryPoint, exitPoint); 66 | 67 | if (entryPoint < 0.0) entryPoint = 0.0; 68 | 69 | float3 rayStart = ray.origin + ray.direction * entryPoint; 70 | float3 rayStop = ray.origin + ray.direction * exitPoint; 71 | 72 | float3 start = rayStop; 73 | float dist = distance(rayStop, rayStart); 74 | float stepSize = dist / float(_SamplingQuality); 75 | float3 ds = normalize(rayStop - rayStart) * stepSize; 76 | 77 | float4 color = float4(0,0,0,0); 78 | for (int i = _SamplingQuality; i >= 0; --i) 79 | { 80 | float3 pos = start.xyz; 81 | pos.xyz = pos.xyz + 0.5f; 82 | float4 mask = tex3D(_MainTex, pos); 83 | 84 | color.xyz += mask.xyz * mask.w; 85 | 86 | start -= ds; 87 | } 88 | color *= _Density / (uint)_SamplingQuality; 89 | 90 | // Weird enough, bruteforce seems quicker (to be investigated) 91 | //const float maxDist = 0.86602540378443864676372317075294f; 92 | //float stepSize = maxDist / (float)_SamplingQuality; 93 | //float dist = distance(rayStop, rayStart); 94 | //int steps = ceil(dist / stepSize); 95 | //float3 ds = normalize(rayStop - rayStart) * stepSize; 96 | //float3 color = float3(0,0,0); 97 | //[unroll(512)] 98 | //for (int i = steps; i >= 0; --i) 99 | //{ 100 | // float3 pos = start.xyz; 101 | // pos.xyz = pos.xyz + 0.5f; 102 | // float4 mask = tex3D(_MainTex, pos); 103 | // 104 | // color += mask.xyz * mask.w; 105 | // 106 | // start += ds; 107 | //} 108 | //color *= _Density / steps; 109 | 110 | return color; 111 | } 112 | ENDCG 113 | 114 | Pass 115 | { 116 | Cull front 117 | Blend One One 118 | ZWrite false 119 | 120 | CGPROGRAM 121 | #pragma target 3.0 122 | #pragma vertex vert 123 | #pragma fragment frag 124 | ENDCG 125 | 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /Assets/Texture3DPreview/Editor/Shaders/Texture3DPreviewShader.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5433510e20cd33045a8a47556dc6f366 3 | timeCreated: 1507540266 4 | licenseType: Pro 5 | ShaderImporter: 6 | externalObjects: {} 7 | defaultTextures: [] 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Texture3DPreviewInInspector.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class Texture3DPreviewInInspector : MonoBehaviour 6 | { 7 | [Texture3DPreview] 8 | public Texture3D texture3D; 9 | } 10 | -------------------------------------------------------------------------------- /Assets/Texture3DPreviewInInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 308d5e80d1df35543bd2ec9636edd96a 3 | timeCreated: 1507629441 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: 9 | - texture3D: {fileID: 11700000, guid: 64677355665b5684c822c245cb6a495b, type: 2} 10 | executionOrder: 0 11 | icon: {instanceID: 0} 12 | userData: 13 | assetBundleName: 14 | assetBundleVariant: 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **[Texture3D](https://docs.unity3d.com/ScriptReference/Texture3D.html) preview for [Unity](https://unity3d.com)** 2 | 3 | ## This package enables interactive previews of [Texture3D](https://docs.unity3d.com/ScriptReference/Texture3D.html) assets in Unity's Inspector window. 4 | 5 | **[You can directly download the Unity package by clicking here or by going in the Release section](https://github.com/raphael-ernaelsten/Texture3DPreview-for-Unity/releases)** 6 | 7 | ---------- 8 | 9 | ### Previews and thumbnails of [Texture3D](https://docs.unity3d.com/ScriptReference/Texture3D.html) asset 10 | 11 | When importing the Texture3D asset, Unity will automatically render a preview of the Texture3D to display in the Project window. 12 | 13 | ![Texture3D asset thumbnail](https://i.imgur.com/K9IhLF3.jpg) 14 | 15 | When selecting a Texture3D asset in the Project windows, Unity will display an preview of the Texture3D in the Inspector. 16 | 17 | ![Texture3D asset preview](https://i.imgur.com/Lm5Kykw.gif) 18 | 19 | ---------- 20 | 21 | ### Previews of a [Texture3D](https://docs.unity3d.com/ScriptReference/Texture3D.html) field on a GameObject's component 22 | 23 | To enable Texture3D field preview on a GameObject's component, add 24 | 25 | [Texture3DPreview] 26 | in front of the declared field. 27 | 28 | ![Texture3D field preview in Inspector](https://i.imgur.com/ru8u1qK.gif) 29 | 30 | ---------- 31 | 32 | ### Requirements 33 | 34 | - Shader model 3 capable graphic card 35 | - Unity 2017.1+ 36 | 37 | ---------- 38 | 39 | ### TODO 40 | 41 | - Preview non uniform Texture3D in their respective ratio (currently all previews will be cube) 42 | - Add alpha blend mode for rendering previews 43 | 44 | ---------- 45 | 46 | ### Know issues / limitations 47 | 48 | - Previews are currently in additive mode 49 | - Previews of multiples Texture3D assets don't work 50 | - Sometimes, the preview of a Texture3D field becomes empty 51 | 52 | ---------- 53 | 54 | ### Contact 55 | 56 | Feel free to contact me for any comment or suggestion. Twitter : @raphernaelsten 57 | 58 | ---------- 59 | 60 | ### Acknowledgment 61 | 62 | The sample Texture3D asset provided with this package was made using [MRI scans found on this website](https://neil.fraser.name/news/2007/11/19/). 63 | 64 | Here's the process : 65 | - selected [the right-to-left gif](https://neil.fraser.name/news/2007/RL.gif) 66 | - rescaled it to 128x128 and extracted all the frames using [VirtualDub](http://www.virtualdub.org/) 67 | - used [Unity's VFX Toolbox Image Sequencer](https://forum.unity.com/threads/release-thread-vfx-toolbox-image-sequencer.438465/) to resample the frames count and lay them on an images sheet 68 | ![Images sheet](https://i.imgur.com/hJvhZ78.jpg) 69 | - used a custom tool to build a Texture3D (basically create a Texture3D with the correct size then copy the images from the sheet as slices) from this sheet and save it as an asset 70 | --------------------------------------------------------------------------------