chenxin
2020-12-04 b66ebdf748f0f8ca0384fb80df379584ab0c9314
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
using UnityEngine;
using UnityEditor;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
 
/// <summary>
/// 粒子特效截屏导出脚本,挂在粒子特效身上,按Q键开始截屏
/// </summary>
public class ParticleExporter : MonoBehaviour
{
    // Default folder name where you want the animations to be output
    public string folder = "PNG_Animations";
 
    // Framerate at which you want to play the animation
    public int frameRate = 25;     // export frame rate 导出帧率,设置Time.captureFramerate会忽略真实时间,直接使用此帧率
    public float frameCount = 100;    // export frame count 导出帧的数目,100帧则相当于导出5秒钟的光效时间。由于导出每一帧的时间很长,所以导出时间会远远长于直观的光效播放时间
    public int screenWidth = 960;    // not use 暂时没用,希望可以直接设置屏幕的大小(即光效画布的大小)
    public int screenHeight = 640;
    public Vector3 cameraPosition = Vector3.zero;
    public Vector3 cameraRotation = Vector3.zero;
 
    private string realFolder = ""; // real folder where the output files will be
    private float originaltimescaleTime; // track the original time scale so we can freeze the animation between frames
    private float currentTime = 0;
    private bool over = false;
    private int currentIndex = 0;
    private Camera exportCamera; // camera for export 导出光效的摄像机,使用RenderTexture
 
    private ParticleSystem particleSystem;
    public void Start()
    {
        particleSystem = GetComponent<ParticleSystem>();
        // set frame rate
        Time.captureFramerate = frameRate;
 
        // Create a folder that doesn't exist yet. Append number if necessary.
        realFolder = Path.Combine(folder, name);//该路径在Asset同级目录下
 
        // Create the folder
        if (!Directory.Exists(realFolder))
        {
            Debug.Log(realFolder);
            Directory.CreateDirectory(realFolder);
        }
 
        originaltimescaleTime = Time.timeScale;
 
        GameObject goCamera = Camera.main.gameObject;
        if (cameraPosition != Vector3.zero)
        {
            goCamera.transform.position = cameraPosition;
        }
 
        if (cameraRotation != Vector3.zero)
        {
            goCamera.transform.rotation = Quaternion.Euler(cameraRotation);
        }
 
        GameObject go = Instantiate(goCamera) as GameObject;
        exportCamera = go.GetComponent<Camera>();
 
        currentTime = 0;
 
 
    }
 
    bool startCapture = false;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            startCapture = !startCapture;
            particleSystem.Play();
        }
        if (startCapture)
        {
            currentTime += Time.deltaTime;
            if (!over && currentIndex >= frameCount)
            {
                over = true;
                Cleanup();
                Debug.Log("Finish");
                return;
            }
 
            // 每帧截屏
            StartCoroutine(CaptureFrame());
        }
 
    }
 
    void Cleanup()
    {
        DestroyImmediate(exportCamera);
        DestroyImmediate(gameObject);
    }
 
    IEnumerator CaptureFrame()
    {
        // Stop time
        Time.timeScale = 0;
        // Yield to next frame and then start the rendering
        // this is important, otherwise will have error
        yield return new WaitForEndOfFrame();
 
        string filename = String.Format("{0}/{1:D04}.png", realFolder, ++currentIndex);
        Debug.Log(filename);
 
        int width = Screen.width;
        int height = Screen.height;
 
        //Initialize and render textures
        RenderTexture blackCamRenderTexture = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32);
        RenderTexture whiteCamRenderTexture = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32);
 
        exportCamera.targetTexture = blackCamRenderTexture;
        exportCamera.backgroundColor = Color.black;
        exportCamera.Render();
        RenderTexture.active = blackCamRenderTexture;
        Texture2D texb = GetTex2D();
 
        //Now do it for Alpha Camera
        exportCamera.targetTexture = whiteCamRenderTexture;
        exportCamera.backgroundColor = Color.white;
        exportCamera.Render();
        RenderTexture.active = whiteCamRenderTexture;
        Texture2D texw = GetTex2D();
 
        // If we have both textures then create final output texture
        if (texw && texb)
        {
            Texture2D outputtex = new Texture2D(width, height, TextureFormat.ARGB32, false);
 
            // we need to check alpha ourselves,because particle use additive shader
            // Create Alpha from the difference between black and white camera renders
            for (int y = 0; y < outputtex.height; ++y)
            { // each row
                for (int x = 0; x < outputtex.width; ++x)
                { // each column
                    float alpha;
                    alpha = texw.GetPixel(x, y).r - texb.GetPixel(x, y).r;
                    alpha = 1.0f - alpha;
                    Color color;
                    if (alpha == 0)
                    {
                        color = Color.clear;
                    }
                    else
                    {
                        color = texb.GetPixel(x, y);
                    }
                    color.a = alpha;
                    outputtex.SetPixel(x, y, color);
                }
            }
 
 
            // Encode the resulting output texture to a byte array then write to the file
            byte[] pngShot = outputtex.EncodeToPNG();
            File.WriteAllBytes(filename, pngShot);
 
            // cleanup, otherwise will memory leak
            pngShot = null;
            RenderTexture.active = null;
            DestroyImmediate(outputtex);
            outputtex = null;
            DestroyImmediate(blackCamRenderTexture);
            blackCamRenderTexture = null;
            DestroyImmediate(whiteCamRenderTexture);
            whiteCamRenderTexture = null;
            DestroyImmediate(texb);
            texb = null;
            DestroyImmediate(texw);
            texb = null;
 
            System.GC.Collect();
 
            // Reset the time scale, then move on to the next frame.
            Time.timeScale = originaltimescaleTime;
        }
    }
 
    // Get the texture from the screen, render all or only half of the camera
    private Texture2D GetTex2D()
    {
        // Create a texture the size of the screen, RGB24 format
        int width = Screen.width;
        int height = Screen.height;
        Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
        // Read screen contents into the texture
        tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        tex.Apply();
        return tex;
    }
}