@@ -10,8 +10,13 @@ public class PixelCamera : MonoBehaviour
10
10
[ Serializable ]
11
11
protected class AdvancedSettings
12
12
{
13
+ [ Tooltip ( "Material to draw output render with" ) ]
13
14
public Material cameraMaterial ;
15
+ [ Tooltip ( "Stretches output display, for non square pixels" ) ]
14
16
public Vector2 aspectStretch = Vector2 . one ;
17
+ [ Tooltip ( "Scales down camera render size" ) ]
18
+ public float downSample = 1 ;
19
+ [ Tooltip ( "Z distance to draw as pixel perfect for perspective camera." ) ]
15
20
public float perspectiveZ = 10 ;
16
21
}
17
22
@@ -20,34 +25,46 @@ protected struct CamSettings
20
25
public int [ ] screenSize ;
21
26
public Vector2 aspect ;
22
27
public float zoomLevel ;
28
+ public float pixelsPerUnit ;
29
+ public float zDistance ;
30
+ public float downsample ;
23
31
public float fieldOfView ;
32
+ public float farPlane ;
24
33
public bool isOrtho ;
25
34
26
- public CamSettings ( Vector2 aspect , float zoomLevel , float fieldOfView , bool isOrtho )
35
+ public CamSettings ( PixelCamera pixelCam , Camera cam )
27
36
{
28
37
screenSize = new [ ] { Screen . width , Screen . height } ;
29
- this . aspect = aspect ;
30
- this . zoomLevel = zoomLevel ;
31
- this . fieldOfView = fieldOfView ;
32
- this . isOrtho = isOrtho ;
38
+ this . aspect = pixelCam . AspectStretch ;
39
+ this . zoomLevel = pixelCam . ZoomLevel ;
40
+ this . pixelsPerUnit = pixelCam . pixelsPerUnit ;
41
+ this . zDistance = pixelCam . PerspectiveZ ;
42
+ this . downsample = pixelCam . DownSample ;
43
+ this . fieldOfView = cam . fieldOfView ;
44
+ this . isOrtho = cam . orthographic ;
45
+ this . farPlane = cam . farClipPlane ;
33
46
}
34
47
35
48
public bool Equals ( CamSettings other )
36
49
{
37
50
bool equalScreen = other . screenSize [ 0 ] == screenSize [ 0 ] &&
38
51
other . screenSize [ 1 ] == screenSize [ 1 ] ;
39
52
bool equalAspect = other . aspect == aspect ;
40
- bool equalFoV = Math . Abs ( other . fieldOfView - fieldOfView ) <= float . Epsilon ;
41
- bool equalZoom = Math . Abs ( other . zoomLevel - zoomLevel ) <= float . Epsilon ;
42
- bool equalOrtho = other . isOrtho == isOrtho ;
43
- bool isEqual = equalScreen && equalAspect &&
44
- equalFoV && equalZoom &&
45
- equalOrtho ;
46
- //if (!isEqual)
47
- //{
48
- // Debug.LogFormat("scr {0}, asp {1}, fov {2}, zoom {3}", equalScreen, equalAspect, equalFoV, equalZoom);
49
- // Debug.LogFormat("Aspect: {0}, Other: {1}", aspect, other.aspect);
50
- //}
53
+
54
+ bool isEqual = other . isOrtho == isOrtho &&
55
+ equalScreen &&
56
+ equalAspect &&
57
+ Mathf . Approximately ( other . zoomLevel , zoomLevel ) &&
58
+ Mathf . Approximately ( other . pixelsPerUnit , pixelsPerUnit ) &&
59
+ Mathf . Approximately ( other . downsample , downsample ) ;
60
+
61
+ if ( isEqual && isOrtho == false )
62
+ {
63
+ isEqual &= Mathf . Approximately ( other . zDistance , zDistance ) &&
64
+ Mathf . Approximately ( other . fieldOfView , fieldOfView ) &&
65
+ Mathf . Approximately ( other . farPlane , farPlane ) ;
66
+ }
67
+
51
68
return isEqual ;
52
69
}
53
70
}
@@ -73,6 +90,9 @@ public bool Equals(CamSettings other)
73
90
public Vector2 QuadMin { get ; protected set ; }
74
91
public Vector2 QuadMax { get ; protected set ; }
75
92
93
+ /// <summary>
94
+ /// Material to draw output render with
95
+ /// </summary>
76
96
public Material CameraMaterial
77
97
{
78
98
get
@@ -107,22 +127,29 @@ public float PixelsPerUnit
107
127
set { pixelsPerUnit = value ; }
108
128
}
109
129
130
+ /// <summary>
131
+ /// For perspective cameras. Z distance between near and far plane to scale as pixel perfect.
132
+ /// </summary>
110
133
public float PerspectiveZ
111
134
{
112
135
get
113
136
{
114
137
if ( advancedSettings == null )
115
138
return cam . farClipPlane * 0.5f ;
116
- return advancedSettings . perspectiveZ ;
139
+ advancedSettings . perspectiveZ = Mathf . Clamp ( advancedSettings . perspectiveZ , cam . nearClipPlane , cam . farClipPlane ) ;
140
+ return advancedSettings . perspectiveZ ;
117
141
}
118
142
set
119
143
{
120
144
if ( advancedSettings == null )
121
145
return ;
122
- advancedSettings . perspectiveZ = value ;
146
+ advancedSettings . perspectiveZ = Mathf . Clamp ( value , cam . nearClipPlane , cam . farClipPlane ) ; ;
123
147
}
124
148
}
125
149
150
+ /// <summary>
151
+ /// Stretches output display, for non square pixels
152
+ /// </summary>
126
153
public Vector2 AspectStretch
127
154
{
128
155
get
@@ -139,8 +166,44 @@ public Vector2 AspectStretch
139
166
}
140
167
}
141
168
169
+ /// <summary>
170
+ /// Scales down camera render size. Clamped at minimum value of 1.
171
+ /// </summary>
172
+ public float DownSample
173
+ {
174
+ get
175
+ {
176
+ if ( advancedSettings == null )
177
+ return 1f ;
178
+ advancedSettings . downSample = Mathf . Max ( 1f , advancedSettings . downSample ) ;
179
+ return advancedSettings . downSample ;
180
+ }
181
+ set
182
+ {
183
+ if ( advancedSettings == null )
184
+ return ;
185
+ advancedSettings . downSample = Mathf . Max ( 1f , value ) ;
186
+ }
187
+ }
188
+
189
+ /// <summary>
190
+ /// The render texture camera is being drawn into
191
+ /// </summary>
142
192
public RenderTexture RenderTexture { get { return renderTexture ; } }
143
- public int [ ] CameraSize { get { return new int [ ] { renderTexture . width , renderTexture . height } ; } }
193
+
194
+ /// <summary>
195
+ /// Pixel size of the camera
196
+ /// </summary>
197
+ public int [ ] CameraSize
198
+ {
199
+ get
200
+ {
201
+ if ( renderTexture == null )
202
+ return new [ ] { 0 , 0 } ;
203
+
204
+ return new [ ] { renderTexture . width , renderTexture . height } ;
205
+ }
206
+ }
144
207
145
208
private void Reset ( )
146
209
{
@@ -167,7 +230,11 @@ private void Start()
167
230
168
231
protected virtual void OnEnable ( )
169
232
{
170
- lastSettings = new CamSettings ( AspectStretch , 0 , cam . fieldOfView , cam . orthographic ) ;
233
+ lastSettings = new CamSettings ( this , cam )
234
+ {
235
+ screenSize = new [ ] { 0 , 0 }
236
+ } ;
237
+ ForceRefresh ( ) ;
171
238
172
239
falseCamGO = new GameObject ( "False Camera" ) { hideFlags = HideFlags . HideAndDontSave } ;
173
240
falseCam = falseCamGO . AddComponent < Camera > ( ) ;
@@ -205,40 +272,15 @@ protected virtual void OnDisable()
205
272
falseCam = null ;
206
273
}
207
274
208
- protected Vector2 GetScreenRenderSize ( )
275
+ private void SetupCamera ( CamSettings settings )
209
276
{
210
- // For orthographic camera, physical render size is based on screen pixels
211
- Vector2 screenRenderSize = new Vector2 ( Screen . width , Screen . height ) ;
212
- screenRenderSize /= zoomLevel ;
213
-
214
- // For perspective camera, physical render is based on world unit height
215
- // in terms of fustrum distance, converted to pixels
216
- if ( cam . orthographic == false )
217
- {
218
- cam . aspect = ( float ) Screen . width / Screen . height ;
219
-
220
- float zDistance = PerspectiveZ ;
221
-
222
- var frustumHeight = 2.0f * zDistance * Mathf . Tan ( cam . fieldOfView * 0.5f * Mathf . Deg2Rad ) ;
223
- var frustumWidth = frustumHeight * cam . aspect ;
224
-
225
- screenRenderSize . x = frustumWidth ;
226
- screenRenderSize . y = frustumHeight ;
227
- screenRenderSize *= pixelsPerUnit ;
228
- }
229
-
230
- return screenRenderSize ;
231
- }
232
-
233
- private void SetupCamera ( )
234
- {
235
- var aspect = AspectStretch ;
277
+ var aspect = settings . aspect ;
236
278
237
279
zoomLevel = Mathf . Max ( 0.05f , Mathf . Abs ( zoomLevel ) ) * Math . Sign ( zoomLevel ) ;
238
280
// "Physical" pixel render size
239
281
Vector2 screenRenderSize = GetScreenRenderSize ( ) ;
240
282
// Pixel render size
241
- int [ ] pixelRenderSize = GetRenderTextureSize ( screenRenderSize , aspect ) ;
283
+ int [ ] pixelRenderSize = GetRenderTextureSize ( screenRenderSize , settings . aspect ) ;
242
284
243
285
float targetAspect = ( float ) pixelRenderSize [ 0 ] / ( float ) pixelRenderSize [ 1 ] ;
244
286
cam . aspect = targetAspect ;
@@ -269,7 +311,9 @@ private void SetupCamera()
269
311
renderTexture . Release ( ) ;
270
312
271
313
// Create new render texture
272
- renderTexture = new RenderTexture ( pixelRenderSize [ 0 ] , pixelRenderSize [ 1 ] , 0 )
314
+ Vector2 renderSize = new Vector2 ( pixelRenderSize [ 0 ] , pixelRenderSize [ 1 ] ) / settings . downsample ;
315
+ int [ ] actualRenderSize = GetRenderTextureSize ( renderSize , Vector2 . one ) ;
316
+ renderTexture = new RenderTexture ( actualRenderSize [ 0 ] , actualRenderSize [ 1 ] , 0 )
273
317
{
274
318
useMipMap = true ,
275
319
filterMode = FilterMode . Point ,
@@ -282,13 +326,46 @@ private void SetupCamera()
282
326
fallbackMaterial . SetTexture ( "_MainTex" , renderTexture ) ;
283
327
if ( advancedSettings != null )
284
328
CameraMaterial = advancedSettings . cameraMaterial ;
285
-
286
- lastSettings = new CamSettings ( aspect , zoomLevel , cam . fieldOfView , cam . orthographic ) ;
329
+
330
+ lastSettings = settings ;
287
331
288
332
cam . Render ( ) ;
289
333
camDraw . DrawQuad ( ) ;
290
334
}
291
335
336
+ private float GetPerspectiveHeight ( float z )
337
+ {
338
+ var frustumHeight = 2.0f * z * Mathf . Tan ( cam . fieldOfView * 0.5f * Mathf . Deg2Rad ) ;
339
+ return frustumHeight ;
340
+ }
341
+
342
+ protected Vector2 GetScreenRenderSize ( )
343
+ {
344
+ // For orthographic camera, physical render size is based on screen pixels
345
+ Vector2 screenRenderSize = new Vector2 ( Screen . width , Screen . height ) ;
346
+ screenRenderSize /= zoomLevel ;
347
+
348
+ // For perspective camera, physical render is based on world unit height
349
+ // in terms of fustrum distance, converted to pixels
350
+ if ( cam . orthographic == false )
351
+ {
352
+ cam . aspect = ( float ) Screen . width / Screen . height ;
353
+
354
+ float scale = Mathf . InverseLerp ( cam . nearClipPlane , cam . farClipPlane , PerspectiveZ ) ;
355
+ float maxHeight = GetPerspectiveHeight ( cam . farClipPlane ) ;
356
+ float minHeight = GetPerspectiveHeight ( cam . nearClipPlane ) ;
357
+
358
+ float height = Mathf . Lerp ( minHeight , maxHeight , scale ) ;
359
+ float width = height * cam . aspect ;
360
+
361
+ screenRenderSize . x = width ;
362
+ screenRenderSize . y = height ;
363
+ screenRenderSize *= pixelsPerUnit ;
364
+ }
365
+
366
+ return screenRenderSize ;
367
+ }
368
+
292
369
/// <summary>
293
370
/// The integer width and height of the texture to render to
294
371
/// </summary>
@@ -361,10 +438,10 @@ public void ForceRefresh()
361
438
362
439
public bool CheckCamera ( )
363
440
{
364
- var currentSettings = new CamSettings ( AspectStretch , zoomLevel , cam . fieldOfView , cam . orthographic ) ;
441
+ var currentSettings = new CamSettings ( this , cam ) ;
365
442
bool didChange = currentSettings . Equals ( lastSettings ) == false ;
366
443
if ( didChange )
367
- SetupCamera ( ) ;
444
+ SetupCamera ( currentSettings ) ;
368
445
return didChange ;
369
446
}
370
447
}
0 commit comments