private void SetupAreaLight(Light light) { BakeryLightMesh bakeryLightMesh = light.GetComponent <BakeryLightMesh>(); if (bakeryLightMesh == null) { bakeryLightMesh = light.gameObject.AddComponent <BakeryLightMesh>(); } if (PlayerSettings.colorSpace != ColorSpace.Linear) { bakeryLightMesh.color = light.color; bakeryLightMesh.intensity = light.intensity; } else if (!GraphicsSettings.lightsUseLinearIntensity) { float lightR, lightG, lightB, lightInt; GetLinearLightParameters(light, out lightR, out lightG, out lightB, out lightInt); bakeryLightMesh.color = new Color(lightR, lightG, lightB); bakeryLightMesh.intensity = lightInt; } else { bakeryLightMesh.color = light.color; bakeryLightMesh.intensity = light.intensity; } bakeryLightMesh.samples = meshSamples[1]; bakeryLightMesh.samples2 = meshSamples[0]; bakeryLightMesh.cutoff = light.range * 1.5f; bakeryLightMesh.selfShadow = false; bakeryLightMesh.bitmask = 1; bakeryLightMesh.indirectIntensity = light.bounceIntensity; }
static public void BuildLight(BakeryLightMesh obj, int SAMPLES, string outName = "lights.bin") { if (!allowOverwrite && lightSaved.ContainsKey(outName)) { return; } lightSaved[outName] = true; var folder = ftBuildGraphics.scenePath;//Directory.GetParent(Application.dataPath).FullName + "/frender"; if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } var f = new BinaryWriter(File.Open(folder + "/" + outName, FileMode.Create)); f.Write(1); var mesh = obj.GetComponent <MeshFilter>().sharedMesh; var tform = obj.transform; var verts = mesh.vertices; var indices = mesh.triangles; int tris = indices.Length / 3; float[] area = new float[tris]; #if (OPTIMIZEDAREA || OPTIMIZEDAREA2) #else float minArea = float.MaxValue; float maxArea = -float.MaxValue; #endif float totalWorldArea = 0; Vector2[] uv = null; int downsampleRes = 0; float[] pixels = null; string texName = ""; if (obj.texture != null) { uv = mesh.uv; var tex = obj.texture; // Save original texture to RGBA32F DDS int existingTexHash; if (!tex2hash.TryGetValue(tex, out existingTexHash)) { existingTexHash = -1; } if (existingTexHash < 0) { int texHash = tex.GetHashCode(); tex2hash[tex] = texHash; existingTexHash = texHash; } texName = "areatex_" + existingTexHash; ftBuildGraphics.InitShaders(); ftBuildGraphics.SaveCookie(tex.GetNativeTexturePtr(), folder + "/" + texName + ".dds" ); GL.IssuePluginEvent(4); // Get downsampled (via mips) texture downsampleRes = (int)Mathf.Sqrt(SAMPLES); if (downsampleRes == 0) { downsampleRes = 1; } var downsampleRT = new RenderTexture(downsampleRes, downsampleRes, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear); var downsampleTex = new Texture2D(downsampleRes, downsampleRes, TextureFormat.RGBAFloat, false, true); Graphics.Blit(tex, downsampleRT); Graphics.SetRenderTarget(downsampleRT); downsampleTex.ReadPixels(new Rect(0, 0, downsampleRes, downsampleRes), 0, 0, false); downsampleTex.Apply(); var bytes = downsampleTex.GetRawTextureData(); pixels = new float[bytes.Length / 4]; System.Buffer.BlockCopy(bytes, 0, pixels, 0, bytes.Length); } for (int j = 0; j < tris; j++) { var v1 = verts[indices[j * 3]]; var v2 = verts[indices[j * 3 + 1]]; var v3 = verts[indices[j * 3 + 2]]; v1 = tform.TransformPoint(v1); v2 = tform.TransformPoint(v2); v3 = tform.TransformPoint(v3); #if (OPTIMIZEDAREA || OPTIMIZEDAREA2) area[j] = Vector3.Cross(v2 - v1, v3 - v1).magnitude; if (area[j] > 0) { totalWorldArea += area[j]; } #else area[j] = Vector3.Cross(v2 - v1, v3 - v1).magnitude; if (area[j] > 0) { totalWorldArea += area[j]; } if (area[j] > 0) { minArea = Mathf.Min(minArea, area[j]); maxArea = Mathf.Max(maxArea, area[j]); } #endif } #if OPTIMIZEDAREA2 // New 2 var randomTriIndices = new int[SAMPLES]; float invTotalArea = 1.0f / (totalWorldArea * 0.5f); float sumWeights = 0.0f; for (int j = 0; j < tris; j++) { area[j] *= invTotalArea * 0.5f; sumWeights += area[j]; } float sampleWidth = sumWeights / SAMPLES; int outputSampleIx = -1; float weightSoFar = -Random.value * sampleWidth; for (int i = 0; i < SAMPLES; i++) { float sampleDist = i * sampleWidth; while (sampleDist >= weightSoFar && outputSampleIx + 1 < tris) { weightSoFar += area[++outputSampleIx]; } randomTriIndices[i] = outputSampleIx; } #elif OPTIMIZEDAREA // New // Collect indices to triangles var triIndices = new int[tris]; float invTotalArea = 1.0f / (totalWorldArea * 0.5f); for (int j = 0; j < tris; j++) { area[j] *= invTotalArea * 0.5f; triIndices[j] = j; } // Sort triangle indices by area (probability) // Smaller -> Larger System.Array.Sort(triIndices, delegate(int a, int b) { return(area[a].CompareTo(area[b])); }); // Put triangle indices into a BSP tree based on area int start = 0; int end = triIndices.Length - 1; //var bspLayers = new List<int[]>(); // tri index array per depth level var bspRoot = BuildProbabilityBSP(triIndices, area, start, end, 0, 0.0f, 1.0f); #else // Legacy if (maxArea / minArea > 65535) { minArea = maxArea / 65535; } float invMinArea = 1.0f / minArea; for (int j = 0; j < tris; j++) { area[j] *= invMinArea; area[j] = Mathf.Round(area[j]); } int skipped = 0; var uniformTriList = new List <int>(); for (int j = 0; j < tris; j++) { var tarea = area[j]; if (tarea > 0 && tarea < 65536) { for (int k = 0; k < tarea; k++) { uniformTriList.Add(j); } } else { skipped++; } } if (skipped > 0) { Debug.LogError("Skipped " + skipped + " invalid triangles out of " + tris + " on LightMesh " + obj.name + " (area is too big?)"); } #endif f.Write(obj.samples2); f.Write(SAMPLES); Vector3 trinormal; for (int sample = 0; sample < SAMPLES; sample++) { #if OPTIMIZEDAREA2 int tri = randomTriIndices[sample]; #elif OPTIMIZEDAREA int tri = GetRandomTriFromBSP(bspRoot, Random.value); //Debug.LogError(tri); #else int rndTri = Random.Range(0, uniformTriList.Count); int tri = uniformTriList.Count > 0 ? uniformTriList[rndTri] : 0; #endif var rndA = Random.value; var rndB = Random.value; var rndC = Random.value; var A = verts[indices[tri * 3]]; var B = verts[indices[tri * 3 + 1]]; var C = verts[indices[tri * 3 + 2]]; var point = (1.0f - Mathf.Sqrt(rndA)) * A + (Mathf.Sqrt(rndA) * (1.0f - rndB)) * B + (Mathf.Sqrt(rndA) * rndB) * C; point = tform.TransformPoint(point); trinormal = Vector3.Cross(A - B, B - C).normalized; trinormal = tform.TransformDirection(trinormal); point += trinormal * 0.001f; f.Write(point.x); f.Write(point.y); f.Write(point.z); f.Write(trinormal.x); f.Write(trinormal.y); f.Write(trinormal.z); if (obj.texture != null) { var tA = uv[indices[tri * 3]]; var tB = uv[indices[tri * 3 + 1]]; var tC = uv[indices[tri * 3 + 2]]; var tpoint = (1.0f - Mathf.Sqrt(rndA)) * tA + (Mathf.Sqrt(rndA) * (1.0f - rndB)) * tB + (Mathf.Sqrt(rndA) * rndB) * tC; int tx = (int)(tpoint.x * (downsampleRes - 1)); int ty = (int)(tpoint.y * (downsampleRes - 1)); int pixelIndex = ty * downsampleRes + tx; if (pixelIndex * 4 + 2 < pixels.Length) { float cr = pixels[pixelIndex * 4]; float cg = pixels[pixelIndex * 4 + 1]; float cb = pixels[pixelIndex * 4 + 2]; f.Write(cr); f.Write(cg); f.Write(cb); } else { f.Write(0.0f); f.Write(0.0f); f.Write(0.0f); } } //var g = GameObject.CreatePrimitive(PrimitiveType.Sphere); //g.transform.position = point; //g.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f); } f.Write(obj.cutoff); f.Write(totalWorldArea * 0.5f); #if SRGBCONVERT f.Write(obj.color.linear.r * obj.intensity); f.Write(obj.color.linear.g * obj.intensity); f.Write(obj.color.linear.b * obj.intensity); #else f.Write(obj.color.r * obj.intensity); f.Write(obj.color.g * obj.intensity); f.Write(obj.color.b * obj.intensity); #endif f.Write(obj.lmid); if (obj.texture != null) { f.Write(texName + ".dds"); } f.Close(); }