// this is the delegate we're going to return to apply a brush stamp. Your passed a paint job,
      // which contains important cached information to make painting fast, and hold the actual stream data. 
      // the index is the index into the vertex array, the val is the brush data we supplied in GetBrushObject,
      // and r is a 0 to 1 with how far to tween the value towards the brush (brush pressure * deltatime)
      void LerpFunc(VertexPainterWindow.PaintJob j, int idx, ref object val, float r)
      {
         // retrieve our brush data and get the stream we're painting into
         BrushData bd = val as BrushData;
         var s = j.stream;
         // use our vertex position to generate noise. We use the get position function because it will
         // return a vert position from the original meshes cached verticies or modified verticies if
         // we've modified them. This makes it compatible with deformations, etc. 
         Vector3 pos = j.GetPosition(idx);
         // convert into world space
         pos = j.renderer.localToWorldMatrix.MultiplyPoint(pos);
         // scale by frequency
         pos.x *= bd.frequency;
         pos.y *= bd.frequency;
         pos.z *= bd.frequency;
         float noise = 0.5f * (0.5f * JBooth.VertexPainterPro.SimplexNoise.Noise.Generate(pos.x, pos.y, pos.z) + 0.5f);
         noise += 0.25f * (0.5f * JBooth.VertexPainterPro.SimplexNoise.Noise.Generate(pos.y * 2.031f, pos.z * 2.031f, pos.x * 2.031f) + 0.5f);
         noise += 0.25f * (0.5f * JBooth.VertexPainterPro.SimplexNoise.Noise.Generate(pos.z * 4.01f, pos.x * 4.01f, pos.y * 4.01f) + 0.5f);
         noise *= bd.amplitude;
         // lerp the noise in
         Color c = s.colors[idx];
         c.r = Mathf.Lerp(c.r, noise, r);
         c.g = Mathf.Lerp(c.g, noise, r);
         c.b = Mathf.Lerp(c.b, noise, r);

         s.colors[idx] = c;
      }
Esempio n. 2
0
        public void OnGUI(PaintJob[] jobs)
        {
            var window = VertexPainterWindow.GetWindow <VertexPainterWindow>();

            window.brushMode = (VertexPainterWindow.BrushTarget)EditorGUILayout.EnumPopup("Target Channel", window.brushMode);
            aoOneMinusColor  = EditorGUILayout.Toggle("Color Inverse (1-v)", aoOneMinusColor);
            aoSamples        = EditorGUILayout.IntSlider("Samples", aoSamples, 64, 1024);
            EditorGUILayout.BeginHorizontal();
            aoRange   = EditorGUILayout.Vector2Field("Range (Min, Max)", aoRange);
            aoRange.x = Mathf.Max(aoRange.x, 0.0001f);
            EditorGUILayout.EndHorizontal();
            aoIntensity  = EditorGUILayout.Slider("Intensity", aoIntensity, 0.25f, 4.0f);
            bakeLighting = EditorGUILayout.Toggle("Bake Lighting", bakeLighting);
            if (bakeLighting)
            {
                aoLightAmbient = EditorGUILayout.ColorField("Light Ambient", aoLightAmbient);
            }
            aoBakeMode = (AOBakeMode)EditorGUILayout.EnumPopup("Mode", aoBakeMode);
            //aoColliderList = EditorGUILayout.ObjectField(aoColliderList);
            EditorGUILayout.LabelField("Colliders: " + aoColliderList.Count.ToString());
            foreach (var go in aoColliderList)
            {
                EditorGUILayout.ObjectField("", go, typeof(GameObject), false);
            }
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Add Selected Object"))
            {
                aoColliderList.AddRange(Selection.gameObjects);
            }
            if (GUILayout.Button("Clear"))
            {
                aoColliderList.Clear();
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            if (GUILayout.Button("Bake"))
            {
                DoBakeAO(jobs, window);
            }
        }
Esempio n. 3
0
        public void OnGUI(PaintJob[] jobs)
        {
            var window = VertexPainterWindow.GetWindow <VertexPainterWindow>();

            window.brushMode = (VertexPainterWindow.BrushTarget)EditorGUILayout.EnumPopup("Target Channel", window.brushMode);
            aoSamples        = EditorGUILayout.IntSlider("Samples", aoSamples, 64, 1024);
            EditorGUILayout.BeginHorizontal();
            aoRange   = EditorGUILayout.Vector2Field("Range (Min, Max)", aoRange);
            aoRange.x = Mathf.Max(aoRange.x, 0.0001f);
            EditorGUILayout.EndHorizontal();
            aoIntensity  = EditorGUILayout.Slider("Intensity", aoIntensity, 0.25f, 4.0f);
            bakeLighting = EditorGUILayout.Toggle("Bake Lighting", bakeLighting);
            if (bakeLighting)
            {
                aoLightAmbient = EditorGUILayout.ColorField("Light Ambient", aoLightAmbient);
            }
            aoBakeMode = (AOBakeMode)EditorGUILayout.EnumPopup("Mode", aoBakeMode);

            EditorGUILayout.Space();
            if (GUILayout.Button("Bake"))
            {
                DoBakeAO(jobs, window);
            }
        }
Esempio n. 4
0
        void DoBakeAO(PaintJob[] jobs, VertexPainterWindow window)
        {
            Light[] aoLights = null;
             if (bakeLighting)
             {
            aoLights = GameObject.FindObjectsOfType<Light>();
             }
             int sample = 0;
             int numVerts = 0;
             for (int i = 0; i < jobs.Length; ++i)
             {
            numVerts += jobs[i].verts.Length;
             }
             int numSamples = numVerts * aoSamples;

             float oldFloat = window.floatBrushValue;
             Color oldColor = window.brushColor;
             int oldVal = window.brushValue;

             // add temp colliders if needed
             bool[] tempCollider = new bool[jobs.Length];
             for (int jIdx = 0; jIdx < jobs.Length; ++jIdx)
             {
            PaintJob job = jobs[jIdx];

            if (job.meshFilter.GetComponent<Collider>() == null)
            {
               job.meshFilter.gameObject.AddComponent<MeshCollider>();
               tempCollider[jIdx] = true;
            }
             }

             // do AO
             for (int jIdx = 0; jIdx < jobs.Length; ++jIdx)
             {
            PaintJob job = jobs[jIdx];

            window.PrepBrushMode(job);
            // bake down the mesh so we take instance positions into account..
            Mesh mesh = VertexPainterUtilities.BakeDownMesh(job.meshFilter.sharedMesh, job.stream);
            Vector3[] verts = mesh.vertices;
            if (mesh.normals == null || mesh.normals.Length == 0)
            {
               mesh.RecalculateNormals();
            }
            Vector3[] normals = mesh.normals;

            window.brushValue = 255;
            window.floatBrushValue = 1.0f;
            window.brushColor = Color.white;
            var val = window.GetBrushValue();
            VertexPainterWindow.Lerper lerper = null;
            VertexPainterWindow.Multiplier mult = null;

            if (aoBakeMode == AOBakeMode.Replace)
            {
               lerper = window.GetLerper();
               for (int i = 0; i < job.verts.Length; ++i)
               {
                  lerper.Invoke(job, i, ref val, 1);
               }
            }
            else
            {
               mult = window.GetMultiplier();
            }

            for (int i = 0; i<verts.Length; i++)
            {
               Vector3 norm = normals[i];
               // to world space!
               Vector3 v = job.meshFilter.transform.TransformPoint(verts[i]);
               Vector3 n = job.meshFilter.transform.TransformPoint(verts[i] + norm);
               Vector3 worldSpaceNormal = (n-v).normalized;

               float totalOcclusion = 0;

               // the slow part..
               for (int j = 0; j < aoSamples; j++)
               {
                  // random rotate around hemisphere
                  float rot = 180.0f;
                  float rot2 = rot / 2.0f;
                  float rotx = (( rot * Random.value ) - rot2);
                  float roty = (( rot * Random.value ) - rot2);
                  float rotz = (( rot * Random.value ) - rot2);

                  Vector3 dir = Quaternion.Euler( rotx, roty, rotz ) * Vector3.up;
                  Quaternion dirq = Quaternion.FromToRotation(Vector3.up, worldSpaceNormal);
                  Vector3 ray = dirq * dir;
                  Vector3 offset = Vector3.Reflect( ray, worldSpaceNormal );

                  // raycast
                  ray = ray * (aoRange.y/ray.magnitude);
                  if ( Physics.Linecast( v-(offset*0.1f), v + ray, out hit ) )
                  {
                     if ( hit.distance > aoRange.x )
                     {
                        totalOcclusion += Mathf.Clamp01( 1 - ( hit.distance / aoRange.y ) );
                     }
                  }

                  sample++;
                  if (sample % 500 == 0)
                  {
                     EditorUtility.DisplayProgressBar("Baking AO...", "Baking...", (float)sample / (float)numSamples);
                  }
               }

               totalOcclusion = Mathf.Clamp01( 1 - ((totalOcclusion*aoIntensity)/aoSamples) );

               if (aoLights != null && aoLights.Length > 0)
               {
                  Color c = aoLightAmbient;
                  for (int l = 0; l < aoLights.Length; ++l)
                  {
                     Light light = aoLights[l];
                     ApplyAOLight(ref c, light, v, n);
                  }
                  c.r *= totalOcclusion;
                  c.g *= totalOcclusion;
                  c.b *= totalOcclusion;
                  c.a = totalOcclusion;
                  window.brushColor = c;

                  // if we're lit and targeting a channel other than color, bake max intensity..
                  window.floatBrushValue = Mathf.Max(Mathf.Max(c.r, c.g), c.b) * totalOcclusion;
                  window.brushValue = (int)(window.floatBrushValue * 255);
               }
               else
               {
                  window.brushColor.r = totalOcclusion;
                  window.brushColor.g = totalOcclusion;
                  window.brushColor.b = totalOcclusion;
                  window.brushColor.a = totalOcclusion;

                  window.floatBrushValue = totalOcclusion;
                  window.brushValue = (int)(totalOcclusion * 255);
               }
               val = window.GetBrushValue();
               if (aoBakeMode == AOBakeMode.Replace)
               {
                  lerper.Invoke(job, i, ref val, 1);
               }
               else
               {
                  mult.Invoke(job.stream, i, ref val);
               }
            }
            job.stream.Apply();
            EditorUtility.SetDirty(job.stream);
            EditorUtility.SetDirty(job.stream.gameObject);
            GameObject.DestroyImmediate(mesh);

            window.brushValue = oldVal;
            window.floatBrushValue = oldFloat;
            window.brushColor = oldColor;
             }
             // remove temp colliders
             for (int jIdx = 0; jIdx < jobs.Length; ++jIdx)
             {
            if (tempCollider[jIdx] == true)
            {
               Collider c = jobs[jIdx].meshFilter.GetComponent<Collider>();
               if (c != null)
               {
                  GameObject.DestroyImmediate(c);
               }
            }
             }

             EditorUtility.ClearProgressBar();
             SceneView.RepaintAll();
        }
Esempio n. 5
0
        void DoBakeAO(PaintJob[] jobs, VertexPainterWindow window)
        {
            Light[] aoLights = null;
            if (bakeLighting)
            {
                aoLights = GameObject.FindObjectsOfType <Light>();
            }
            int sample   = 0;
            int numVerts = 0;

            for (int i = 0; i < jobs.Length; ++i)
            {
                numVerts += jobs[i].verts.Length;
            }
            int numSamples = numVerts * aoSamples;

            float oldFloat = window.floatBrushValue;
            Color oldColor = window.brushColor;
            int   oldVal   = window.brushValue;

            // add temp colliders if needed
            bool[] tempCollider = new bool[jobs.Length];
            for (int jIdx = 0; jIdx < jobs.Length; ++jIdx)
            {
                PaintJob job = jobs[jIdx];

                if (job.meshFilter.GetComponent <Collider>() == null)
                {
                    job.meshFilter.gameObject.AddComponent <MeshCollider>();
                    tempCollider[jIdx] = true;
                }
            }

            // do AO
            for (int jIdx = 0; jIdx < jobs.Length; ++jIdx)
            {
                PaintJob job = jobs[jIdx];

                window.PrepBrushMode(job);
                // bake down the mesh so we take instance positions into account..
                Mesh      mesh  = VertexPainterUtilities.BakeDownMesh(job.meshFilter.sharedMesh, job.stream);
                Vector3[] verts = mesh.vertices;
                if (mesh.normals == null || mesh.normals.Length == 0)
                {
                    mesh.RecalculateNormals();
                }
                Vector3[] normals = mesh.normals;

                window.brushValue      = 255;
                window.floatBrushValue = 1.0f;
                window.brushColor      = Color.white;
                var val = window.GetBrushValue();
                VertexPainterWindow.Lerper     lerper = null;
                VertexPainterWindow.Multiplier mult   = null;

                if (aoBakeMode == AOBakeMode.Replace)
                {
                    lerper = window.GetLerper();
                    for (int i = 0; i < job.verts.Length; ++i)
                    {
                        lerper.Invoke(job, i, ref val, 1);
                    }
                }
                else
                {
                    mult = window.GetMultiplier();
                }

                for (int i = 0; i < verts.Length; i++)
                {
                    Vector3 norm = normals[i];
                    // to world space!
                    Vector3 v = job.meshFilter.transform.TransformPoint(verts[i]);
                    Vector3 n = job.meshFilter.transform.TransformPoint(verts[i] + norm);
                    Vector3 worldSpaceNormal = (n - v).normalized;

                    float totalOcclusion = 0;

                    // the slow part..
                    for (int j = 0; j < aoSamples; j++)
                    {
                        // random rotate around hemisphere
                        float rot  = 180.0f;
                        float rot2 = rot / 2.0f;
                        float rotx = ((rot * Random.value) - rot2);
                        float roty = ((rot * Random.value) - rot2);
                        float rotz = ((rot * Random.value) - rot2);

                        Vector3    dir    = Quaternion.Euler(rotx, roty, rotz) * Vector3.up;
                        Quaternion dirq   = Quaternion.FromToRotation(Vector3.up, worldSpaceNormal);
                        Vector3    ray    = dirq * dir;
                        Vector3    offset = Vector3.Reflect(ray, worldSpaceNormal);

                        // raycast
                        ray = ray * (aoRange.y / ray.magnitude);
                        if (Physics.Linecast(v - (offset * 0.1f), v + ray, out hit))
                        {
                            if (hit.distance > aoRange.x)
                            {
                                totalOcclusion += Mathf.Clamp01(1 - (hit.distance / aoRange.y));
                            }
                        }

                        sample++;
                        if (sample % 500 == 0)
                        {
                            EditorUtility.DisplayProgressBar("Baking AO...", "Baking...", (float)sample / (float)numSamples);
                        }
                    }

                    totalOcclusion = Mathf.Clamp01(1 - ((totalOcclusion * aoIntensity) / aoSamples));

                    if (aoLights != null && aoLights.Length > 0)
                    {
                        Color c = aoLightAmbient;
                        for (int l = 0; l < aoLights.Length; ++l)
                        {
                            Light light = aoLights[l];
                            ApplyAOLight(ref c, light, v, n);
                        }
                        c.r *= totalOcclusion;
                        c.g *= totalOcclusion;
                        c.b *= totalOcclusion;
                        c.a  = totalOcclusion;
                        window.brushColor = c;

                        // if we're lit and targeting a channel other than color, bake max intensity..
                        window.floatBrushValue = Mathf.Max(Mathf.Max(c.r, c.g), c.b) * totalOcclusion;
                        window.brushValue      = (int)(window.floatBrushValue * 255);
                    }
                    else
                    {
                        window.brushColor.r = totalOcclusion;
                        window.brushColor.g = totalOcclusion;
                        window.brushColor.b = totalOcclusion;
                        window.brushColor.a = totalOcclusion;

                        window.floatBrushValue = totalOcclusion;
                        window.brushValue      = (int)(totalOcclusion * 255);
                    }
                    val = window.GetBrushValue();
                    if (aoBakeMode == AOBakeMode.Replace)
                    {
                        lerper.Invoke(job, i, ref val, 1);
                    }
                    else
                    {
                        mult.Invoke(job.stream, i, ref val);
                    }
                }
                job.stream.Apply();
                EditorUtility.SetDirty(job.stream);
                EditorUtility.SetDirty(job.stream.gameObject);
                GameObject.DestroyImmediate(mesh);

                window.brushValue      = oldVal;
                window.floatBrushValue = oldFloat;
                window.brushColor      = oldColor;
            }
            // remove temp colliders
            for (int jIdx = 0; jIdx < jobs.Length; ++jIdx)
            {
                if (tempCollider[jIdx] == true)
                {
                    Collider c = jobs[jIdx].meshFilter.GetComponent <Collider>();
                    if (c != null)
                    {
                        GameObject.DestroyImmediate(c);
                    }
                }
            }

            EditorUtility.ClearProgressBar();
            SceneView.RepaintAll();
        }