void UpdateLights() { SphericalHarmonics lighting = SphericalHarmonics.FromLights(lights .ConvertAll(a => new SHLight { directionTo = a.pose.position.Normalized(), color = Color.HSV(a.color) * LightIntensity(a.pose.position) }) .ToArray()); Renderer.SkyTex = Tex.GenCubemap(lighting); Renderer.SkyLight = lighting; }
public static void UpdateSH9FormCubeMap(Cubemap ibl, ref Cubemap curIbl, SH9Struct iblData) { if (curIbl != ibl) { if (null == ibl) { iblData.coefficients = new Vector4[0]; } else { SH9Helper.ModifyTextureReadable(ibl); iblData.coefficients = new Vector4[9]; if (SphericalHarmonics.CPU_Project_Uniform_9Coeff(ibl, iblData.coefficients)) { } } curIbl = ibl; } }
public void Initialize() { oldSkyTex = Renderer.SkyTex; oldSkyLight = Renderer.SkyLight; sphereMesh = Mesh.GenerateSphere(1, 5); Renderer.SkyTex = Tex.FromCubemapEquirectangular("old_depot.hdr", out SphericalHarmonics lighting); Renderer.SkyLight = lighting; pbrModel = Model.FromFile("DamagedHelmet.gltf"); pbrMaterials = new Material[materialGrid * materialGrid]; for (int y = 0; y < materialGrid; y++) { for (int x = 0; x < materialGrid; x++) { int i = x + y * materialGrid; pbrMaterials[i] = new Material(Default.ShaderPbr); pbrMaterials[i][MatParamName.ColorTint] = Color.HSV(0.3f, 0.8f, 0.8f); pbrMaterials[i][MatParamName.MetallicAmount] = x / (float)(materialGrid - 1); pbrMaterials[i][MatParamName.RoughnessAmount] = y / (float)(materialGrid - 1); } } /// :CodeSample: Material.GetAllParamInfo Material.GetParamInfo Material.ParamCount MatParamInfo MatParamInfo.name MatParamInfo.type /// ### Listing parameters in a Material // Iterate using a foreach Log.Info("Builtin PBR Materials contain these parameters:"); foreach (MatParamInfo info in Material.PBR.GetAllParamInfo()) { Log.Info($"- {info.name} : {info.type}"); } // Or with a normal for loop Log.Info("Builtin Unlit Materials contain these parameters:"); for (int i = 0; i < Material.Unlit.ParamCount; i += 1) { MatParamInfo info = Material.Unlit.GetParamInfo(i); Log.Info($"- {info.name} : {info.type}"); } /// :End: }
public void Initialize() { oldSkyTex = Renderer.SkyTex; oldSkyLight = Renderer.SkyLight; sphereMesh = Mesh.GenerateSphere(1, 5); Renderer.SkyTex = Tex.FromCubemapEquirectangular("old_depot.hdr", out SphericalHarmonics lighting); Renderer.SkyLight = lighting; pbrModel = Model.FromFile("DamagedHelmet.gltf"); pbrMaterials = new Material[materialGrid * materialGrid]; for (int y = 0; y < materialGrid; y++) { for (int x = 0; x < materialGrid; x++) { int i = x + y * materialGrid; pbrMaterials[i] = new Material(Default.ShaderPbr); pbrMaterials[i][MatParamName.ColorTint] = Color.HSV(0.3f, 0.8f, 0.8f); pbrMaterials[i][MatParamName.MetallicAmount] = x / (float)(materialGrid - 1); pbrMaterials[i][MatParamName.RoughnessAmount] = y / (float)(materialGrid - 1); } } }
public static void UpdateSH9FormCubeMap(Cubemap ibl, ref Cubemap curIbl, SH9Struct iblData) { if (curIbl != ibl) { if (null == ibl) { iblData.coefficients = new Vector4[0]; } else { SH9Helper.ModifyTextureReadable(ibl); iblData.coefficients = new Vector4[9]; if (SphericalHarmonics.CPU_Project_Uniform_9Coeff(ibl, iblData.coefficients)) { /*g_sph0.xyz * 0.2820947917f + * g_sph1.xyz * 0.4886025119f * v.y; * g_sph2.xyz * 0.4886025119f * v.z; * g_sph3.xyz * 0.4886025119f * v.x; * g_sph4.xyz * 1.0925484306f * v.x * v.y; * g_sph5.xyz * 1.0925484306f * v.y * v.z; * g_sph6.xyz * 0.3153915652f * (3.0f * v.z * v.z - 1.0f); * g_sph7.xyz * 1.0925484306f * v.x * v.z; * g_sph8.xyz * 0.5462742153f * (v.x * v.x - v.y * v.y); */ iblData.coefficients[0] = iblData.coefficients[0] * 0.2820947917f; iblData.coefficients[1] = iblData.coefficients[1] * 0.4886025119f; iblData.coefficients[2] = iblData.coefficients[2] * 0.4886025119f; iblData.coefficients[3] = iblData.coefficients[3] * 0.4886025119f; iblData.coefficients[4] = iblData.coefficients[4] * 1.0925484306f; iblData.coefficients[5] = iblData.coefficients[5] * 1.0925484306f; iblData.coefficients[6] = iblData.coefficients[6] * 0.3153915652f; iblData.coefficients[7] = iblData.coefficients[7] * 1.0925484306f; iblData.coefficients[8] = iblData.coefficients[8] * 0.5462742153f; } } curIbl = ibl; } }
protected override void DrawCore(RenderContext context) { var inputTexture = RadianceMap; if (inputTexture == null) return; // Gets and checks the input texture if (inputTexture.Dimension != TextureDimension.TextureCube) throw new NotSupportedException("Only texture cube are currently supported as input of 'LambertianPrefilteringSH' effect."); const int FirstPassBlockSize = 4; const int FirstPassSumsCount = FirstPassBlockSize * FirstPassBlockSize; var faceCount = inputTexture.Dimension == TextureDimension.TextureCube ? 6 : 1; var inputSize = new Int2(inputTexture.Width, inputTexture.Height); // (Note: for cube maps width = height) var coefficientsCount = harmonicalOrder * harmonicalOrder; var sumsToPerfomRemaining = inputSize.X * inputSize.Y * faceCount / FirstPassSumsCount; var partialSumBuffer = NewScopedTypedBuffer(coefficientsCount * sumsToPerfomRemaining, PixelFormat.R32G32B32A32_Float, true); // Project the radiance on the SH basis and sum up the results along the 4x4 blocks firstPassEffect.ThreadNumbers = new Int3(FirstPassBlockSize, FirstPassBlockSize, 1); firstPassEffect.ThreadGroupCounts = new Int3(inputSize.X/FirstPassBlockSize, inputSize.Y/FirstPassBlockSize, faceCount); firstPassEffect.Parameters.Set(LambertianPrefilteringSHParameters.BlockSize, FirstPassBlockSize); firstPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder); firstPassEffect.Parameters.Set(LambertianPrefilteringSHPass1Keys.RadianceMap, inputTexture); firstPassEffect.Parameters.Set(LambertianPrefilteringSHPass1Keys.OutputBuffer, partialSumBuffer); firstPassEffect.Draw(context); // Recursively applies the pass2 (sums the coefficients together) as long as needed. Swap input/output buffer at each iteration. var secondPassInputBuffer = partialSumBuffer; Buffer secondPassOutputBuffer = null; while (sumsToPerfomRemaining % 2 == 0) { // we are limited in the number of summing threads by the group-shared memory size. // determine the number of threads to use and update the number of sums remaining afterward. var sumsCount = 1; while (sumsCount < (1<<10) && sumsToPerfomRemaining % 2 == 0) // shader can perform only an 2^x number of sums. { sumsCount <<= 1; sumsToPerfomRemaining >>= 1; } // determine the numbers of groups (limited to 65535 groups by dimensions) var groupCountX = 1; var groupCountY = sumsToPerfomRemaining; while (groupCountX >= short.MaxValue) { groupCountX <<= 1; groupCountY >>= 1; } // create the output buffer if not existing yet if (secondPassOutputBuffer == null) secondPassOutputBuffer = NewScopedTypedBuffer(coefficientsCount * sumsToPerfomRemaining, PixelFormat.R32G32B32A32_Float, true); // draw pass 2 secondPassEffect.ThreadNumbers = new Int3(sumsCount, 1, 1); secondPassEffect.ThreadGroupCounts = new Int3(groupCountX, groupCountY, coefficientsCount); secondPassEffect.Parameters.Set(LambertianPrefilteringSHParameters.BlockSize, sumsCount); secondPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder); secondPassEffect.Parameters.Set(LambertianPrefilteringSHPass2Keys.InputBuffer, secondPassInputBuffer); secondPassEffect.Parameters.Set(LambertianPrefilteringSHPass2Keys.OutputBuffer, secondPassOutputBuffer); secondPassEffect.Draw(context); // swap second pass input/output buffers. var swapTemp = secondPassOutputBuffer; secondPassOutputBuffer = secondPassInputBuffer; secondPassInputBuffer = swapTemp; } // create and initialize result SH prefilteredLambertianSH = new SphericalHarmonics(HarmonicOrder); // Get the data out of the final buffer var sizeResult = coefficientsCount * sumsToPerfomRemaining * PixelFormat.R32G32B32A32_Float.SizeInBytes(); var stagedBuffer = NewScopedBuffer(new BufferDescription(sizeResult, BufferFlags.None, GraphicsResourceUsage.Staging)); GraphicsDevice.CopyRegion(secondPassInputBuffer, 0, new ResourceRegion(0, 0, 0, sizeResult, 1, 1), stagedBuffer, 0); var finalsValues = stagedBuffer.GetData<Vector4>(); // performs last possible additions, normalize the result and store it in the SH for (var c = 0; c < coefficientsCount; c++) { var coeff = Vector4.Zero; for (var f = 0; f < sumsToPerfomRemaining; ++f) { coeff += finalsValues[coefficientsCount * f + c]; } prefilteredLambertianSH.Coefficients[c] = 4 * MathUtil.Pi / coeff.W * new Color3(coeff.X, coeff.Y, coeff.Z); } }
private void OnGUI() { EditorGUILayout.PropertyField(sp_to_compute); so.ApplyModifiedProperties(); EditorGUILayout.Space(); if (to_compute != null && GUILayout.Button("Compute Thickness")) { //create the folder with saved mesh assets if (!AssetDatabase.IsValidFolder("Assets/TranslucentMeshes")) { AssetDatabase.CreateFolder("Assets", "TranslucentMeshes"); } GameObject tmp_camera_object = new GameObject("tmp_camera"); Camera tmp_camera = tmp_camera_object.AddComponent <Camera>(); tmp_camera.clearFlags = CameraClearFlags.Color; tmp_camera.backgroundColor = Color.black; tmp_camera.nearClipPlane = 0.01f; tmp_camera.farClipPlane = 300; GameObject clone = Instantiate(to_compute.gameObject); Mesh mesh = Instantiate(to_compute.sharedMesh); Vector3[] vertices = mesh.vertices; Vector3[] normals = mesh.normals; Vector2[] uv2 = new Vector2[mesh.vertexCount]; Vector2[] uv3 = new Vector2[mesh.vertexCount]; Vector2[] uv4 = new Vector2[mesh.vertexCount]; Color[] colors = new Color[mesh.vertexCount]; //temporary storage for the sh coefficients Vector4[] coefficients = new Vector4[9]; //64x64 cubemap should be enough Cubemap thickness_cubemap = new Cubemap(128, TextureFormat.RGBA32, false); //TODO: usare formato float for (int v = 0; v < mesh.vertexCount; ++v) { //vertices in the mesh are in local space, transform to world coordinate Vector3 vertex_world_position = vertices[v]; // clone.transform.localToWorldMatrix.MultiplyPoint(vertices[v]); //TODO: al posto di lavorare in world space, lavorare in local Vector3 world_normal = normals[v]; // clone.transform.localToWorldMatrix.MultiplyVector(normals[v]); tmp_camera.transform.position = vertex_world_position - world_normal * 0.011f; tmp_camera.RenderToCubemap(thickness_cubemap); //project the cubemap to the spherical harmonic basis SphericalHarmonics.GPU_Project_Uniform_9Coeff(thickness_cubemap, coefficients); //put 4 coefficients in the vertex color, 2 in the uv2 and 2 in the uv3 and 1 in uv4 colors[v] = new Color(coefficients[0].x, coefficients[1].x, coefficients[2].x, coefficients[3].x); uv2[v] = new Vector2(coefficients[4].x, coefficients[5].x); uv3[v] = new Vector2(coefficients[6].x, coefficients[7].x); uv4[v] = new Vector2(coefficients[8].x, 0); for (int i = 0; i < 9; ++i) { coefficients[i] = Vector4.zero; } } mesh.colors = colors; mesh.uv2 = uv2; mesh.uv3 = uv3; mesh.uv4 = uv4; mesh.UploadMeshData(true); //save the mesh AssetDatabase.CreateAsset(mesh, "Assets/TranslucentMeshes/" + to_compute.name + ".asset"); clone.GetComponent <MeshFilter>().sharedMesh = mesh; Object.DestroyImmediate(tmp_camera_object); to_compute.gameObject.SetActive(false); } }
public void StoreLightmapInfos(int index) { if (GLog.IsLogInfoEnabled) { GLog.LogInfo("Storing data for lighting scenario " + index); } if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.OnDemand) { if (GLog.IsLogErrorEnabled) { GLog.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled."); } return; } var newLightingScenarioData = new LightingScenarioData(); var newRendererInfos = new List <RendererInfo>(); var newLightmapsTextures = new List <Texture2D>(); var newLightmapsTexturesDir = new List <Texture2D>(); var newLightmapsMode = new LightmapsMode(); var newSphericalHarmonicsList = new List <SphericalHarmonics>(); newLightmapsMode = LightmapSettings.lightmapsMode; GenerateLightmapInfo(gameObject, newRendererInfos, newLightmapsTextures, newLightmapsTexturesDir, newLightmapsMode); newLightingScenarioData.lightmapsMode = newLightmapsMode; newLightingScenarioData.lightmaps = newLightmapsTextures.ToArray(); if (newLightmapsMode != LightmapsMode.NonDirectional) { newLightingScenarioData.lightmapsDir = newLightmapsTexturesDir.ToArray(); } newLightingScenarioData.rendererInfos = newRendererInfos.ToArray(); var scene_LightProbes = new SphericalHarmonicsL2[LightmapSettings.lightProbes.bakedProbes.Length]; scene_LightProbes = LightmapSettings.lightProbes.bakedProbes; for (int i = 0; i < scene_LightProbes.Length; i++) { var SHCoeff = new SphericalHarmonics(); // j is coefficient for (int j = 0; j < 3; j++) { //k is channel ( r g b ) for (int k = 0; k < 9; k++) { SHCoeff.coefficients[j * 9 + k] = scene_LightProbes[i][j, k]; } } newSphericalHarmonicsList.Add(SHCoeff); } newLightingScenarioData.lightProbes = newSphericalHarmonicsList.ToArray(); lightingScenariosData = newLightingScenarioData; if (lightingScenesNames == null || lightingScenesNames.Count < lightingScenariosCount) { lightingScenesNames = new List <string>(); while (lightingScenesNames.Count < lightingScenariosCount) { lightingScenesNames.Add(null); } } }
private void OnGUI() { EditorGUILayout.PropertyField(sp_input_cubemap, new GUIContent("Input Cubemap")); so.ApplyModifiedProperties(); if (input_cubemap != null) { EditorGUILayout.Space(); if (GUILayout.Button("CPU Uniform 9 Coefficients")) { coefficients = new Vector4[9]; if (SphericalHarmonics.CPU_Project_Uniform_9Coeff(input_cubemap, coefficients)) { for (int i = 0; i < 9; ++i) { view_mat.SetVector("c" + i.ToString(), coefficients[i]); view_mat.SetTexture("input", input_cubemap); } SceneView.RepaintAll(); } } EditorGUILayout.Space(); if (GUILayout.Button("CPU Monte Carlo 9 Coefficients")) { coefficients = new Vector4[9]; if (SphericalHarmonics.CPU_Project_MonteCarlo_9Coeff(input_cubemap, coefficients, 4096)) { for (int i = 0; i < 9; ++i) { view_mat.SetVector("c" + i.ToString(), coefficients[i]); view_mat.SetTexture("input", input_cubemap); } SceneView.RepaintAll(); } } EditorGUILayout.Space(); if (GUILayout.Button("GPU Uniform 9 Coefficients")) { coefficients = new Vector4[9]; if (SphericalHarmonics.GPU_Project_Uniform_9Coeff(input_cubemap, coefficients)) { for (int i = 0; i < 9; ++i) { view_mat.SetVector("c" + i.ToString(), coefficients[i]); view_mat.SetTexture("input", input_cubemap); } SceneView.RepaintAll(); } } EditorGUILayout.Space(); if (GUILayout.Button("GPU Monte Carlo 9 Coefficients")) { coefficients = new Vector4[9]; if (SphericalHarmonics.GPU_Project_MonteCarlo_9Coeff(input_cubemap, coefficients)) { for (int i = 0; i < 9; ++i) { view_mat.SetVector("c" + i.ToString(), coefficients[i]); view_mat.SetTexture("input", input_cubemap); } } } EditorGUILayout.Space(); if (GUILayout.Button("Show")) { RenderSettings.skybox = view_mat; } view_mode = EditorGUILayout.Slider(view_mode, 0, 1); view_mat.SetFloat("_Mode", view_mode); EditorGUILayout.Space(); //print the 9 coefficients if (coefficients != null) { for (int i = 0; i < 9; ++i) { EditorGUILayout.LabelField("c_" + i.ToString() + ": " + coefficients[i].ToString("f4")); } } } EditorGUILayout.Space(); if (tmp != null) { GUILayout.Label(tmp); } }
public void StoreLightmapInfos(int index) { var newLightingScenarioData = new LightingScenarioData(); var newRendererInfos = new List <RendererInfo>(); var newLightmapsTextures = new List <Texture2D>(); var newLightmapsTexturesDir = new List <Texture2D>(); var newLightmapsMode = new LightmapsMode(); var newSphericalHarmonicsList = new List <SphericalHarmonics>(); var newLightmapsShadowMasks = new List <Texture2D>(); newLightmapsMode = LightmapSettings.lightmapsMode; GenerateLightmapInfo(gameObject, newRendererInfos, newLightmapsTextures, newLightmapsTexturesDir, newLightmapsShadowMasks, newLightmapsMode); newLightingScenarioData.lightmapsMode = newLightmapsMode; newLightingScenarioData.lightmaps = newLightmapsTextures.ToArray(); if (newLightmapsMode != LightmapsMode.NonDirectional) { newLightingScenarioData.lightmapsDir = newLightmapsTexturesDir.ToArray(); } //Mixed or realtime support newLightingScenarioData.hasRealtimeLights = latestBuildHasReltimeLights; newLightingScenarioData.shadowMasks = newLightmapsShadowMasks.ToArray(); newLightingScenarioData.rendererInfos = newRendererInfos.ToArray(); var scene_LightProbes = new SphericalHarmonicsL2[LightmapSettings.lightProbes.bakedProbes.Length]; scene_LightProbes = LightmapSettings.lightProbes.bakedProbes; for (int i = 0; i < scene_LightProbes.Length; i++) { var SHCoeff = new SphericalHarmonics(); // j is coefficient for (int j = 0; j < 3; j++) { //k is channel ( r g b ) for (int k = 0; k < 9; k++) { SHCoeff.coefficients[j * 9 + k] = scene_LightProbes[i][j, k]; } } newSphericalHarmonicsList.Add(SHCoeff); } newLightingScenarioData.lightProbes = newSphericalHarmonicsList.ToArray(); if (lightingScenariosData.Count < index + 1) { lightingScenariosData.Insert(index, newLightingScenarioData); } else { lightingScenariosData[index] = newLightingScenarioData; } lightingScenariosCount = lightingScenariosData.Count; if (lightingScenesNames == null || lightingScenesNames.Length < lightingScenariosCount) { lightingScenesNames = new string[lightingScenariosCount]; } }
public void StoreLightmapInfos(int index) { Debug.Log("Storing data for lighting scenario " + index); if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.OnDemand) { Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled."); return; } var newLightingScenarioData = new LightingScenarioData(); var newRendererInfos = new List <RendererInfo>(); var newLightmapsTextures = new List <Texture2D>(); var newLightmapsTexturesDir = new List <Texture2D>(); var newLightmapsMode = new LightmapsMode(); var newSphericalHarmonicsList = new List <SphericalHarmonics>(); var newLightmapsShadowMasks = new List <Texture2D>(); newLightmapsMode = LightmapSettings.lightmapsMode; GenerateLightmapInfo(gameObject, newRendererInfos, newLightmapsTextures, newLightmapsTexturesDir, newLightmapsShadowMasks, newLightmapsMode); newLightingScenarioData.lightmapsMode = newLightmapsMode; newLightingScenarioData.lightmaps = newLightmapsTextures.ToArray(); if (newLightmapsMode != LightmapsMode.NonDirectional) { newLightingScenarioData.lightmapsDir = newLightmapsTexturesDir.ToArray(); } //Mixed or realtime support newLightingScenarioData.hasRealtimeLights = latestBuildHasReltimeLights; newLightingScenarioData.shadowMasks = newLightmapsShadowMasks.ToArray(); newLightingScenarioData.rendererInfos = newRendererInfos.ToArray(); var scene_LightProbes = new SphericalHarmonicsL2[LightmapSettings.lightProbes.bakedProbes.Length]; scene_LightProbes = LightmapSettings.lightProbes.bakedProbes; for (int i = 0; i < scene_LightProbes.Length; i++) { var SHCoeff = new SphericalHarmonics(); // j is coefficient for (int j = 0; j < 3; j++) { //k is channel ( r g b ) for (int k = 0; k < 9; k++) { SHCoeff.coefficients[j * 9 + k] = scene_LightProbes[i][j, k]; } } newSphericalHarmonicsList.Add(SHCoeff); } newLightingScenarioData.lightProbes = newSphericalHarmonicsList.ToArray(); if (lightingScenariosData.Count < index + 1) { lightingScenariosData.Insert(index, newLightingScenarioData); } else { lightingScenariosData[index] = newLightingScenarioData; } lightingScenariosCount = lightingScenariosData.Count; if (lightingScenesNames == null || lightingScenesNames.Length < lightingScenariosCount) { lightingScenesNames = new string[lightingScenariosCount]; } if (latestBuildHasReltimeLights && lightingScenesNames[index] != null) { lightingScenesNames[index] = lightingScenariosScenes[index].name; } }
public void SaveLightMaps() { LightingScenarioData newLightingScenario = new LightingScenarioData(); var newRendererInfos = new List <RendererInfo>(); var newLightmapsTextures = new List <Texture2D>(); var newLightmapsTexturesDir = new List <Texture2D>(); var newLightmapsTexturesShadow = new List <Texture2D>(); var newLightmapsMode = new LightmapsMode(); var newSphericalHarmonicsList = new List <SphericalHarmonics>(); newLightmapsMode = LightmapSettings.lightmapsMode; var renderers = FindObjectsOfType(typeof(MeshRenderer)); Debug.Log("stored info for " + renderers.Length + " meshrenderers"); foreach (MeshRenderer renderer in renderers) { if (renderer.lightmapIndex != -1) { RendererInfo info = new RendererInfo(); info.renderer = renderer; info.lightmapOffsetScale = renderer.lightmapScaleOffset; Texture2D lightmaplight = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapColor; info.lightmapIndex = newLightmapsTextures.IndexOf(lightmaplight); if (info.lightmapIndex == -1) { info.lightmapIndex = newLightmapsTextures.Count; newLightmapsTextures.Add(lightmaplight); } if (newLightmapsMode != LightmapsMode.NonDirectional) { //first directional lighting Texture2D lightmapdir = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapDir; info.lightmapIndex = newLightmapsTexturesDir.IndexOf(lightmapdir); if (info.lightmapIndex == -1) { info.lightmapIndex = newLightmapsTexturesDir.Count; newLightmapsTexturesDir.Add(lightmapdir); } LightmapData lmd = LightmapSettings.lightmaps[0]; //now the shadowmask Texture2D lightmapshadow = LightmapSettings.lightmaps[renderer.lightmapIndex].shadowMask; if (lightmapshadow != null) { info.lightmapIndex = newLightmapsTexturesShadow.IndexOf(lightmapshadow); if (info.lightmapIndex == -1) { info.lightmapIndex = newLightmapsTexturesShadow.Count; newLightmapsTexturesShadow.Add(lightmapshadow); } } } newRendererInfos.Add(info); } } newLightingScenario.lightmapsMode = newLightmapsMode; newLightingScenario.lightmaps = newLightmapsTextures.ToArray(); if (newLightmapsMode != LightmapsMode.NonDirectional) { newLightingScenario.lightmapsDir = newLightmapsTexturesDir.ToArray(); newLightingScenario.lightmapsShadow = newLightmapsTexturesShadow.ToArray(); } newLightingScenario.rendererInfos = newRendererInfos.ToArray(); var scene_LightProbes = new SphericalHarmonicsL2[LightmapSettings.lightProbes.bakedProbes.Length]; scene_LightProbes = LightmapSettings.lightProbes.bakedProbes; for (int i = 0; i < scene_LightProbes.Length; i++) { var SHCoeff = new SphericalHarmonics(); // j is coefficient for (int j = 0; j < 3; j++) { //k is channel ( r g b ) for (int k = 0; k < 9; k++) { SHCoeff.coefficients[j * 9 + k] = scene_LightProbes[i][j, k]; } } newSphericalHarmonicsList.Add(SHCoeff); } newLightingScenario.lightProbes = newSphericalHarmonicsList.ToArray(); // write the files and map config data. CreateResourcesDirectory(m_currentLightScenario); string resourcesDir = GetResourcesDirectory(m_currentLightScenario); CopyTextureToResources(resourcesDir, newLightingScenario.lightmaps); CopyTextureToResources(resourcesDir, newLightingScenario.lightmapsDir); CopyTextureToResources(resourcesDir, newLightingScenario.lightmapsShadow); newLightingScenario.name = m_currentLightScenario; SaveLightScenarioData(newLightingScenario); UnityEditor.EditorUtility.SetDirty(this.gameObject); }
protected override void DrawCore(RenderDrawContext context) { var inputTexture = RadianceMap; if (inputTexture == null) return; var coefficientsCount = harmonicalOrder * harmonicalOrder; var faceCount = inputTexture.Dimension == TextureDimension.TextureCube ? 6 : 1; if (faceCount == 1) { throw new NotSupportedException("Only texture cube are currently supported as input of 'LambertianPrefilteringNoCompute' effect."); } firstPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder); firstPassEffect.Parameters.Set(LambertianPrefilteringSHNoComputePass1Keys.RadianceMap, inputTexture); // Create a tree of power-of-two textures for summing up coefficients var intermediateSize = new Int2(MathUtil.NextPowerOfTwo(inputTexture.Width), MathUtil.NextPowerOfTwo(inputTexture.Height)); var intermediateTextures = new List<Texture>(); intermediateTextures.Add(NewScopedRenderTarget2D(intermediateSize.X, intermediateSize.Y, PixelFormat.R32G32B32A32_Float)); while (intermediateSize.X > 1 || intermediateSize.Y > 1) { if (intermediateSize.X > 1) intermediateSize.X >>= 1; if (intermediateSize.Y > 1) intermediateSize.Y >>= 1; intermediateTextures.Add(NewScopedRenderTarget2D(intermediateSize.X, intermediateSize.Y, PixelFormat.R32G32B32A32_Float)); } // Create a staging texture for each coefficient var stagingTextures = new Texture[coefficientsCount]; var stagingDescription = intermediateTextures[intermediateTextures.Count - 1].Description.ToStagingDescription(); for (var c = 0; c < coefficientsCount; c++) stagingTextures[c] = Texture.New(GraphicsDevice, stagingDescription); // Calculate one coefficient at a time for (var c = 0; c < coefficientsCount; c++) { // Project the radiance on the SH basis and sum up the results for all faces firstPassEffect.Parameters.Set(LambertianPrefilteringSHNoComputePass1Keys.CoefficientIndex, c); firstPassEffect.Parameters.Set(LambertianPrefilteringSHNoComputePass1Keys.RadianceMap, RadianceMap); firstPassEffect.SetOutput(intermediateTextures[0]); ((RendererBase)firstPassEffect).Draw(context); // Recursive summation for (var i = 1; i < intermediateTextures.Count; i++) { secondPassEffect.SetInput(intermediateTextures[i - 1]); secondPassEffect.SetOutput(intermediateTextures[i]); ((RendererBase)secondPassEffect).Draw(context); } context.CommandList.Copy(intermediateTextures[intermediateTextures.Count - 1], stagingTextures[c]); } // Create and initialize result SH PrefilteredLambertianSH = new SphericalHarmonics(HarmonicOrder); // Read back coefficients and store it in the SH for (var c = 0; c < coefficientsCount; c++) { var value = stagingTextures[c].GetData<Vector4>(context.CommandList)[0]; PrefilteredLambertianSH.Coefficients[c] = 4 * MathUtil.Pi / value.W * new Color3(value.X, value.Y, value.Z); } }
public void Initialize() { oldSkyTex = Renderer.SkyTex; oldSkyLight = Renderer.SkyLight; /// :CodeSample: Renderer.SkyTex Renderer.SkyLight Tex.FromCubemapEquirectangular /// ## Setting lighting to an equirect cubemap /// Changing the environment's lighting based on an image is a really /// great way to instantly get a particular feel to your scene! A neat /// place to find compatible equirectangular images for this is /// [Poly Haven](https://polyhaven.com/hdris) Renderer.SkyTex = Tex.FromCubemapEquirectangular("old_depot.hdr", out SphericalHarmonics lighting); Renderer.SkyLight = lighting; /// And here's what it looks like applied to the default Material! /// ![Default Material example]({{site.screen_url}}/MaterialDefault.jpg) /// :End: meshSphere = Mesh.GenerateSphere(1, 8); /// :CodeSample: Default.Material /// If you want to modify the default material, it's recommended to /// copy it first! matDefault = Default.Material.Copy(); /// And here's what it looks like: /// ![Default Material example]({{site.screen_url}}/MaterialDefault.jpg) /// :End: /// :CodeSample: Default.MaterialUI /// This Material is basically the same as Default.Material, except it /// also adds some glow to the surface near the user's fingers. It /// works best on flat surfaces, and in StereoKit's design language, /// can be used to indicate that something is interactive. matUI = Default.MaterialUI.Copy(); /// And here's what it looks like: /// ![UI Material example]({{site.screen_url}}/MaterialUI.jpg) /// :End: /// :CodeSample: Material.Wireframe /// Here's creating a simple wireframe material! matWireframe = Default.Material.Copy(); matWireframe.Wireframe = true; /// Which looks like this: /// ![Wireframe material example]({{site.screen_url}}/MaterialWireframe.jpg) /// :End: /// :CodeSample: Material.FaceCull Cull.Front /// Here's setting FaceCull to Front, which is the opposite of the /// default behavior. On a sphere, this is a little hard to see, but /// you might notice here that the lighting is for the back side of /// the sphere! matCull = Default.Material.Copy(); matCull.FaceCull = Cull.Front; /// ![FaceCull material example]({{site.screen_url}}/MaterialCull.jpg) /// :End: /// :CodeSample: Material.Transparency Transparency.Add /// ## Additive Transparency /// Here's an example material with additive transparency. /// Transparent materials typically don't write to the depth buffer, /// but this may vary from case to case. Note that the material's /// alpha does not play any role in additive transparency! Instead, /// you could make the material's tint darker. matAlphaAdd = Default.Material.Copy(); matAlphaAdd.Transparency = Transparency.Add; matAlphaAdd.DepthWrite = false; /// ![Additive transparency example]({{site.screen_url}}/MaterialAlphaAdd.jpg) /// :End: /// :CodeSample: Material.Transparency Transparency.Blend /// ## Alpha Blending /// Here's an example material with an alpha blend transparency. /// Transparent materials typically don't write to the depth buffer, /// but this may vary from case to case. Here we're setting the alpha /// through the material's Tint value, but the diffuse texture's /// alpha and the instance render color's alpha may also play a part /// in the final alpha value. matAlphaBlend = Default.Material.Copy(); matAlphaBlend.Transparency = Transparency.Blend; matAlphaBlend.DepthWrite = false; matAlphaBlend[MatParamName.ColorTint] = new Color(1, 1, 1, 0.75f); /// ![Alpha blend example]({{site.screen_url}}/MaterialAlphaBlend.jpg) /// :End: matTextured = Default.Material.Copy(); matTextured[MatParamName.DiffuseTex] = Tex.FromFile("floor.png"); /// :CodeSample: Default.MaterialUnlit matUnlit = Default.MaterialUnlit.Copy(); matUnlit[MatParamName.DiffuseTex] = Tex.FromFile("floor.png"); /// ![Unlit material example]({{site.screen_url}}/MaterialUnlit.jpg) /// :End: /// :CodeSample: Default.MaterialPBR /// Occlusion (R), Roughness (G), and Metal (B) are stored /// respectively in the R, G and B channels of their texture. /// Occlusion can be separated out into a different texture as per /// the GLTF spec, so you do need to assign it separately from the /// Metal texture. matPBR = Default.MaterialPBR.Copy(); matPBR[MatParamName.DiffuseTex] = Tex.FromFile("metal_plate_diff.jpg"); matPBR[MatParamName.MetalTex] = Tex.FromFile("metal_plate_metal.jpg", false); matPBR[MatParamName.OcclusionTex] = Tex.FromFile("metal_plate_metal.jpg", false); /// ![PBR material example]({{site.screen_url}}/MaterialPBR.jpg) /// :End: /// :CodeSample: Default.MaterialUIBox /// The UI Box material has 3 parameters to control how the box wires /// are rendered. The initial size in meters is 'border_size', and /// can grow by 'border_size_grow' meters based on distance to the /// user's hand. That distance can be configured via the /// 'border_affect_radius' property of the shader, which is also in /// meters. matUIBox = Default.MaterialUIBox.Copy(); matUIBox["border_size"] = 0.005f; matUIBox["border_size_grow"] = 0.01f; matUIBox["border_affect_radius"] = 0.2f; /// ![UI box material example]({{site.screen_url}}/MaterialUIBox.jpg) /// :End: matParameters = Default.Material.Copy(); matParameters[MatParamName.DiffuseTex] = Tex.FromFile("floor.png"); matParameters[MatParamName.ColorTint] = Color.HSV(0.6f, 0.7f, 1f); matParameters[MatParamName.TexScale] = 2; }
private void OnGUI() { modle = EditorGUILayout.Toggle("CubeMap", modle); if (modle) { input_cubemap = EditorGUILayout.ObjectField("Input Cubemap", input_cubemap, typeof(Cubemap), true) as Cubemap; isCopyNew = EditorGUILayout.Toggle("从环境球获取", isCopyNew); if (input_cubemap != null) { EditorGUILayout.Space(); if (GUILayout.Button("CPU Uniform 9 Coefficients")) { Cubemap cm = input_cubemap; if (isCopyNew) { test = cm = CopyFromEnvMap(); } ModifyTextureReadable(); coefficients = new Vector4[9]; if (SphericalHarmonics.CPU_Project_Uniform_9Coeff(cm, coefficients)) { setSH9Global(); } if (isCopyNew) { GameObject.DestroyImmediate(cm, true); } } EditorGUILayout.Space(); if (GUILayout.Button("CPU Monte Carlo 9 Coefficients")) { Cubemap cm = input_cubemap; if (isCopyNew) { cm = CopyFromEnvMap(); } ModifyTextureReadable(); coefficients = new Vector4[9]; if (SphericalHarmonics.CPU_Project_MonteCarlo_9Coeff(cm, coefficients, 4096)) { setSH9Global(); } if (isCopyNew) { GameObject.DestroyImmediate(cm, true); } } EditorGUILayout.Space(); if (GUILayout.Button("GPU Uniform 9 Coefficients")) { Cubemap cm = input_cubemap; if (isCopyNew) { input_cubemap = cm = CopyFromEnvMap(); } ModifyTextureReadable(); coefficients = new Vector4[9]; if (SphericalHarmonics.GPU_Project_Uniform_9Coeff(cm, coefficients)) { setSH9Global(); } if (isCopyNew) { GameObject.DestroyImmediate(cm, true); } } EditorGUILayout.Space(); if (GUILayout.Button("GPU Monte Carlo 9 Coefficients")) { Cubemap cm = input_cubemap; if (isCopyNew) { cm = CopyFromEnvMap(); } ModifyTextureReadable(); coefficients = new Vector4[9]; if (SphericalHarmonics.GPU_Project_MonteCarlo_9Coeff(cm, coefficients)) { setSH9Global(); } if (isCopyNew) { GameObject.DestroyImmediate(cm, true); } } EditorGUILayout.Space(); } } else { env_map = EditorGUILayout.ObjectField("360环境球", env_map, typeof(Texture2D), true) as Texture2D; if (env_map) { sun = EditorGUILayout.Toggle("太阳", sun); } enableLight = EditorGUILayout.Toggle("灯光", enableLight); if (enableLight) { GUILayout.BeginHorizontal(); if (GUILayout.Button("+")) { lights.Add(null); } if (GUILayout.Button("-")) { if (lights.Count > 0) { lights.RemoveAt(lights.Count - 1); } } GUILayout.EndHorizontal(); for (int i = 0; i < lights.Count; i++) { lights[i] = EditorGUILayout.ObjectField("360环境球", lights[i], typeof(Light), true) as Light; } } bool hasLight = false; for (int i = 0; i < lights.Count; i++) { if (lights [i] != null) { hasLight = true; break; } } //lights if (hasLight || env_map != null) { EditorGUILayout.Space(); if (GUILayout.Button("CPU Uniform 9 Coefficients")) { ModifyTextureReadable(env_map); List <Light> ls = new List <Light> (); foreach (Light l in lights) { if (l != null) { ls.Add(l); } } coefficients = new Vector4[9]; if (SphericalHarmonics.CPU_Project_360HJQ(env_map, coefficients, 4096, sun, ls.ToArray())) { setSH9Global(); } } } } if (coefficients != null && coefficients.Length == 9) { if (GUILayout.Button("保存")) { SH9Data data = SH9Data.CreateInstance <SH9Data> (); data.coefficients = coefficients; string path = EditorUtility.SaveFilePanelInProject("Save SH9 Data", "ibl.asset", "asset", "Please enter a file name to save the texture to"); if (path.Length != 0) { if (System.IO.File.Exists(path)) { /*if (EditorUtility.DisplayDialog("目标已存在", "替换", "取消")) * { * * }*/ data.test = new Vector4(1, 0, 0, 1); data = AssetDatabase.LoadAssetAtPath <SH9Data> (path); data.coefficients = coefficients; AssetDatabase.SaveAssets(); } else { data.test = Vector4.one; AssetDatabase.CreateAsset(data, path); AssetDatabase.ImportAsset(path); } } } EditorGUILayout.Space(); for (int i = 0; i < 9; ++i) { EditorGUILayout.LabelField("c_" + i.ToString() + ": " + coefficients[i].ToString("f4")); } } EditorGUILayout.Space(); if (tmp != null) { GUILayout.Label(tmp); } }
protected override void DrawCore(RenderDrawContext context) { var inputTexture = RadianceMap; if (inputTexture == null) { return; } const int FirstPassBlockSize = 4; const int FirstPassSumsCount = FirstPassBlockSize * FirstPassBlockSize; var faceCount = inputTexture.ViewDimension == TextureDimension.TextureCube ? 6 : 1; if (faceCount == 1) { throw new NotSupportedException("Only texture cube are currently supported as input of 'LambertianPrefilteringSH' effect."); } var inputSize = new Int2(inputTexture.Width, inputTexture.Height); // (Note: for cube maps width = height) var coefficientsCount = harmonicalOrder * harmonicalOrder; var sumsToPerfomRemaining = inputSize.X * inputSize.Y * faceCount / FirstPassSumsCount; var partialSumBuffer = NewScopedTypedBuffer(coefficientsCount * sumsToPerfomRemaining, PixelFormat.R32G32B32A32_Float, true); // Project the radiance on the SH basis and sum up the results along the 4x4 blocks firstPassEffect.ThreadNumbers = new Int3(FirstPassBlockSize, FirstPassBlockSize, 1); firstPassEffect.ThreadGroupCounts = new Int3(inputSize.X / FirstPassBlockSize, inputSize.Y / FirstPassBlockSize, faceCount); firstPassEffect.Parameters.Set(LambertianPrefilteringSHParameters.BlockSize, FirstPassBlockSize); firstPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder); firstPassEffect.Parameters.Set(LambertianPrefilteringSHPass1Keys.RadianceMap, inputTexture); firstPassEffect.Parameters.Set(LambertianPrefilteringSHPass1Keys.OutputBuffer, partialSumBuffer); ((RendererBase)firstPassEffect).Draw(context); // Recursively applies the pass2 (sums the coefficients together) as long as needed. Swap input/output buffer at each iteration. var secondPassInputBuffer = partialSumBuffer; Buffer secondPassOutputBuffer = null; while (sumsToPerfomRemaining % 2 == 0) { // we are limited in the number of summing threads by the group-shared memory size. // determine the number of threads to use and update the number of sums remaining afterward. var sumsCount = 1; while (sumsCount < (1 << 10) && sumsToPerfomRemaining % 2 == 0) // shader can perform only an 2^x number of sums. { sumsCount <<= 1; sumsToPerfomRemaining >>= 1; } // determine the numbers of groups (limited to 65535 groups by dimensions) var groupCountX = 1; var groupCountY = sumsToPerfomRemaining; while (groupCountX >= short.MaxValue) { groupCountX <<= 1; groupCountY >>= 1; } // create the output buffer if not existing yet if (secondPassOutputBuffer == null) { secondPassOutputBuffer = NewScopedTypedBuffer(coefficientsCount * sumsToPerfomRemaining, PixelFormat.R32G32B32A32_Float, true); } // draw pass 2 secondPassEffect.ThreadNumbers = new Int3(sumsCount, 1, 1); secondPassEffect.ThreadGroupCounts = new Int3(groupCountX, groupCountY, coefficientsCount); secondPassEffect.Parameters.Set(LambertianPrefilteringSHParameters.BlockSize, sumsCount); secondPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder); secondPassEffect.Parameters.Set(LambertianPrefilteringSHPass2Keys.InputBuffer, secondPassInputBuffer); secondPassEffect.Parameters.Set(LambertianPrefilteringSHPass2Keys.OutputBuffer, secondPassOutputBuffer); ((RendererBase)secondPassEffect).Draw(context); // swap second pass input/output buffers. var swapTemp = secondPassOutputBuffer; secondPassOutputBuffer = secondPassInputBuffer; secondPassInputBuffer = swapTemp; } // create and initialize result SH prefilteredLambertianSH = new SphericalHarmonics(HarmonicOrder); // Get the data out of the final buffer var sizeResult = coefficientsCount * sumsToPerfomRemaining * PixelFormat.R32G32B32A32_Float.SizeInBytes(); var stagedBuffer = NewScopedBuffer(new BufferDescription(sizeResult, BufferFlags.None, GraphicsResourceUsage.Staging)); context.CommandList.CopyRegion(secondPassInputBuffer, 0, new ResourceRegion(0, 0, 0, sizeResult, 1, 1), stagedBuffer, 0); var finalsValues = stagedBuffer.GetData <Vector4>(context.CommandList); // performs last possible additions, normalize the result and store it in the SH for (var c = 0; c < coefficientsCount; c++) { var coeff = Vector4.Zero; for (var f = 0; f < sumsToPerfomRemaining; ++f) { coeff += finalsValues[coefficientsCount * f + c]; } prefilteredLambertianSH.Coefficients[c] = 4 * MathUtil.Pi / coeff.W * new Color3(coeff.X, coeff.Y, coeff.Z); } }
protected override void DrawCore(RenderDrawContext context) { var inputTexture = RadianceMap; if (inputTexture == null) { return; } var coefficientsCount = harmonicalOrder * harmonicalOrder; var faceCount = inputTexture.ViewDimension == TextureDimension.TextureCube ? 6 : 1; if (faceCount == 1) { throw new NotSupportedException("Only texture cube are currently supported as input of 'LambertianPrefilteringNoCompute' effect."); } firstPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder); firstPassEffect.Parameters.Set(LambertianPrefilteringSHNoComputePass1Keys.RadianceMap, inputTexture); // Create a tree of power-of-two textures for summing up coefficients var intermediateSize = new Int2(MathUtil.NextPowerOfTwo(inputTexture.Width), MathUtil.NextPowerOfTwo(inputTexture.Height)); var intermediateTextures = new List <Texture>(); intermediateTextures.Add(NewScopedRenderTarget2D(intermediateSize.X, intermediateSize.Y, PixelFormat.R32G32B32A32_Float)); while (intermediateSize.X > 1 || intermediateSize.Y > 1) { if (intermediateSize.X > 1) { intermediateSize.X >>= 1; } if (intermediateSize.Y > 1) { intermediateSize.Y >>= 1; } intermediateTextures.Add(NewScopedRenderTarget2D(intermediateSize.X, intermediateSize.Y, PixelFormat.R32G32B32A32_Float)); } // Create a staging texture for each coefficient var stagingTextures = new Texture[coefficientsCount]; var stagingDescription = intermediateTextures[intermediateTextures.Count - 1].Description.ToStagingDescription(); for (var c = 0; c < coefficientsCount; c++) { stagingTextures[c] = Texture.New(GraphicsDevice, stagingDescription); } // Calculate one coefficient at a time for (var c = 0; c < coefficientsCount; c++) { // Project the radiance on the SH basis and sum up the results for all faces firstPassEffect.Parameters.Set(LambertianPrefilteringSHNoComputePass1Keys.CoefficientIndex, c); firstPassEffect.Parameters.Set(LambertianPrefilteringSHNoComputePass1Keys.RadianceMap, RadianceMap); firstPassEffect.SetOutput(intermediateTextures[0]); ((RendererBase)firstPassEffect).Draw(context); // Recursive summation for (var i = 1; i < intermediateTextures.Count; i++) { secondPassEffect.SetInput(intermediateTextures[i - 1]); secondPassEffect.SetOutput(intermediateTextures[i]); ((RendererBase)secondPassEffect).Draw(context); } context.CommandList.Copy(intermediateTextures[intermediateTextures.Count - 1], stagingTextures[c]); } // Create and initialize result SH PrefilteredLambertianSH = new SphericalHarmonics(HarmonicOrder); // Read back coefficients and store it in the SH for (var c = 0; c < coefficientsCount; c++) { var value = stagingTextures[c].GetData <Vector4>(context.CommandList)[0]; PrefilteredLambertianSH.Coefficients[c] = 4 * MathUtil.Pi / value.W * new Color3(value.X, value.Y, value.Z); } }
public void Compute() { Material old_skybox = RenderSettings.skybox; Material cosine_skybox = new Material(Shader.Find("SH/CosineSkybox")); RenderSettings.skybox = cosine_skybox; //create the folder with saved mesh assets if (!AssetDatabase.IsValidFolder("Assets/ComputedMeshes")) { AssetDatabase.CreateFolder("Assets", "ComputedMeshes"); } //don't modify the original objects but make a copy GameObject parent = new GameObject("computed"); parent.SetActive(false); GameObject tmp_camera_object = new GameObject("tmp_camera"); Camera tmp_camera = tmp_camera_object.AddComponent <Camera>(); tmp_camera.clearFlags = CameraClearFlags.Skybox; tmp_camera.nearClipPlane = 0.01f; tmp_camera.farClipPlane = 300; //temporary storage for the sh coefficients Vector4[] coefficients = new Vector4[9]; //64x64 cubemap should be enough Cubemap visibility_cubemap = new Cubemap(64, TextureFormat.RGBA32, false); //cycle the children renderers MeshRenderer[] to_compute = gameObject.GetComponentsInChildren <MeshRenderer>(); //get the total number of vertex to compute int total_vertex = 0; int completed_vertex = 0; foreach (MeshRenderer mr in to_compute) { if (mr.gameObject.isStatic) { total_vertex = mr.gameObject.GetComponent <MeshFilter>().sharedMesh.vertexCount; } } //shader for rendering the visibility (black = occluded) Shader black_shader = Shader.Find("SH/BlackShader"); foreach (MeshRenderer mr in to_compute) { if (mr.gameObject.isStatic) //compute only static objects { //clone the original GameObject clone = Instantiate(mr.gameObject); clone.name = mr.gameObject.name; clone.transform.SetParent(parent.transform); Mesh mesh = Instantiate(mr.gameObject.GetComponent <MeshFilter>().sharedMesh); Vector3[] vertices = mesh.vertices; Vector3[] normals = mesh.normals; Vector2[] uv2 = new Vector2[mesh.vertexCount]; Vector2[] uv3 = new Vector2[mesh.vertexCount]; Vector2[] uv4 = new Vector2[mesh.vertexCount]; Color[] colors = new Color[mesh.vertexCount]; for (int v = 0; v < mesh.vertexCount; ++v) { //vertices in the mesh are in local space, transform to world coordinate Vector3 vertex_world_position = clone.transform.localToWorldMatrix.MultiplyPoint(vertices[v]); Vector3 world_normal = clone.transform.localToWorldMatrix.MultiplyVector(normals[v]); tmp_camera.transform.position = vertex_world_position + world_normal * 0.011f; //offset the camera a little in the normal direction cosine_skybox.SetVector("N", world_normal); tmp_camera.SetReplacementShader(black_shader, ""); tmp_camera.RenderToCubemap(visibility_cubemap); tmp_camera.ResetReplacementShader(); //project the cubemap to the spherical harmonic basis SphericalHarmonics.GPU_Project_Uniform_9Coeff(visibility_cubemap, coefficients); //put 4 coefficients in the vertex color, 2 in the uv2 and 2 in the uv3 and 1 in uv4 colors[v] = new Color(coefficients[0].x, coefficients[1].x, coefficients[2].x, coefficients[3].x); uv2[v] = new Vector2(coefficients[4].x, coefficients[5].x); uv3[v] = new Vector2(coefficients[6].x, coefficients[7].x); uv4[v] = new Vector2(coefficients[8].x, 0); for (int i = 0; i < 9; ++i) { coefficients[i] = Vector4.zero; } completed_vertex++; } mesh.colors = colors; mesh.uv2 = uv2; mesh.uv3 = uv3; mesh.uv4 = uv4; mesh.UploadMeshData(true); //save the mesh AssetDatabase.CreateAsset(mesh, "Assets/ComputedMeshes/" + mr.name + ".asset"); clone.GetComponent <MeshFilter>().sharedMesh = mesh; Material mat = new Material(Shader.Find("SH/SH_Shader")); clone.GetComponent <MeshRenderer>().material = mat; } } Object.DestroyImmediate(tmp_camera_object); gameObject.SetActive(false); parent.SetActive(true); RenderSettings.skybox = old_skybox; }