public void BlendToGlobalSky(mset.Sky next, float blendTime, float skipTime) { if(next != null) { nextSky = next; #if UNITY_EDITOR nextBlendTime = Application.isPlaying ? blendTime : 0f; #else nextBlendTime = blendTime; #endif nextSkipTime = skipTime; } //??? Harmless but weird? where did this come from? _GlobalSky = nextSky; }
public static void ProbeSkies(GameObject[] objects, mset.Sky[] skies, bool probeAll, bool probeIBL, System.Action doneCallback) { mset.SkyManager mgr = mset.SkyManager.Get(); if(mgr) { Probeshop window = (Probeshop)EditorWindow.GetWindow (typeof (Probeshop), true); window.Show(true); window.minSize = window.maxSize = new Vector2(400,200); Rect r = window.position; r.center = new Vector2(Screen.currentResolution.width/2, Screen.currentResolution.height/2); window.position = r; window.DoneCallback = doneCallback; mgr.ProbeSkies( objects, skies, probeAll, probeIBL); } else { EditorUtility.DisplayDialog("No Sky Manager found!", "Probing skies requires a SkyManager object in the scene. Add one through the GameObject menu.", "Ok"); Debug.LogWarning("Probing requires a SkyManager object in the scene."); } }
public static void projectCubeBuffer(ref mset.SHEncoding sh, CubeBuffer cube) { sh.clearToBlack(); float totalarea = 0f; ulong faceSize = (ulong)cube.faceSize; float[] dc = new float[9]; Vector3 u = Vector3.zero; for(ulong face=0; face<6; ++face) for(ulong y=0; y<faceSize; ++y) for(ulong x=0; x<faceSize; ++x) { //compute cube direction float areaweight = 1f; mset.Util.invCubeLookup(ref u, ref areaweight, face, x, y, faceSize); float shscale = 4f / 3f; ulong index = face*faceSize*faceSize + y*faceSize + x; Color rgba = cube.pixels[index]; //project on basis functions, and accumulate dc[0] = project_l0_m0(u); dc[1] = project_l1_mneg1(u); dc[2] = project_l1_m0(u); dc[3] = project_l1_m1(u); dc[4] = project_l2_mneg2(u); dc[5] = project_l2_mneg1(u); dc[6] = project_l2_m0(u); dc[7] = project_l2_m1(u); dc[8] = project_l2_m2(u); for(int i=0; i<9; ++i ) { sh.c[3*i + 0] += shscale * areaweight * rgba[0] * dc[i]; sh.c[3*i + 1] += shscale * areaweight * rgba[1] * dc[i]; sh.c[3*i + 2] += shscale * areaweight * rgba[2] * dc[i]; } totalarea += areaweight; } //complete the integration by dividing by total area scale( ref sh, 16f / totalarea ); }
public void UnregisterApplicator(mset.SkyApplicator app, HashSet<Renderer> renderersToClear) { skyApplicators.Remove(app); foreach(Renderer rend in renderersToClear) { if(_GlobalSky != null) _GlobalSky.Apply(rend,0); } }
public void RegisterApplicator(mset.SkyApplicator app) { skyApplicators.Add(app); foreach(Renderer rend in dynamicRenderers) { app.RendererInside(rend); } foreach(Renderer rend in staticRenderers) { app.RendererInside(rend); } }
static void scale( ref mset.SHEncoding sh, float s ) { for(int i=0; i<27; ++i) { sh.c[i] *= s; } }
public static void convolve(ref mset.SHEncoding sh) { convolve(ref sh, 1f, 2f/3f, 0.25f); }
public void QueueSkies(mset.Sky[] skiesToProbe) { if(this.probeQueue == null) this.probeQueue = new Queue<ProbeTarget>(); else this.probeQueue.Clear(); foreach(mset.Sky sky in skiesToProbe) { if(sky != null && (sky.SpecularCube as Cubemap) != null) { QueueCubemap(sky.SpecularCube as Cubemap, sky.HDRSpec, sky.transform.position, sky.transform.rotation); } } }
public void BlendToGlobalSky(mset.Sky next, float blendTime) { BlendToGlobalSky(next, blendTime, 0f); }
public void SnapToSky(mset.Sky nusky) { if(nusky == null) return; if(BindType == AnchorBindType.TargetSky) return; Blender.SnapToSky(nusky); HasLocalSky = true; }
private static void copySky(mset.Sky dest, mset.Sky src) { dest.diffuseCube = src.diffuseCube; dest.specularCube = src.specularCube; dest.skyboxCube = src.skyboxCube; dest.masterIntensity = src.masterIntensity; dest.skyIntensity = src.skyIntensity; dest.specIntensity = src.specIntensity; dest.diffIntensity = src.diffIntensity; dest.camExposure = src.camExposure; dest.specIntensityLM = src.specIntensityLM; dest.diffIntensityLM = src.diffIntensityLM; dest.hdrSky = src.hdrSky; dest.hdrSpec = src.hdrSpec; dest.hdrDiff = src.hdrDiff; dest.showSkybox = src.showSkybox; dest.linearSpace = src.linearSpace; dest.autoDetectColorSpace = src.autoDetectColorSpace; //for inspector use dest.hasDimensions = src.hasDimensions; dest.autoApply = src.autoApply; if(src.SH != null) { if(dest.SH == null) dest.SH = new mset.SHEncoding(); dest.SH.copyFrom(src.SH); } }
public static void generateSH(ref mset.Sky sky) { skyToGUI(sky.SkyboxCube, sky.HDRSky, null, refSKY, sky.name, false); skyToGUI(sky.SpecularCube, sky.HDRSpec, null, refSIM, sky.name, false); if( refSIM.computeSH ) { if( refSIM.cube != null ) { refSIM.update(); //refSIM.updateBuffers(); //Slow. Surely this is done after every change? sky.SH.copyFrom( refSIM.SH ); mset.SHUtil.convolve(ref sky.SH); } if( sky.SH != null ) { sky.SH.copyToBuffer(); } } }
public static void detectColorSpace(ref mset.Sky sky) { sky.LinearSpace = PlayerSettings.colorSpace == ColorSpace.Linear; #if UNITY_IPHONE || UNITY_ANDROID sky.LinearSpace = false; // no sRGB on mobile #endif }
private static bool GUIToSky(ref Texture skyCube, ref bool skyHDR, mset.SHEncoding skySH, mset.CubemapGUI cubeGUI) { //cubeGUI -> sky bool prevHDR = cubeGUI.HDR; Texture prevInput = cubeGUI.input; cubeGUI.drawGUI(); skyCube = cubeGUI.input; skyHDR = cubeGUI.HDR; bool dirty = false; //copy spherical harmonics if they've changed if( cubeGUI.computeSH ) { if( skySH != null ) { if(cubeGUI.SH == null) { skySH.clearToBlack(); dirty = true; } else if(!skySH.equals(cubeGUI.SH)) { skySH.copyFrom(cubeGUI.SH); dirty = true; } skySH.copyToBuffer(); } } //return true if the cubeGUI gui changed any parameters dirty |= prevHDR != cubeGUI.HDR; dirty |= prevInput != cubeGUI.input; return dirty; }
private static bool skyToGUI(Texture skyCube, bool skyHDR, mset.SHEncoding skySH, mset.CubemapGUI cubeGUI, string skyName, bool updatePreview) { bool dirty = false; bool dirtyGUI = false; //sky -> cubeGUI dirtyGUI |= cubeGUI.HDR != skyHDR; cubeGUI.HDR = skyHDR; cubeGUI.skyName = skyName; RenderTexture RT = skyCube as RenderTexture; if(cubeGUI.input != skyCube) { if(RT) { cubeGUI.setReference(RT, RT.useMipMap); } else if(skyCube) { string path = AssetDatabase.GetAssetPath(skyCube); cubeGUI.setReference(path, cubeGUI.mipmapped); } else { cubeGUI.clear(); } //dirty = true; } if(RT && skySH != null) { if(cubeGUI.SH != null && !skySH.equals(cubeGUI.SH)) { cubeGUI.SH.copyFrom(skySH); cubeGUI.SH.copyToBuffer(); //dirty = true; } } if( dirtyGUI && updatePreview ) { cubeGUI.updatePreview(); } return dirty; }
public void BlendToGlobalSky(mset.Sky next) { BlendToGlobalSky(next, GlobalBlendTime, 0f); }
public void BlendToSky(mset.Sky nusky) { if(nusky == null) return; //ignore if swaps if we are glued to a specific sky if(BindType == AnchorBindType.TargetSky) return; Blender.BlendToSky(nusky); HasLocalSky = true; }
public void SnapToGlobalSky(mset.Sky nusky) { SnapToSky(nusky); HasLocalSky = false; }
public void BlendToGlobalSky(mset.Sky nusky) { if(HasLocalSky) BlendToSky(nusky); HasLocalSky = false; }
public static void projectCube(ref mset.SHEncoding sh, Cubemap cube, int mip, bool hdr) { sh.clearToBlack(); float totalarea = 0f; ulong faceSize = (ulong)cube.width; mip = Mathf.Min(mset.QPow.Log2i(faceSize)+1, mip); faceSize = (ulong)(faceSize >> mip); float[] dc = new float[9]; Vector3 u = Vector3.zero; for(ulong face=0; face<6; ++face) { Color rgba = Color.black; Color[] pixels = cube.GetPixels((CubemapFace)face, mip); for(ulong y=0; y<faceSize; ++y) for(ulong x=0; x<faceSize; ++x) { //compute cube direction float areaweight = 1f; mset.Util.invCubeLookup(ref u, ref areaweight, face, x, y, faceSize); float shscale = 4f / 3f; ulong index = y*faceSize + x; if(hdr) mset.RGB.fromRGBM(ref rgba, pixels[index], true); else rgba = pixels[index]; //project on basis functions, and accumulate dc[0] = project_l0_m0(u); dc[1] = project_l1_mneg1(u); dc[2] = project_l1_m0(u); dc[3] = project_l1_m1(u); dc[4] = project_l2_mneg2(u); dc[5] = project_l2_mneg1(u); dc[6] = project_l2_m0(u); dc[7] = project_l2_m1(u); dc[8] = project_l2_m2(u); for(int i=0; i<9; ++i ) { sh.c[3*i + 0] += shscale * areaweight * rgba[0] * dc[i]; sh.c[3*i + 1] += shscale * areaweight * rgba[1] * dc[i]; sh.c[3*i + 2] += shscale * areaweight * rgba[2] * dc[i]; } totalarea += areaweight; } } //complete the integration by dividing by total area scale( ref sh, 16f / totalarea ); }
private void StartLightBlend(mset.Sky prev, mset.Sky next) { //get a list of lights and intensities from the sky we're blending away from prevLights = null; prevIntensities = null; if(prev) { prevLights = prev.GetComponentsInChildren<Light>(); if(prevLights != null && prevLights.Length > 0) { prevIntensities = new float[prevLights.Length]; for(int i=0; i<prevLights.Length; ++i) { prevLights[i].enabled = true; prevIntensities[i] = prevLights[i].intensity; } } } nextLights = null; nextIntensities = null; if(next) { nextLights = next.GetComponentsInChildren<Light>(); if(nextLights != null && nextLights.Length > 0) { nextIntensities = new float[nextLights.Length]; for(int i=0; i<nextLights.Length; ++i) { nextIntensities[i] = nextLights[i].intensity; nextLights[i].enabled = true; nextLights[i].intensity = 0f; } } } }
public static void convolve(ref mset.SHEncoding sh, float conv0, float conv1, float conv2) { for( int i=0; i<27; ++i ) { if(i<3) sh.c[i] *= conv0; else if(i<12) sh.c[i] *= conv1; else sh.c[i] *= conv2; } }
//Probes all skies in list of skies, and all sky components in list of game objects. Either list can be null when convenient. //If probeAll is false, only skies marked as "Is Probe" are considered public void ProbeSkies(GameObject[] objects, mset.Sky[] skies, bool probeAll, bool probeIBL) { int skipCount = 0; List<mset.Sky> probes = new List<mset.Sky>(); string notProbes = ""; if(skies != null) { foreach(mset.Sky sky in skies) { if(sky) { if(probeAll || sky.IsProbe) probes.Add(sky); else { skipCount++; notProbes += sky.name + "\n"; } } } } if(objects != null) { foreach(GameObject obj in objects) { mset.Sky sky = obj.GetComponent<mset.Sky>(); if(sky) { if(probeAll || sky.IsProbe) probes.Add(sky); else { skipCount++; notProbes += sky.name + "\n"; } } } } if(skipCount > 0) { #if UNITY_EDITOR bool k = UnityEditor.EditorUtility.DisplayDialog(skipCount + " skies not probes", "The following skies are not marked as probes and will be skipped:\n"+notProbes, "Ok", "Cancel"); if(!k) return; #endif } if(probes.Count > 0) { this.ProbeExposures = probeIBL ? Vector4.one : Vector4.zero; this.SkiesToProbe = new mset.Sky[probes.Count]; for(int i = 0; i < probes.Count; ++i) { this.SkiesToProbe[i] = probes[i]; } } }
//call once public void SnapToSky(mset.Sky nusky) { if(nusky == null) return; CurrentSky = PreviousSky = nusky; blendTimer = 0f; }
private static bool skyToGUI(ref Cubemap skyCube, ref bool skyHDR, mset.CubemapGUI cubeGUI, bool updatePreview) { bool dirty = false; bool dirtyGUI = false; //sky -> cubeGUI dirtyGUI |= cubeGUI.HDR != skyHDR; cubeGUI.HDR = skyHDR; if(cubeGUI.cube != skyCube) { if(skyCube) { string path = AssetDatabase.GetAssetPath(skyCube); cubeGUI.setReference(path, cubeGUI.mipmapped); } else { cubeGUI.clear(); } //dirty = true; } if( dirtyGUI && updatePreview ) { cubeGUI.updatePreview(); } return dirty; }
//call once public void BlendToSky(mset.Sky nusky) { if(nusky == null) return; if(CurrentSky != nusky) { //do some blending if(CurrentSky == null) { //nothing to blend from PreviousSky = CurrentSky = nusky; blendTimer = 0f; } else { PreviousSky = CurrentSky; CurrentSky = nusky; currentBlendTime = blendTime; blendTimer = currentBlendTime; } } }
private bool needsLinearSampling( mset.CubemapGUI cubegui ) { if( cubegui.HDR ) return !ps.gammaCompress; //non-gamma compression requires sRGB sampling bypassed return false; }
//returns whether or not an output cubemap should be generated/encoded with a gamma-curve private bool needsGamma( mset.CubemapGUI cubegui ) { if( cubegui.HDR ) return ps.gammaCompress; //toggle gamma curve by whether we want RGBM gamma compression on or off return true; //LDR data should always be saved as sRGB }
private void gatherLights(ref mset.CubeBuffer cube) { ps.lights = new Color[cube.pixels.Length]; mset.CubeBuffer.pixelCopy(ref ps.lights, 0, cube.pixels, 0, cube.pixels.Length); ps.lightCount = (ulong)ps.lights.LongLength; ulong faceSize = (ulong)cube.faceSize; ps.lightDirs = new mset.DirLookup[ps.lightCount]; Vector3 vec = new Vector3(); for( ulong face = 0; face<6; ++face ) for( ulong y=0; y<faceSize; ++y ) for( ulong x=0; x<faceSize; ++x ) { ulong i = face*faceSize*faceSize + y*faceSize + x; mset.Util.invCubeLookup(ref vec, ref ps.lightDirs[i].weight, face, x, y, faceSize); ps.lights[i] *= ps.lightDirs[i].weight; ps.lightDirs[i].weight = 1f; ps.lightDirs[i].x = vec.x; ps.lightDirs[i].y = vec.y; ps.lightDirs[i].z = vec.z; } }
private void EditorApplyToList(object[] renderers, mset.SkyApplicator[] apps, bool forceApply) { foreach(object mr in renderers) { Renderer rend = (Renderer)mr; //filter by ignored layers int layerFlag = 1 << rend.gameObject.layer; if( (IgnoredLayerMask & layerFlag) != 0 ) continue; if(!rend.gameObject.activeInHierarchy) continue; #if USE_PROPERTY_BLOCKS //HACK: force clear all property blocks just in case if(forceApply) { MaterialPropertyBlock pb = new MaterialPropertyBlock(); pb.Clear(); rend.SetPropertyBlock(pb); } #endif //mset.Sky.ScrubKeywords(rend.sharedMaterials); mset.SkyAnchor anchor = rend.gameObject.GetComponent<mset.SkyAnchor>(); if(anchor && !anchor.enabled) anchor = null; bool rendHasChanged = rend.transform.hasChanged || (anchor && anchor.HasChanged); bool localFound = false; if(anchor && anchor.BindType == mset.SkyAnchor.AnchorBindType.TargetSky) { anchor.Apply(); localFound = true; } //trigger stuff is only processed if the game will auto apply as well if(GameAutoApply && !localFound) { foreach(mset.SkyApplicator app in apps) { if(!app.gameObject.activeInHierarchy) continue; if(app.TargetSky) { if(forceApply || app.HasChanged || app.TargetSky.Dirty || rendHasChanged) { localFound |= app.ApplyInside(rend); app.TargetSky.Dirty = false; } } app.HasChanged = false; } } if(!localFound && _GlobalSky) { if(forceApply || _GlobalSky.Dirty || rendHasChanged) { _GlobalSky.Apply(rend,0); } } //HACK: we are checking and clearing hasChanged in a weird place during the editor loop. Hopefully that won't conflict with other plugins? rend.transform.hasChanged = false; if(anchor) anchor.HasChanged = false; } //this is always called in EditorUpdate, only run if forced externally if(forceApply && _GlobalSky) { _GlobalSky.Apply(0); if(_SkyboxMaterial) { _GlobalSky.Apply(_SkyboxMaterial, 0); } _GlobalSky.Dirty = false; } }