예제 #1
0
        void ComputeZone()
        {
            if (m_Beam)
            {
                var rangeEnd        = m_Beam.fallOffEnd * rangeMultiplier;
                var lerpedRadiusEnd = Mathf.LerpUnclamped(m_Beam.coneRadiusStart, m_Beam.coneRadiusEnd, rangeMultiplier);

                if (m_Beam.dimensions == Dimensions.Dim3D)
                {
                    var meshCollider = gameObject.GetOrAddComponent <MeshCollider>();
                    Debug.Assert(meshCollider);

                    int sides = Mathf.Min(m_Beam.geomSides, kMeshColliderNumSides);
                    var mesh  = MeshGenerator.GenerateConeZ_Radius(rangeEnd, m_Beam.coneRadiusStart, lerpedRadiusEnd, sides, 0, false, false);
                    mesh.hideFlags = Consts.ProceduralObjectsHideFlags;

                    meshCollider.sharedMesh = mesh;
                    meshCollider.convex     = setIsTrigger;
                    meshCollider.isTrigger  = setIsTrigger;
                }
                else
                {
                    if (m_PolygonCollider2D == null)
                    {
                        m_PolygonCollider2D = gameObject.GetOrAddComponent <PolygonCollider2D>();
                        Debug.Assert(m_PolygonCollider2D);
                    }

                    var polyCoordsLS = new Vector2[] // polygon coord in local space
                    {
                        new Vector2(0.0f, -m_Beam.coneRadiusStart),
                        new Vector2(rangeEnd, -lerpedRadiusEnd),
                        new Vector2(rangeEnd, lerpedRadiusEnd),
                        new Vector2(0.0f, m_Beam.coneRadiusStart)
                    };

                    if (m_DynamicOcclusionRaycasting && m_DynamicOcclusionRaycasting.planeEquationWS.IsValid())
                    {
                        var plane3dWS = m_DynamicOcclusionRaycasting.planeEquationWS;

                        if (Utils.IsAlmostZero(plane3dWS.normal.z))
                        {
                            // Compute 2 points on the plane in world space
                            // Use this technique instead of transforming the plane's normal to fully support scaling

                            var ptOnPlane1 = plane3dWS.ClosestPointOnPlaneCustom(Vector3.zero);
                            var ptOnPlane2 = plane3dWS.ClosestPointOnPlaneCustom(Vector3.up);

                            if (Utils.IsAlmostZero(Vector3.SqrMagnitude(ptOnPlane1 - ptOnPlane2)))
                            {
                                ptOnPlane1 = plane3dWS.ClosestPointOnPlaneCustom(Vector3.right);
                            }

                            // Compute 2 points on the plane in local space
                            ptOnPlane1 = transform.InverseTransformPoint(ptOnPlane1);
                            ptOnPlane2 = transform.InverseTransformPoint(ptOnPlane2);

                            // Compute plane equation in local space
                            var plane2dLS = PolygonHelper.Plane2D.FromPoints(ptOnPlane1, ptOnPlane2);
                            if (plane2dLS.normal.x > 0.0f)
                            {
                                plane2dLS.Flip();
                            }

                            polyCoordsLS = plane2dLS.CutConvex(polyCoordsLS);
                        }
                    }

                    m_PolygonCollider2D.points    = polyCoordsLS;
                    m_PolygonCollider2D.isTrigger = setIsTrigger;
                }
            }
        }
예제 #2
0
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            bool reloadNoise = false;

            bool isUsedInstance = (Object)Config.Instance == this.target;

            if (!IsOverriddenInstance())
            {
                if (isUsedInstance)
                {
                    if (GUILayout.Button(EditorStrings.ConfigCreateOverrideAsset))
                    {
                        ConfigOverrideEditor.CreateAsset();
                    }
                }
                else
                {
                    ButtonOpenConfig(/*miniButton*/ false);
                }
                DrawLineSeparator();
            }

            if (IsOverriddenInstance() && !isUsedInstance)
            {
                EditorGUILayout.HelpBox(EditorStrings.ConfigMultipleAssets, MessageType.Error);
                EditorGUILayout.Separator();
                ButtonOpenConfig();
            }
            else
            {
                EditorGUI.BeginDisabledGroup(IsDisabled());
                {
                    EditorGUI.BeginChangeCheck();
                    {
                        if (HeaderFoldable("Beam Geometry"))
                        {
                            using (new EditorGUILayout.HorizontalScope())
                            {
                                geometryOverrideLayer.boolValue = EditorGUILayout.Toggle(EditorStrings.ConfigGeometryOverrideLayer, geometryOverrideLayer.boolValue);
                                using (new EditorGUI.DisabledGroupScope(!geometryOverrideLayer.boolValue))
                                {
                                    geometryLayerID.intValue = EditorGUILayout.LayerField(geometryLayerID.intValue);
                                }
                            }

                            geometryTag.stringValue = EditorGUILayout.TagField(EditorStrings.ConfigGeometryTag, geometryTag.stringValue);
                        }
                        DrawLineSeparator();

                        if (HeaderFoldable("Rendering"))
                        {
                            RenderQueueGUIDraw();

                            if (BeamGeometry.isCustomRenderPipelineSupported)
                            {
                                EditorGUI.BeginChangeCheck();
                                {
                                    renderPipeline.CustomEnum <RenderPipeline>(EditorStrings.ConfigGeometryRenderPipeline, EditorStrings.ConfigGeometryRenderPipelineEnumDescriptions);
                                }
                                if (EditorGUI.EndChangeCheck())
                                {
                                    Config.OnRenderPipelineChanged((RenderPipeline)renderPipeline.enumValueIndex);
                                    VolumetricLightBeam._EditorSetAllBeamGeomDirty(); // need to fully reset the BeamGeom to update the shader
                                    ReimportShaders();
                                }
                            }

                            EditorGUI.BeginChangeCheck();
                            {
                                EditorGUILayout.PropertyField(renderingMode, EditorStrings.ConfigGeometryRenderingMode);

                                if (renderPipeline.enumValueIndex == (int)RenderPipeline.SRP_4_0_0_or_higher && renderingMode.enumValueIndex == (int)RenderingMode.MultiPass)
                                {
                                    EditorGUILayout.HelpBox(EditorStrings.ConfigSrpAndMultiPassNoCompatible, MessageType.Error);
                                }

#pragma warning disable 0162 // warning CS0162: Unreachable code detected
                                if (renderingMode.enumValueIndex == (int)RenderingMode.GPUInstancing && !GpuInstancing.isSupported)
                                {
                                    EditorGUILayout.HelpBox(EditorStrings.ConfigGeometryGpuInstancingNotSupported, MessageType.Warning);
                                }
#pragma warning restore 0162
                            }
                            if (EditorGUI.EndChangeCheck())
                            {
                                VolumetricLightBeam._EditorSetAllBeamGeomDirty(); // need to fully reset the BeamGeom to update the shader
                                GlobalMesh.Destroy();
                                ReimportShaders();
                            }
                        }
                    }
                    if (EditorGUI.EndChangeCheck())
                    {
                        VolumetricLightBeam._EditorSetAllMeshesDirty();
                    }
                    DrawLineSeparator();

                    if (HeaderFoldable("Shared Mesh"))
                    {
                        EditorGUI.BeginChangeCheck();
                        EditorGUILayout.PropertyField(sharedMeshSides, EditorStrings.ConfigSharedMeshSides);
                        EditorGUILayout.PropertyField(sharedMeshSegments, EditorStrings.ConfigSharedMeshSegments);
                        if (EditorGUI.EndChangeCheck())
                        {
                            GlobalMesh.Destroy();
                            VolumetricLightBeam._EditorSetAllMeshesDirty();
                        }

                        var meshInfo = "These properties will change the mesh tessellation of each Volumetric Light Beam with 'Shared' MeshType.\nAdjust them carefully since they could impact performance.";
                        meshInfo += string.Format("\nShared Mesh stats: {0} vertices, {1} triangles", MeshGenerator.GetSharedMeshVertexCount(), MeshGenerator.GetSharedMeshIndicesCount() / 3);
                        EditorGUILayout.HelpBox(meshInfo, MessageType.Info);
                    }
                    DrawLineSeparator();

                    if (HeaderFoldable("Global 3D Noise"))
                    {
                        EditorGUILayout.PropertyField(globalNoiseScale, EditorStrings.ConfigGlobalNoiseScale);
                        EditorGUILayout.PropertyField(globalNoiseVelocity, EditorStrings.ConfigGlobalNoiseVelocity);
                    }
                    DrawLineSeparator();

                    if (HeaderFoldable("Camera to compute Fade Out"))
                    {
                        EditorGUI.BeginChangeCheck();
                        fadeOutCameraTag.stringValue = EditorGUILayout.TagField(EditorStrings.ConfigFadeOutCameraTag, fadeOutCameraTag.stringValue);
                        if (EditorGUI.EndChangeCheck() && Application.isPlaying)
                        {
                            (target as Config).ForceUpdateFadeOutCamera();
                        }
                    }
                    DrawLineSeparator();

                    if (HeaderFoldable("Internal Data (do not change)"))
                    {
                        EditorGUILayout.PropertyField(beamShader1Pass, EditorStrings.ConfigBeamShader1Pass);
                        EditorGUILayout.PropertyField(beamShader2Pass, EditorStrings.ConfigBeamShader2Pass);
                        EditorGUILayout.PropertyField(dustParticlesPrefab, EditorStrings.ConfigDustParticlesPrefab);

                        EditorGUI.BeginChangeCheck();
                        EditorGUILayout.PropertyField(noise3DData, EditorStrings.ConfigNoise3DData);
                        EditorGUILayout.PropertyField(noise3DSize, EditorStrings.ConfigNoise3DSize);
                        if (EditorGUI.EndChangeCheck())
                        {
                            reloadNoise = true;
                        }

                        if (Noise3D.isSupported && !Noise3D.isProperlyLoaded)
                        {
                            EditorGUILayout.HelpBox(EditorStrings.HelpNoiseLoadingFailed, MessageType.Error);
                        }
                    }
                    DrawLineSeparator();

                    using (new EditorGUILayout.HorizontalScope())
                    {
                        if (GUILayout.Button(EditorStrings.ConfigOpenDocumentation, EditorStyles.miniButton))
                        {
                            UnityEditor.Help.BrowseURL(Consts.HelpUrlConfig);
                        }

                        if (GUILayout.Button(EditorStrings.ConfigResetToDefaultButton, EditorStyles.miniButton))
                        {
                            UnityEditor.Undo.RecordObject(target, "Reset Config Properties");
                            (target as Config).Reset();
                        }
                    }
                }
                EditorGUI.EndDisabledGroup();
            }

            serializedObject.ApplyModifiedProperties();

            if (reloadNoise)
            {
                Noise3D._EditorForceReloadData(); // Should be called AFTER ApplyModifiedProperties so the Config instance has the proper values when reloading data
            }
        }
예제 #3
0
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            Debug.Assert(m_TargetConfig != null);

            m_NeedToReloadNoise   = false;
            m_NeedToRefreshShader = false;
            m_IsUsedInstance      = m_TargetConfig.IsCurrentlyUsedInstance();

            // Config per plaftorm
#if UNITY_2018_1_OR_NEWER
            {
                bool hasValidName            = m_TargetConfig.HasValidAssetName();
                bool isCurrentPlatformSuffix = m_TargetConfig.GetAssetSuffix() == PlatformHelper.GetCurrentPlatformSuffix();

                var    platformSuffix = m_TargetConfig.GetAssetSuffix();
                string platformStr    = "Default Config asset";
                if (!string.IsNullOrEmpty(platformSuffix))
                {
                    platformStr = string.Format("Config asset for platform '{0}'", m_TargetConfig.GetAssetSuffix());
                }
                if (!hasValidName)
                {
                    platformStr += " (INVALID)";
                }
                EditorGUILayout.LabelField(platformStr, EditorStyles.boldLabel);

                if (GUILayout.Button(EditorStrings.Beam.ButtonCreateOverridePerPlatform, EditorStyles.miniButton))
                {
                    var menu = new GenericMenu();
                    foreach (var platform in System.Enum.GetValues(typeof(RuntimePlatform)))
                    {
                        menu.AddItem(new GUIContent(platform.ToString()), false, OnAddConfigPerPlatform, platform);
                    }
                    menu.ShowAsContext();
                }

                if (!hasValidName)
                {
                    EditorGUILayout.Separator();
                    EditorGUILayout.HelpBox(EditorStrings.Config.InvalidPlatformOverride, MessageType.Error);
                    ButtonOpenConfig();
                }
                else if (!m_IsUsedInstance)
                {
                    EditorGUILayout.Separator();

                    if (isCurrentPlatformSuffix)
                    {
                        EditorGUILayout.HelpBox(EditorStrings.Config.WrongAssetLocation, MessageType.Error);
                    }
                    else
                    {
                        EditorGUILayout.HelpBox(EditorStrings.Config.NotCurrentAssetInUse, MessageType.Warning);
                    }

                    ButtonOpenConfig();
                }

                DrawLineSeparator();
            }
#endif

            {
                EditorGUI.BeginChangeCheck();
                {
                    if (FoldableHeader.Begin(this, EditorStrings.Config.HeaderBeamGeometry))
                    {
                        using (new EditorGUILayout.HorizontalScope())
                        {
                            geometryOverrideLayer.boolValue = EditorGUILayout.Toggle(EditorStrings.Config.GeometryOverrideLayer, geometryOverrideLayer.boolValue);
                            using (new EditorGUI.DisabledGroupScope(!geometryOverrideLayer.boolValue))
                            {
                                geometryLayerID.intValue = EditorGUILayout.LayerField(geometryLayerID.intValue);
                            }
                        }

                        geometryTag.stringValue = EditorGUILayout.TagField(EditorStrings.Config.GeometryTag, geometryTag.stringValue);
                    }
                    FoldableHeader.End();

                    if (FoldableHeader.Begin(this, EditorStrings.Config.HeaderRendering))
                    {
                        RenderQueueGUIDraw();

                        if (BeamGeometry.isCustomRenderPipelineSupported)
                        {
                            EditorGUI.BeginChangeCheck();
                            {
                                renderPipeline.CustomEnum <RenderPipeline>(EditorStrings.Config.GeometryRenderPipeline, EditorStrings.Config.GeometryRenderPipelineEnumDescriptions);
                            }
                            if (EditorGUI.EndChangeCheck())
                            {
                                SetDirty(DirtyFlags.AllBeamGeom | DirtyFlags.Shader); // need to fully reset the BeamGeom to update the shader
                            }
                        }

                        if (m_TargetConfig.hasRenderPipelineMismatch)
                        {
                            EditorGUILayout.HelpBox(EditorStrings.Config.ErrorRenderPipelineMismatch, MessageType.Error);
                        }

                        EditorGUI.BeginChangeCheck();
                        {
                            EditorGUILayout.PropertyField(renderingMode, EditorStrings.Config.GeometryRenderingMode);

                            if (renderPipeline.enumValueIndex == (int)RenderPipeline.BuiltIn)
                            {
                                if (renderingMode.enumValueIndex == (int)RenderingMode.SRPBatcher)
                                {
                                    EditorGUILayout.HelpBox(EditorStrings.Config.ErrorSrpBatcherOnlyCompatibleWithSrp, MessageType.Error);
                                }
                            }
                            else
                            {
                                if (renderingMode.enumValueIndex == (int)RenderingMode.SRPBatcher && SRPHelper.renderPipelineType == SRPHelper.RenderPipeline.LWRP)
                                {
                                    EditorGUILayout.HelpBox(EditorStrings.Config.ErrorSrpBatcherNotCompatibleWithLWRP, MessageType.Error);
                                }

                                if (renderingMode.enumValueIndex == (int)RenderingMode.MultiPass)
                                {
                                    EditorGUILayout.HelpBox(EditorStrings.Config.ErrorSrpAndMultiPassNotCompatible, MessageType.Error);
                                }
                            }

#pragma warning disable 0162 // warning CS0162: Unreachable code detected
                            if (renderingMode.enumValueIndex == (int)RenderingMode.GPUInstancing && !BatchingHelper.isGpuInstancingSupported)
                            {
                                EditorGUILayout.HelpBox(EditorStrings.Config.ErrorGeometryGpuInstancingNotSupported, MessageType.Error);
                            }
#pragma warning restore 0162
                        }
                        if (EditorGUI.EndChangeCheck())
                        {
                            SetDirty(DirtyFlags.AllBeamGeom | DirtyFlags.GlobalMesh | DirtyFlags.Shader); // need to fully reset the BeamGeom to update the shader
                        }

                        if (m_TargetConfig.beamShader == null)
                        {
                            EditorGUILayout.HelpBox(EditorStrings.Config.GetErrorInvalidShader(), MessageType.Error);
                        }

                        if (ditheringFactor.FloatSlider(EditorStrings.Config.DitheringFactor, 0.0f, 1.0f))
                        {
                            SetDirty(DirtyFlags.Shader);
                        }
                    }
                    FoldableHeader.End();
                }
                if (EditorGUI.EndChangeCheck())
                {
                    VolumetricLightBeam._EditorSetAllMeshesDirty();
                }

                if (FoldableHeader.Begin(this, EditorStrings.Config.HeaderSharedMesh))
                {
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(sharedMeshSides, EditorStrings.Config.SharedMeshSides);
                    EditorGUILayout.PropertyField(sharedMeshSegments, EditorStrings.Config.SharedMeshSegments);
                    if (EditorGUI.EndChangeCheck())
                    {
                        SetDirty(DirtyFlags.GlobalMesh | DirtyFlags.AllMeshes);
                    }

                    var meshInfo = "These properties will change the mesh tessellation of each Volumetric Light Beam with 'Shared' MeshType.\nAdjust them carefully since they could impact performance.";
                    meshInfo += string.Format("\nShared Mesh stats: {0} vertices, {1} triangles", MeshGenerator.GetSharedMeshVertexCount(), MeshGenerator.GetSharedMeshIndicesCount() / 3);
                    EditorGUILayout.HelpBox(meshInfo, MessageType.Info);
                }
                FoldableHeader.End();

                if (FoldableHeader.Begin(this, EditorStrings.Config.HeaderGlobal3DNoise))
                {
                    EditorGUILayout.PropertyField(globalNoiseScale, EditorStrings.Config.GlobalNoiseScale);
                    EditorGUILayout.PropertyField(globalNoiseVelocity, EditorStrings.Config.GlobalNoiseVelocity);
                }
                FoldableHeader.End();

                if (FoldableHeader.Begin(this, EditorStrings.Config.HeaderFadeOutCamera))
                {
                    EditorGUI.BeginChangeCheck();
                    fadeOutCameraTag.stringValue = EditorGUILayout.TagField(EditorStrings.Config.FadeOutCameraTag, fadeOutCameraTag.stringValue);
                    if (EditorGUI.EndChangeCheck() && Application.isPlaying)
                    {
                        m_TargetConfig.ForceUpdateFadeOutCamera();
                    }
                }
                FoldableHeader.End();

                if (FoldableHeader.Begin(this, EditorStrings.Config.HeaderFeaturesEnabled))
                {
                    EditorGUI.BeginChangeCheck();
                    {
                        EditorGUILayout.PropertyField(featureEnabledColorGradient, EditorStrings.Config.FeatureEnabledColorGradient);
                        EditorGUILayout.PropertyField(featureEnabledDepthBlend, EditorStrings.Config.FeatureEnabledDepthBlend);
                        EditorGUILayout.PropertyField(featureEnabledNoise3D, EditorStrings.Config.FeatureEnabledNoise3D);
                        EditorGUILayout.PropertyField(featureEnabledDynamicOcclusion, EditorStrings.Config.FeatureEnabledDynamicOcclusion);
                        EditorGUILayout.PropertyField(featureEnabledMeshSkewing, EditorStrings.Config.FeatureEnabledMeshSkewing);
                        EditorGUILayout.PropertyField(featureEnabledShaderAccuracyHigh, EditorStrings.Config.FeatureEnabledShaderAccuracyHigh);
                    }
                    if (EditorGUI.EndChangeCheck())
                    {
                        SetDirty(DirtyFlags.Shader | DirtyFlags.AllBeamGeom);
                    }
                }
                FoldableHeader.End();

                if (FoldableHeader.Begin(this, EditorStrings.Config.HeaderInternalData))
                {
                    EditorGUILayout.PropertyField(dustParticlesPrefab, EditorStrings.Config.DustParticlesPrefab);

                    EditorGUILayout.PropertyField(ditheringNoiseTexture, EditorStrings.Config.DitheringNoiseTexture);

                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(noise3DData, EditorStrings.Config.Noise3DData);
                    EditorGUILayout.PropertyField(noise3DSize, EditorStrings.Config.Noise3DSize);
                    if (EditorGUI.EndChangeCheck())
                    {
                        SetDirty(DirtyFlags.Noise);
                    }

                    if (Noise3D.isSupported && !Noise3D.isProperlyLoaded)
                    {
                        EditorGUILayout.HelpBox(EditorStrings.Common.HelpNoiseLoadingFailed, MessageType.Error);
                    }
                }
                FoldableHeader.End();

                if (GUILayout.Button(EditorStrings.Config.OpenDocumentation, EditorStyles.miniButton))
                {
                    UnityEditor.Help.BrowseURL(Consts.HelpUrlConfig);
                }

                using (new EditorGUILayout.HorizontalScope())
                {
                    if (GUILayout.Button(EditorStrings.Config.ResetToDefaultButton, EditorStyles.miniButton))
                    {
                        UnityEditor.Undo.RecordObject(target, "Reset Config Properties");
                        m_TargetConfig.Reset();
                        SetDirty(DirtyFlags.Target | DirtyFlags.Noise);
                    }

                    if (GUILayout.Button(EditorStrings.Config.ResetInternalDataButton, EditorStyles.miniButton))
                    {
                        UnityEditor.Undo.RecordObject(target, "Reset Internal Data");
                        m_TargetConfig.ResetInternalData();
                        SetDirty(DirtyFlags.Target | DirtyFlags.Noise);
                    }
                }
            }

            serializedObject.ApplyModifiedProperties();

            if (m_NeedToRefreshShader)
            {
                m_TargetConfig.RefreshShader(Config.RefreshShaderFlags.All); // need to be done AFTER ApplyModifiedProperties
            }
            if (m_NeedToReloadNoise)
            {
                Noise3D._EditorForceReloadData(); // Should be called AFTER ApplyModifiedProperties so the Config instance has the proper values when reloading data
            }
        }
 public static int GetSharedMeshVertexCount()
 {
     return(MeshGenerator.GetVertexCount(Config.Instance.sharedMeshSides, Config.Instance.sharedMeshSegments, true));
 }
예제 #5
0
        public void UpdateMaterialAndBounds()
        {
            Debug.Assert(m_Master);

            if (ApplyMaterial() == false)
            {
                return;
            }

            MaterialChangeStart();
            {
                if (m_CustomMaterial == null)
                {
                    if (m_MaterialModifierCallback != null)
                    {
                        m_MaterialModifierCallback(this);
                    }
                }

                float slopeRad = (m_Master.coneAngle * Mathf.Deg2Rad) / 2; // use coneAngle (instead of spotAngle) which is more correct with the geometry
                SetMaterialProp(ShaderProperties.ConeSlopeCosSin, new Vector2(Mathf.Cos(slopeRad), Mathf.Sin(slopeRad)));

                // kMinRadius and kMinApexOffset prevents artifacts when fresnel computation is done in the vertex shader
                const float kMinRadius = 0.0001f;
                var         coneRadius = new Vector2(Mathf.Max(m_Master.coneRadiusStart, kMinRadius), Mathf.Max(m_Master.coneRadiusEnd, kMinRadius));
                SetMaterialProp(ShaderProperties.ConeRadius, coneRadius);

                const float kMinApexOffset = 0.0001f;
                float       nonNullApex    = Mathf.Sign(m_Master.coneApexOffsetZ) * Mathf.Max(Mathf.Abs(m_Master.coneApexOffsetZ), kMinApexOffset);
                SetMaterialProp(ShaderProperties.ConeApexOffsetZ, nonNullApex);

                if (m_Master.usedColorMode == ColorMode.Flat)
                {
                    SetMaterialProp(ShaderProperties.ColorFlat, m_Master.color);
                }
                else
                {
                    var precision = Utils.GetFloatPackingPrecision();
                    m_ColorGradientMatrix = m_Master.colorGradient.SampleInMatrix((int)precision);
                    // pass the gradient matrix in OnWillRenderObject()
                }

                float intensityInside, intensityOutside;
                m_Master.GetInsideAndOutsideIntensity(out intensityInside, out intensityOutside);
                SetMaterialProp(ShaderProperties.AlphaInside, intensityInside);
                SetMaterialProp(ShaderProperties.AlphaOutside, intensityOutside);
                SetMaterialProp(ShaderProperties.AttenuationLerpLinearQuad, m_Master.attenuationLerpLinearQuad);
                SetMaterialProp(ShaderProperties.DistanceFallOff, new Vector3(m_Master.fallOffStart, m_Master.fallOffEnd, m_Master.maxGeometryDistance));
                SetMaterialProp(ShaderProperties.DistanceCamClipping, m_Master.cameraClippingDistance);
                SetMaterialProp(ShaderProperties.FresnelPow, Mathf.Max(0.001f, m_Master.fresnelPow)); // no pow 0, otherwise will generate inf fresnel and issues on iOS
                SetMaterialProp(ShaderProperties.GlareBehind, m_Master.glareBehind);
                SetMaterialProp(ShaderProperties.GlareFrontal, m_Master.glareFrontal);
                SetMaterialProp(ShaderProperties.DrawCap, m_Master.geomCap ? 1 : 0);
                SetMaterialProp(ShaderProperties.TiltVector, m_Master.tiltFactor);
                SetMaterialProp(ShaderProperties.AdditionalClippingPlaneWS, m_Master.additionalClippingPlane);

                if (isDepthBlendEnabled)
                {
                    SetMaterialProp(ShaderProperties.DepthBlendDistance, m_Master.depthBlendDistance);
                }

                if (isNoiseEnabled)
                {
                    Noise3D.LoadIfNeeded();

                    var noiseVelocity = m_Master.noiseVelocityUseGlobal ? Config.Instance.globalNoiseVelocity : m_Master.noiseVelocityLocal;
                    var noiseScale    = m_Master.noiseScaleUseGlobal ? Config.Instance.globalNoiseScale : m_Master.noiseScaleLocal;

                    SetMaterialProp(ShaderProperties.NoiseVelocityAndScale, new Vector4(
                                        noiseVelocity.x,
                                        noiseVelocity.y,
                                        noiseVelocity.z,
                                        noiseScale));

                    SetMaterialProp(ShaderProperties.NoiseParam, new Vector2(
                                        m_Master.noiseIntensity,
                                        m_Master.noiseMode == NoiseMode.WorldSpace ? 0f : 1f));
                }

                var localScale = ComputeLocalMatrix(); // compute matrix before sending it to the shader

                if (m_Master.hasMeshSkewing)
                {
                    var localForwardDirectionNormalized = m_Master.skewingLocalForwardDirectionNormalized;
                    SetMaterialProp(ShaderProperties.LocalForwardDirection, localForwardDirectionNormalized);

                    if (coneMesh != null) // coneMesh can be null few frames with Dynamic Occlusion & GPU Instancing
                    {
                        var localForwardDirectionN = localForwardDirectionNormalized;
                        localForwardDirectionN   /= localForwardDirectionN.z;
                        localForwardDirectionN   *= m_Master.fallOffEnd;
                        localForwardDirectionN.x /= localScale.x;
                        localForwardDirectionN.y /= localScale.y;

                        var bounds = MeshGenerator.ComputeBounds(1f, 1f, 1f);
                        var min    = bounds.min;
                        var max    = bounds.max;

                        if (localForwardDirectionN.x > 0.0f)
                        {
                            max.x += localForwardDirectionN.x;
                        }
                        else
                        {
                            min.x += localForwardDirectionN.x;
                        }

                        if (localForwardDirectionN.y > 0.0f)
                        {
                            max.y += localForwardDirectionN.y;
                        }
                        else
                        {
                            min.y += localForwardDirectionN.y;
                        }

                        bounds.min      = min;
                        bounds.max      = max;
                        coneMesh.bounds = bounds;
                    }
                }

#if VLB_SRP_SUPPORT
                // This update is to make QA test 'ReflectionObliqueProjection' pass
                UpdateMatricesPropertiesForGPUInstancingSRP();
#endif
            }
            MaterialChangeStop();

#if DEBUG_SHOW_MESH_NORMALS
            for (int vertexInd = 0; vertexInd < coneMesh.vertexCount; vertexInd++)
            {
                var vertex = coneMesh.vertices[vertexInd];

                // apply modification done inside VS
                vertex.x *= Mathf.Lerp(coneRadius.x, coneRadius.y, vertex.z);
                vertex.y *= Mathf.Lerp(coneRadius.x, coneRadius.y, vertex.z);
                vertex.z *= m_Master.fallOffEnd;

                var cosSinFlat = new Vector2(vertex.x, vertex.y).normalized;
                var normal     = new Vector3(cosSinFlat.x * Mathf.Cos(slopeRad), cosSinFlat.y * Mathf.Cos(slopeRad), -Mathf.Sin(slopeRad)).normalized;

                vertex = transform.TransformPoint(vertex);
                normal = transform.TransformDirection(normal);
                Debug.DrawRay(vertex, normal * 0.25f);
            }
#endif
        }
        public static Mesh GenerateConeZ_Radius(float lengthZ, float radiusStart, float radiusEnd, int numSides, int numSegments, bool cap)
        {
            Debug.Assert(lengthZ > 0f);
            Debug.Assert(radiusStart >= 0f);
            Debug.Assert(numSides >= 3);
            Debug.Assert(numSegments >= 0);
            Mesh mesh = new Mesh();
            bool flag = false;

            flag        = (!cap ? false : radiusStart > 0f);
            radiusStart = Mathf.Max(radiusStart, 0.001f);
            int num  = numSides * (numSegments + 2);
            int num1 = num;

            if (flag)
            {
                num1 = num1 + numSides + 1;
            }
            Vector3[] vector3 = new Vector3[num1];
            for (int i = 0; i < numSides; i++)
            {
                float single  = 6.28318548f * (float)i / (float)numSides;
                float single1 = Mathf.Cos(single);
                float single2 = Mathf.Sin(single);
                for (int j = 0; j < numSegments + 2; j++)
                {
                    float single3 = (float)j / (float)(numSegments + 1);
                    Debug.Assert((single3 < 0f ? false : single3 <= 1f));
                    float single4 = Mathf.Lerp(radiusStart, radiusEnd, single3);
                    vector3[i + j * numSides] = new Vector3(single4 * single1, single4 * single2, single3 * lengthZ);
                }
            }
            if (flag)
            {
                int num2 = num;
                vector3[num2] = Vector3.zero;
                num2++;
                for (int k = 0; k < numSides; k++)
                {
                    float single5 = 6.28318548f * (float)k / (float)numSides;
                    float single6 = Mathf.Cos(single5);
                    float single7 = Mathf.Sin(single5);
                    vector3[num2] = new Vector3(radiusStart * single6, radiusStart * single7, 0f);
                    num2++;
                }
                Debug.Assert(num2 == (int)vector3.Length);
            }
            if (MeshGenerator.duplicateBackFaces)
            {
                Vector3[] vector3Array = new Vector3[(int)vector3.Length * 2];
                vector3.CopyTo(vector3Array, 0);
                vector3.CopyTo(vector3Array, (int)vector3.Length);
                mesh.vertices = vector3Array;
            }
            else
            {
                mesh.vertices = vector3;
            }
            Vector2[] vector2 = new Vector2[num1];
            int       num3    = 0;

            for (int l = 0; l < num; l++)
            {
                int num4 = num3;
                num3          = num4 + 1;
                vector2[num4] = Vector2.zero;
            }
            if (flag)
            {
                for (int m = 0; m < numSides + 1; m++)
                {
                    int num5 = num3;
                    num3          = num5 + 1;
                    vector2[num5] = new Vector2(1f, 0f);
                }
            }
            Debug.Assert(num3 == (int)vector2.Length);
            if (MeshGenerator.duplicateBackFaces)
            {
                Vector2[] vector2Array = new Vector2[(int)vector2.Length * 2];
                vector2.CopyTo(vector2Array, 0);
                vector2.CopyTo(vector2Array, (int)vector2.Length);
                for (int n = 0; n < (int)vector2.Length; n++)
                {
                    Vector2 vector21 = vector2Array[n + (int)vector2.Length];
                    vector2Array[n + (int)vector2.Length] = new Vector2(vector21.x, 1f);
                }
                mesh.uv = vector2Array;
            }
            else
            {
                mesh.uv = vector2;
            }
            int num6 = numSides * 2 * Mathf.Max(numSegments + 1, 1) * 3;

            if (flag)
            {
                num6 = num6 + numSides * 3;
            }
            int[] numArray = new int[num6];
            int   num7     = 0;

            for (int o = 0; o < numSides; o++)
            {
                int num8 = o + 1;
                if (num8 == numSides)
                {
                    num8 = 0;
                }
                for (int p = 0; p < numSegments + 1; p++)
                {
                    int num9  = p * numSides;
                    int num10 = num7;
                    num7            = num10 + 1;
                    numArray[num10] = num9 + o;
                    int num11 = num7;
                    num7            = num11 + 1;
                    numArray[num11] = num9 + num8;
                    int num12 = num7;
                    num7            = num12 + 1;
                    numArray[num12] = num9 + o + numSides;
                    int num13 = num7;
                    num7            = num13 + 1;
                    numArray[num13] = num9 + num8 + numSides;
                    int num14 = num7;
                    num7            = num14 + 1;
                    numArray[num14] = num9 + o + numSides;
                    int num15 = num7;
                    num7            = num15 + 1;
                    numArray[num15] = num9 + num8;
                }
            }
            if (flag)
            {
                for (int q = 0; q < numSides - 1; q++)
                {
                    int num16 = num7;
                    num7            = num16 + 1;
                    numArray[num16] = num;
                    int num17 = num7;
                    num7            = num17 + 1;
                    numArray[num17] = num + q + 2;
                    int num18 = num7;
                    num7            = num18 + 1;
                    numArray[num18] = num + q + 1;
                }
                int num19 = num7;
                num7            = num19 + 1;
                numArray[num19] = num;
                int num20 = num7;
                num7            = num20 + 1;
                numArray[num20] = num + 1;
                int num21 = num7;
                num7            = num21 + 1;
                numArray[num21] = num + numSides;
            }
            Debug.Assert(num7 == (int)numArray.Length);
            if (MeshGenerator.duplicateBackFaces)
            {
                int[] numArray1 = new int[(int)numArray.Length * 2];
                numArray.CopyTo(numArray1, 0);
                for (int r = 0; r < (int)numArray.Length; r += 3)
                {
                    numArray1[(int)numArray.Length + r]     = numArray[r] + num1;
                    numArray1[(int)numArray.Length + r + 1] = numArray[r + 2] + num1;
                    numArray1[(int)numArray.Length + r + 2] = numArray[r + 1] + num1;
                }
                mesh.triangles = numArray1;
            }
            else
            {
                mesh.triangles = numArray;
            }
            Bounds bound = new Bounds(new Vector3(0f, 0f, lengthZ * 0.5f), new Vector3(Mathf.Max(radiusStart, radiusEnd) * 2f, Mathf.Max(radiusStart, radiusEnd) * 2f, lengthZ));

            mesh.bounds = bound;
            Debug.Assert(mesh.vertexCount == MeshGenerator.GetVertexCount(numSides, numSegments, flag));
            Debug.Assert((int)mesh.triangles.Length == MeshGenerator.GetIndicesCount(numSides, numSegments, flag));
            return(mesh);
        }
 public static Mesh GenerateConeZ_Angle(float lengthZ, float coneAngle, int numSides, int numSegments, bool cap)
 {
     return(MeshGenerator.GenerateConeZ_RadiusAndAngle(lengthZ, 0f, coneAngle, numSides, numSegments, cap));
 }
예제 #8
0
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            Header("Beam Geometry");
            EditorGUI.BeginChangeCheck();
            {
                using (new EditorGUILayout.HorizontalScope())
                {
                    geometryOverrideLayer.boolValue = EditorGUILayout.Toggle(EditorStrings.ConfigGeometryOverrideLayer, geometryOverrideLayer.boolValue);
                    using (new EditorGUI.DisabledGroupScope(!geometryOverrideLayer.boolValue))
                    {
                        geometryLayerID.intValue = EditorGUILayout.LayerField(geometryLayerID.intValue);
                    }
                }

                geometryTag.stringValue = EditorGUILayout.TagField(EditorStrings.ConfigGeometryTag, geometryTag.stringValue);
            }

            Header("Rendering");
            {
                RenderQueueGUIDraw();

                EditorGUI.BeginChangeCheck();
                {
                    EditorGUILayout.PropertyField(renderingMode, EditorStrings.ConfigGeometryRenderingMode);

#pragma warning disable 0162 // warning CS0162: Unreachable code detected
                    if (renderingMode.intValue == (int)RenderingMode.GPUInstancing && !GpuInstancing.isSupported)
                    {
                        EditorGUILayout.HelpBox(EditorStrings.ConfigGeometryGpuInstancingNotSupported, MessageType.Warning);
                    }
#pragma warning restore 0162
                }
                if (EditorGUI.EndChangeCheck())
                {
                    VolumetricLightBeam._EditorSetAllBeamGeomDirty(); // need to fully reset the BeamGeom to update the shader
                    GlobalMesh.Destroy();
                }
            }
            if (EditorGUI.EndChangeCheck())
            {
                VolumetricLightBeam._EditorSetAllMeshesDirty();
            }

            Header("Shared Mesh");
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(sharedMeshSides, EditorStrings.ConfigSharedMeshSides);
            EditorGUILayout.PropertyField(sharedMeshSegments, EditorStrings.ConfigSharedMeshSegments);
            if (EditorGUI.EndChangeCheck())
            {
                GlobalMesh.Destroy();
                VolumetricLightBeam._EditorSetAllMeshesDirty();
            }

            var meshInfo = "These properties will change the mesh tessellation of each Volumetric Light Beam with 'Shared' MeshType.\nAdjust them carefully since they could impact performance.";
            meshInfo += string.Format("\nShared Mesh stats: {0} vertices, {1} triangles", MeshGenerator.GetSharedMeshVertexCount(), MeshGenerator.GetSharedMeshIndicesCount() / 3);
            EditorGUILayout.HelpBox(meshInfo, MessageType.Info);

            Header("Global 3D Noise");
            EditorGUILayout.PropertyField(globalNoiseScale, EditorStrings.ConfigGlobalNoiseScale);
            EditorGUILayout.PropertyField(globalNoiseVelocity, EditorStrings.ConfigGlobalNoiseVelocity);

            EditorGUILayout.Separator();
            EditorExtensions.HorizontalLineSeparator();

            Header("Internal Data (do not change)");
            EditorGUILayout.PropertyField(beamShader1Pass, EditorStrings.ConfigBeamShader1Pass);
            EditorGUILayout.PropertyField(beamShader2Pass, EditorStrings.ConfigBeamShader2Pass);
            EditorGUILayout.PropertyField(dustParticlesPrefab, EditorStrings.ConfigDustParticlesPrefab);

            bool reloadNoise = false;
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(noise3DData, EditorStrings.ConfigNoise3DData);
            EditorGUILayout.PropertyField(noise3DSize, EditorStrings.ConfigNoise3DSize);
            if (EditorGUI.EndChangeCheck())
            {
                reloadNoise = true;
            }

            if (Noise3D.isSupported && !Noise3D.isProperlyLoaded)
            {
                EditorGUILayout.HelpBox(EditorStrings.HelpNoiseLoadingFailed, MessageType.Error);
            }


            EditorGUILayout.Separator();
            EditorExtensions.HorizontalLineSeparator();
            EditorGUILayout.Separator();

            using (new EditorGUILayout.HorizontalScope())
            {
                if (GUILayout.Button(EditorStrings.ConfigOpenDocumentation, EditorStyles.miniButton))
                {
                    UnityEditor.Help.BrowseURL(Consts.HelpUrlConfig);
                }

                if (GUILayout.Button(EditorStrings.ConfigResetToDefaultButton, EditorStyles.miniButton))
                {
                    UnityEditor.Undo.RecordObject(target, "Reset Config Properties");
                    (target as Config).Reset();
                }
            }

            serializedObject.ApplyModifiedProperties();

            if (reloadNoise)
            {
                Noise3D._EditorForceReloadData(); // Should be called AFTER ApplyModifiedProperties so the Config instance has the proper values when reloading data
            }
        }
예제 #9
0
        public static Mesh GenerateConeZ_Radius(
            float lengthZ,
            float radiusStart,
            float radiusEnd,
            int numSides,
            int numSegments,
            bool cap)
        {
            Debug.Assert((double)lengthZ > 0.0);
            Debug.Assert((double)radiusStart >= 0.0);
            Debug.Assert(numSides >= 3);
            Debug.Assert(numSegments >= 0);
            Mesh mesh    = new Mesh();
            bool geomCap = cap && (double)radiusStart > 0.0;

            radiusStart = Mathf.Max(radiusStart, 1f / 1000f);
            int num1    = numSides * (numSegments + 2);
            int length1 = num1;

            if (geomCap)
            {
                length1 += numSides + 1;
            }
            Vector3[] vector3Array1 = new Vector3[length1];
            for (int index1 = 0; index1 < numSides; ++index1)
            {
                double num2 = 6.28318548202515 * (double)index1 / (double)numSides;
                float  num3 = Mathf.Cos((float)num2);
                float  num4 = Mathf.Sin((float)num2);
                for (int index2 = 0; index2 < numSegments + 2; ++index2)
                {
                    float num5 = (float)index2 / (float)(numSegments + 1);
                    Debug.Assert((double)num5 >= 0.0 && (double)num5 <= 1.0);
                    float num6 = Mathf.Lerp(radiusStart, radiusEnd, num5);
                    vector3Array1[index1 + index2 * numSides] = new Vector3(num6 * num3, num6 * num4, num5 * lengthZ);
                }
            }
            if (geomCap)
            {
                int index1 = num1;
                vector3Array1[index1] = Vector3.get_zero();
                int index2 = index1 + 1;
                for (int index3 = 0; index3 < numSides; ++index3)
                {
                    double num2 = 6.28318548202515 * (double)index3 / (double)numSides;
                    float  num3 = Mathf.Cos((float)num2);
                    float  num4 = Mathf.Sin((float)num2);
                    vector3Array1[index2] = new Vector3(radiusStart * num3, radiusStart * num4, 0.0f);
                    ++index2;
                }
                Debug.Assert(index2 == vector3Array1.Length);
            }
            if (!MeshGenerator.duplicateBackFaces)
            {
                mesh.set_vertices(vector3Array1);
            }
            else
            {
                Vector3[] vector3Array2 = new Vector3[vector3Array1.Length * 2];
                vector3Array1.CopyTo((Array)vector3Array2, 0);
                vector3Array1.CopyTo((Array)vector3Array2, vector3Array1.Length);
                mesh.set_vertices(vector3Array2);
            }
            Vector2[] vector2Array1 = new Vector2[length1];
            int       num7          = 0;

            for (int index = 0; index < num1; ++index)
            {
                vector2Array1[num7++] = Vector2.get_zero();
            }
            if (geomCap)
            {
                for (int index = 0; index < numSides + 1; ++index)
                {
                    vector2Array1[num7++] = new Vector2(1f, 0.0f);
                }
            }
            Debug.Assert(num7 == vector2Array1.Length);
            if (!MeshGenerator.duplicateBackFaces)
            {
                mesh.set_uv(vector2Array1);
            }
            else
            {
                Vector2[] vector2Array2 = new Vector2[vector2Array1.Length * 2];
                vector2Array1.CopyTo((Array)vector2Array2, 0);
                vector2Array1.CopyTo((Array)vector2Array2, vector2Array1.Length);
                for (int index = 0; index < vector2Array1.Length; ++index)
                {
                    Vector2 vector2 = vector2Array2[index + vector2Array1.Length];
                    vector2Array2[index + vector2Array1.Length] = new Vector2((float)vector2.x, 1f);
                }
                mesh.set_uv(vector2Array2);
            }
            int length2 = numSides * 2 * Mathf.Max(numSegments + 1, 1) * 3;

            if (geomCap)
            {
                length2 += numSides * 3;
            }
            int[] numArray1 = new int[length2];
            int   num8      = 0;

            for (int index1 = 0; index1 < numSides; ++index1)
            {
                int num2 = index1 + 1;
                if (num2 == numSides)
                {
                    num2 = 0;
                }
                for (int index2 = 0; index2 < numSegments + 1; ++index2)
                {
                    int   num3      = index2 * numSides;
                    int[] numArray2 = numArray1;
                    int   index3    = num8;
                    int   num4      = index3 + 1;
                    int   num5      = num3 + index1;
                    numArray2[index3] = num5;
                    int[] numArray3 = numArray1;
                    int   index4    = num4;
                    int   num6      = index4 + 1;
                    int   num9      = num3 + num2;
                    numArray3[index4] = num9;
                    int[] numArray4 = numArray1;
                    int   index5    = num6;
                    int   num10     = index5 + 1;
                    int   num11     = num3 + index1 + numSides;
                    numArray4[index5] = num11;
                    int[] numArray5 = numArray1;
                    int   index6    = num10;
                    int   num12     = index6 + 1;
                    int   num13     = num3 + num2 + numSides;
                    numArray5[index6] = num13;
                    int[] numArray6 = numArray1;
                    int   index7    = num12;
                    int   num14     = index7 + 1;
                    int   num15     = num3 + index1 + numSides;
                    numArray6[index7] = num15;
                    int[] numArray7 = numArray1;
                    int   index8    = num14;
                    num8 = index8 + 1;
                    int num16 = num3 + num2;
                    numArray7[index8] = num16;
                }
            }
            if (geomCap)
            {
                for (int index1 = 0; index1 < numSides - 1; ++index1)
                {
                    int[] numArray2 = numArray1;
                    int   index2    = num8;
                    int   num2      = index2 + 1;
                    int   num3      = num1;
                    numArray2[index2] = num3;
                    int[] numArray3 = numArray1;
                    int   index3    = num2;
                    int   num4      = index3 + 1;
                    int   num5      = num1 + index1 + 2;
                    numArray3[index3] = num5;
                    int[] numArray4 = numArray1;
                    int   index4    = num4;
                    num8 = index4 + 1;
                    int num6 = num1 + index1 + 1;
                    numArray4[index4] = num6;
                }
                int[] numArray5 = numArray1;
                int   index5    = num8;
                int   num9      = index5 + 1;
                int   num10     = num1;
                numArray5[index5] = num10;
                int[] numArray6 = numArray1;
                int   index6    = num9;
                int   num11     = index6 + 1;
                int   num12     = num1 + 1;
                numArray6[index6] = num12;
                int[] numArray7 = numArray1;
                int   index7    = num11;
                num8 = index7 + 1;
                int num13 = num1 + numSides;
                numArray7[index7] = num13;
            }
            Debug.Assert(num8 == numArray1.Length);
            if (!MeshGenerator.duplicateBackFaces)
            {
                mesh.set_triangles(numArray1);
            }
            else
            {
                int[] numArray2 = new int[numArray1.Length * 2];
                numArray1.CopyTo((Array)numArray2, 0);
                for (int index = 0; index < numArray1.Length; index += 3)
                {
                    numArray2[numArray1.Length + index]     = numArray1[index] + length1;
                    numArray2[numArray1.Length + index + 1] = numArray1[index + 2] + length1;
                    numArray2[numArray1.Length + index + 2] = numArray1[index + 1] + length1;
                }
                mesh.set_triangles(numArray2);
            }
            Bounds bounds;

            ((Bounds) ref bounds).\u002Ector(new Vector3(0.0f, 0.0f, lengthZ * 0.5f), new Vector3(Mathf.Max(radiusStart, radiusEnd) * 2f, Mathf.Max(radiusStart, radiusEnd) * 2f, lengthZ));
            mesh.set_bounds(bounds);
            Debug.Assert(mesh.get_vertexCount() == MeshGenerator.GetVertexCount(numSides, numSegments, geomCap));
            Debug.Assert(mesh.get_triangles().Length == MeshGenerator.GetIndicesCount(numSides, numSegments, geomCap));
            return(mesh);
        }
예제 #10
0
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            Header("Beam Geometry");
            EditorGUI.BeginChangeCheck();
            {
                geometryLayerID.intValue = EditorGUILayout.LayerField(EditorStrings.ConfigGeometryLayerID, geometryLayerID.intValue);
                geometryTag.stringValue  = EditorGUILayout.TagField(EditorStrings.ConfigGeometryTag, geometryTag.stringValue);
                RenderQueueGUIDraw();

                EditorGUI.BeginChangeCheck();
                {
                    forceSinglePass.ToggleLeft(EditorStrings.ConfigGeometryForceSinglePass);
                }
                if (EditorGUI.EndChangeCheck())
                {
                    VolumetricLightBeam._EditorSetAllBeamGeomDirty(); // need to fully reset the BeamGeom to update the shader
                    GlobalMesh.Destroy();
                }
            }
            if (EditorGUI.EndChangeCheck())
            {
                VolumetricLightBeam._EditorSetAllMeshesDirty();
            }

            EditorGUILayout.PropertyField(beamShader1Pass, EditorStrings.ConfigBeamShader1Pass);
            EditorGUILayout.PropertyField(beamShader2Pass, EditorStrings.ConfigBeamShader2Pass);

            Header("Shared Mesh");
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(sharedMeshSides, EditorStrings.ConfigSharedMeshSides);
            EditorGUILayout.PropertyField(sharedMeshSegments, EditorStrings.ConfigSharedMeshSegments);
            if (EditorGUI.EndChangeCheck())
            {
                GlobalMesh.Destroy();
                VolumetricLightBeam._EditorSetAllMeshesDirty();
            }

            var meshInfo = "These properties will change the mesh tessellation of each Volumetric Light Beam with 'Shared' MeshType.\nAdjust them carefully since they could impact performance.";

            meshInfo += string.Format("\nShared Mesh stats: {0} vertices, {1} triangles", MeshGenerator.GetSharedMeshVertexCount(), MeshGenerator.GetSharedMeshIndicesCount() / 3);
            EditorGUILayout.HelpBox(meshInfo, MessageType.Info);

            Header("Global 3D Noise");
            EditorGUILayout.PropertyField(globalNoiseScale, EditorStrings.ConfigGlobalNoiseScale);
            EditorGUILayout.PropertyField(globalNoiseVelocity, EditorStrings.ConfigGlobalNoiseVelocity);

            Header("3D Noise Texture Data");
            bool reloadNoise = false;

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(noise3DData, EditorStrings.ConfigNoise3DData);
            EditorGUILayout.PropertyField(noise3DSize, EditorStrings.ConfigNoise3DSize);
            if (EditorGUI.EndChangeCheck())
            {
                reloadNoise = true;
            }

            if (Noise3D.isSupported && !Noise3D.isProperlyLoaded)
            {
                EditorGUILayout.HelpBox(EditorStrings.HelpNoiseLoadingFailed, MessageType.Error);
            }

            Header("Volumetric Dust Particles");
            EditorGUILayout.PropertyField(dustParticlesPrefab, EditorStrings.ConfigDustParticlesPrefab);

            EditorGUILayout.Separator();
            EditorExtensions.HorizontalLineSeparator();
            EditorGUILayout.Separator();

            if (GUILayout.Button(EditorStrings.ConfigResetToDefaultButton, EditorStyles.miniButton))
            {
                UnityEditor.Undo.RecordObject(target, "Reset Config Properties");
                (target as Config).Reset();
            }

            serializedObject.ApplyModifiedProperties();

            if (reloadNoise)
            {
                Noise3D._EditorForceReloadData(); // Should be called AFTER ApplyModifiedProperties so the Config instance has the proper values when reloading data
            }
        }