void LerpFunc(PaintJob j, int idx, ref object val, float r) { if (didHit) { j.stream.normals[idx] = Vector3.Lerp(j.stream.normals[idx], normal, r); j.stream.tangents[idx] = Vector4.Lerp(j.stream.tangents[idx], tangent, r); } }
void LerpFunc(PaintJob j, int idx, ref object val, float r) { BrushData bd = val as BrushData; var s = j.stream; Vector3 pos = j.GetPosition(idx); pos = j.renderer.localToWorldMatrix.MultiplyPoint(pos); pos.x *= bd.frequency; pos.y *= bd.frequency; pos.z *= bd.frequency; float noise = 0.5f * (0.5f * ShaderLib.VertexPainter.SimplexNoise.Noise.Generate(pos.x, pos.y, pos.z) + 0.5f); noise += 0.25f * (0.5f * ShaderLib.VertexPainter.SimplexNoise.Noise.Generate(pos.y * 2.031f, pos.z * 2.031f, pos.x * 2.031f) + 0.5f); noise += 0.25f * (0.5f * ShaderLib.VertexPainter.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; }
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(); }