示例#1
0
        private static bool CaptureViews(
            Transform root,
            BillboardImposter imposter,
            Snapshots[] snapshots,
            Transform lightingRoot,
            Shader albedoBake,
            Shader normalBake,
            ComputeShader processCompute)
        {
            Vector3 originalScale = root.localScale;

            root.localScale = Vector3.one;
            var prevRt    = RenderTexture.active;
            var baseAtlas = RenderTexture.GetTemporary(_atlasResolution, _atlasResolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);

            baseAtlas.enableRandomWrite = true;
            baseAtlas.Create();

            var packAtlas = RenderTexture.GetTemporary(_atlasResolution, _atlasResolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);

            packAtlas.enableRandomWrite = true;
            packAtlas.Create();
            var tempAtlas = RenderTexture.GetTemporary(baseAtlas.descriptor);

            tempAtlas.Create();

            var frameReso = _atlasResolution / imposter.Frames;
            var frame     = RenderTexture.GetTemporary(frameReso, frameReso, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);

            frame.enableRandomWrite = true;
            frame.Create();

            var packFrame = RenderTexture.GetTemporary(frameReso, frameReso, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);

            packFrame.Create();

            var tempFrame = RenderTexture.GetTemporary(frame.descriptor);

            tempFrame.Create();

            var frameResUpscale = frameReso * 4;
            var superSizedFrame = RenderTexture.GetTemporary(frameResUpscale, frameResUpscale, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);

            superSizedFrame.enableRandomWrite = true;
            superSizedFrame.Create();

            var superSizedFrameTemp = RenderTexture.GetTemporary(superSizedFrame.descriptor);
            var superSizedAlphaMask = RenderTexture.GetTemporary(superSizedFrame.descriptor);

            superSizedAlphaMask.Create();

            imposter.BaseTexture = new Texture2D(baseAtlas.width, baseAtlas.height, TextureFormat.ARGB32, true, true);
            imposter.PackTexture = new Texture2D(baseAtlas.width, baseAtlas.height, TextureFormat.ARGB32, true, true);

            ComputeBuffer minDistancesBuffer = new ComputeBuffer(frame.width * frame.height, sizeof(float));
            ComputeBuffer maxDistanceBuffer  = new ComputeBuffer(1, sizeof(float));

            const int layer      = 30;
            var       clearColor = Color.clear;

            var camera = new GameObject().AddComponent <Camera>();

            camera.gameObject.hideFlags = HideFlags.DontSave;
            camera.cullingMask          = 1 << layer;
            camera.clearFlags           = CameraClearFlags.SolidColor;
            camera.backgroundColor      = clearColor;
            camera.orthographic         = true;
            camera.nearClipPlane        = 0f;
            camera.farClipPlane         = imposter.Radius * 2f;
            camera.orthographicSize     = imposter.Radius;
            camera.allowMSAA            = false;
            camera.enabled = false;

            var frameCount = imposter.Frames * imposter.Frames;

            var originalLayers = new Dictionary <GameObject, int>();

            StoreLayers(root, layer, ref originalLayers);

            var originalLights = new Dictionary <Light, bool>();
            var customLit      = lightingRoot != null;

            if (customLit)
            {
                var lights = FindObjectsOfType <Light>();
                for (var i = 0; i < lights.Length; i++)
                {
                    if (!lights[i].transform.IsChildOf(lightingRoot))
                    {
                        if (originalLights.ContainsKey(lights[i]))
                        {
                            continue;
                        }
                        originalLights.Add(lights[i], lights[i].enabled);
                        lights[i].enabled = false;
                    }
                    else
                    {
                        lights[i].enabled = true;
                        if (!originalLights.ContainsKey(lights[i]))
                        {
                            originalLights.Add(lights[i], false);
                        }
                    }
                }
            }

            var tempMinMaxRT = RenderTexture.GetTemporary(frame.width, frame.height, 0, RenderTextureFormat.ARGB32);

            tempMinMaxRT.Create();

            Graphics.SetRenderTarget(tempMinMaxRT);
            GL.Clear(true, true, Color.clear);

            camera.clearFlags      = CameraClearFlags.Nothing;
            camera.backgroundColor = clearColor;
            camera.targetTexture   = tempMinMaxRT;

            var min = Vector2.one * frame.width;
            var max = Vector2.zero;

            for (var i = 0; i < frameCount; i++)
            {
                if (i > snapshots.Length - 1)
                {
                    Debug.LogError("[Imposter] snapshot data length less than frame count! this shouldn't happen!");
                    continue;
                }

                //position camera with the current snapshot info
                var snap = snapshots[i];
                camera.transform.position = snap.Position;
                camera.transform.rotation = Quaternion.LookRotation(snap.Ray, Vector3.up);

                //render alpha only
                Shader.SetGlobalFloat("_ImposterRenderAlpha", 1f);
                camera.RenderWithShader(albedoBake, "");
                camera.ResetReplacementShader();

                //render without clearing (accumulating filled pixels)
                camera.Render();

                //supply the root position taken into camera space
                //this is for the min max, in the case root is further from opaque pixels
                var viewPos = camera.WorldToViewportPoint(root.position);
                var texPos  = new Vector2(viewPos.x, viewPos.y) * frame.width;
                texPos.x = Mathf.Clamp(texPos.x, 0f, frame.width);
                texPos.y = Mathf.Clamp(texPos.y, 0f, frame.width);
                min.x    = Mathf.Min(min.x, texPos.x);
                min.y    = Mathf.Min(min.y, texPos.y);
                max.x    = Mathf.Max(max.x, texPos.x);
                max.y    = Mathf.Max(max.y, texPos.y);
            }

            camera.clearFlags      = CameraClearFlags.SolidColor;
            camera.backgroundColor = clearColor;
            camera.targetTexture   = null;

            //now read render texture
            var tempMinMaxTex = new Texture2D(tempMinMaxRT.width, tempMinMaxRT.height, TextureFormat.ARGB32, false);

            RenderTexture.active = tempMinMaxRT;
            tempMinMaxTex.ReadPixels(new Rect(0f, 0f, tempMinMaxRT.width, tempMinMaxRT.height), 0, 0);
            tempMinMaxTex.Apply();

            var tempTexC = tempMinMaxTex.GetPixels32();

            //loop pixels get min max
            for (var c = 0; c < tempTexC.Length; c++)
            {
                if (tempTexC[c].r != 0x00)
                {
                    var texPos = Get2DIndex(c, tempMinMaxRT.width);
                    min.x = Mathf.Min(min.x, texPos.x);
                    min.y = Mathf.Min(min.y, texPos.y);
                    max.x = Mathf.Max(max.x, texPos.x);
                    max.y = Mathf.Max(max.y, texPos.y);
                }
            }

            DestroyImmediate(tempMinMaxTex, true);
            RenderTexture.ReleaseTemporary(tempMinMaxRT);

            //rescale radius
            var len   = new Vector2(max.x - min.x, max.y - min.y);
            var maxR  = Mathf.Max(len.x, len.y);
            var ratio = maxR / frame.width;

            imposter.Radius         = imposter.Radius * ratio;
            camera.farClipPlane     = imposter.Radius * 2f;
            camera.orthographicSize = imposter.Radius;

            Vector3 scaleFactor = new Vector3(root.localScale.x / originalScale.x, root.localScale.y / originalScale.y, root.localScale.z / originalScale.z);

            imposter.Offset = Vector3.Scale(imposter.Offset, scaleFactor);

            snapshots = UpdateSnapshots(imposter.Frames, imposter.Radius, root.position + imposter.Offset, imposter.IsHalf);


            for (var frameIndex = 0; frameIndex < frameCount; frameIndex++)
            {
                if (frameIndex > snapshots.Length - 1)
                {
                    Debug.LogError("[Imposter] snapshot data length less than frame count! this shouldn't happen!");
                    continue;
                }

                var snap = snapshots[frameIndex];
                camera.transform.position = snap.Position;
                camera.transform.rotation = Quaternion.LookRotation(snap.Ray, Vector3.up);
                clearColor = Color.clear;

                //target and clear base frame
                Graphics.SetRenderTarget(superSizedFrame);
                GL.Clear(true, true, clearColor);
                Graphics.SetRenderTarget(superSizedFrameTemp);
                GL.Clear(true, true, clearColor);

                camera.targetTexture   = superSizedFrameTemp;
                camera.backgroundColor = clearColor;

                if (!customLit)
                {
                    Shader.SetGlobalFloat("_ImposterRenderAlpha", 0f);
                    camera.RenderWithShader(albedoBake, "");
                    camera.ResetReplacementShader();
                }
                else
                {
                    camera.Render();
                }

                camera.targetTexture   = superSizedAlphaMask;
                camera.backgroundColor = clearColor;
                camera.Render();

                Graphics.Blit(superSizedAlphaMask, superSizedFrame, _processingMat, 3);
                Graphics.Blit(superSizedFrame, superSizedAlphaMask);

                _processingMat.SetTexture("_MainTex", superSizedFrameTemp);
                _processingMat.SetTexture("_MainTex2", superSizedAlphaMask);
                _processingMat.SetFloat("_Step", 1f);

                Graphics.Blit(superSizedFrameTemp, superSizedFrame, _processingMat, 1);

                Graphics.SetRenderTarget(frame);
                GL.Clear(true, true, clearColor);
                Graphics.Blit(superSizedFrame, frame);

                Graphics.SetRenderTarget(superSizedFrameTemp);
                GL.Clear(true, true, clearColor);
                Graphics.SetRenderTarget(superSizedFrame);
                GL.Clear(true, true, clearColor);

                clearColor             = new Color(0.0f, 0.0f, 0.0f, 0.5f);
                camera.targetTexture   = superSizedFrame;
                camera.backgroundColor = clearColor;
                camera.RenderWithShader(normalBake, "");
                camera.ResetReplacementShader();

                Graphics.SetRenderTarget(packFrame);
                GL.Clear(true, true, clearColor);
                Graphics.Blit(superSizedFrame, packFrame);


                Graphics.SetRenderTarget(tempFrame);
                GL.Clear(true, true, Color.clear);

                int threadsX, threadsY, threadsZ;
                CalcWorkSize(packFrame.width * packFrame.height, out threadsX, out threadsY, out threadsZ);
                processCompute.SetTexture(0, "Source", packFrame);
                processCompute.SetTexture(0, "SourceMask", frame);
                processCompute.SetTexture(0, "Result", tempFrame);
                processCompute.SetBool("AllChannels", true);
                processCompute.SetBool("NormalsDepth", true);
                processCompute.Dispatch(0, threadsX, threadsY, threadsZ);

                Graphics.Blit(tempFrame, packFrame);

                Graphics.SetRenderTarget(tempFrame);
                GL.Clear(true, true, Color.clear);

                CalcWorkSize(frame.width * frame.height, out threadsX, out threadsY, out threadsZ);
                processCompute.SetTexture(0, "Source", frame);
                processCompute.SetTexture(0, "SourceMask", frame);
                processCompute.SetTexture(0, "Result", tempFrame);
                processCompute.SetBool("AllChannels", false);
                processCompute.SetBool("NormalsDepth", false);
                processCompute.Dispatch(0, threadsX, threadsY, threadsZ);

                Graphics.Blit(tempFrame, frame);

                Graphics.SetRenderTarget(tempFrame);
                GL.Clear(true, true, Color.clear);

                CalcWorkSize(frame.width * frame.height, out threadsX, out threadsY, out threadsZ);
                processCompute.SetTexture(1, "Source", frame);
                processCompute.SetTexture(1, "SourceMask", frame);
                processCompute.SetBuffer(1, "MinDistances", minDistancesBuffer);
                processCompute.Dispatch(1, threadsX, threadsY, threadsZ);

                processCompute.SetInt("MinDistancesLength", minDistancesBuffer.count);
                processCompute.SetBuffer(2, "MaxOfMinDistances", maxDistanceBuffer);
                processCompute.SetBuffer(2, "MinDistances", minDistancesBuffer);
                processCompute.Dispatch(2, 1, 1, 1);

                CalcWorkSize(frame.width * frame.height, out threadsX, out threadsY, out threadsZ);
                processCompute.SetTexture(3, "Source", frame);
                processCompute.SetTexture(3, "SourceMask", frame);
                processCompute.SetTexture(3, "Result", tempFrame);
                processCompute.SetBuffer(3, "MinDistances", minDistancesBuffer);
                processCompute.SetBuffer(3, "MaxOfMinDistances", maxDistanceBuffer);
                processCompute.Dispatch(3, threadsX, threadsY, threadsZ);

                Graphics.Blit(tempFrame, frame);

                int x;
                int y;
                XYFromIndex(frameIndex, imposter.Frames, out x, out y);

                x *= frame.width;
                y *= frame.height;

                Graphics.CopyTexture(frame, 0, 0, 0, 0, frame.width, frame.height, baseAtlas, 0, 0, x, y);
                Graphics.CopyTexture(packFrame, 0, 0, 0, 0, packFrame.width, packFrame.height, packAtlas, 0, 0, x, y);
            }

            Graphics.SetRenderTarget(packAtlas);
            imposter.PackTexture.ReadPixels(new Rect(0f, 0f, packAtlas.width, packAtlas.height), 0, 0);

            Graphics.SetRenderTarget(baseAtlas);
            imposter.BaseTexture.ReadPixels(new Rect(0f, 0f, baseAtlas.width, baseAtlas.height), 0, 0);

            RenderTexture.active = prevRt;
            baseAtlas.Release();
            frame.Release();
            packAtlas.Release();
            packFrame.Release();

            RenderTexture.ReleaseTemporary(baseAtlas);
            RenderTexture.ReleaseTemporary(packAtlas);
            RenderTexture.ReleaseTemporary(tempAtlas);

            RenderTexture.ReleaseTemporary(frame);
            RenderTexture.ReleaseTemporary(packFrame);
            RenderTexture.ReleaseTemporary(tempFrame);

            RenderTexture.ReleaseTemporary(superSizedFrame);
            RenderTexture.ReleaseTemporary(superSizedAlphaMask);
            RenderTexture.ReleaseTemporary(superSizedFrameTemp);

            minDistancesBuffer.Dispose();
            maxDistanceBuffer.Dispose();

            DestroyImmediate(camera.gameObject, true);

            //restore layers
            RestoreLayers(originalLayers);

            //restore lights
            var enumerator2 = originalLights.Keys.GetEnumerator();

            while (enumerator2.MoveNext())
            {
                var light = enumerator2.Current;
                if (light != null)
                {
                    light.enabled = originalLights[light];
                }
            }

            enumerator2.Dispose();
            originalLights.Clear();

            var savePath   = "";
            var file       = "";
            var filePrefab = "";

            if (imposter.AssetReference != null)
            {
                savePath = AssetDatabase.GetAssetPath(imposter.AssetReference);
                var lastSlash = savePath.LastIndexOf("/", StringComparison.Ordinal);
                var folder    = savePath.Substring(0, lastSlash);
                file       = savePath.Substring(lastSlash + 1, savePath.LastIndexOf(".", StringComparison.Ordinal) - lastSlash - 1);
                filePrefab = file;
                savePath   = folder + "/" + file + "_Imposter" + ".asset";
            }
            else //no prefab, ask where to save
            {
                file     = root.name;
                savePath = EditorUtility.SaveFilePanelInProject("Save Billboard Imposter", file + "_Imposter", "asset", "Select save location");
            }

            imposter.PrefabSuffix = _suffix;
            imposter.name         = file;
            AssetDatabase.CreateAsset(imposter, savePath);

            imposter.Save(savePath, file, _createUnityBillboard);

            //spawn
            var spawned = imposter.Spawn(root.position, true, filePrefab);

            spawned.transform.position   = root.position + new Vector3(2f, 0f, 2f);
            spawned.transform.rotation   = root.rotation;
            spawned.transform.localScale = originalScale;

            root.localScale = originalScale;

            return(true);
        }