Reputation: 305
void LateUpdate()
{
takeHiResShot = Input.GetKeyDown("k");
resWidth = 256;
resHeight = 256;
if (takeHiResShot)
{
for (int i = 0; i < 20; ++i)
{
Vector3 buffer_x = new Vector3((int)rift.transform.eulerAngles.x + 1, (int)rift.transform.eulerAngles.y, (int)rift.transform.eulerAngles.z);
rift.transform.eulerAngles = buffer_x;
int y_buf = 160;
for (int j = 0; j < 5; ++j)
{
Vector3 buffer_y = new Vector3((int)rift.transform.eulerAngles.x, (int)rift.transform.eulerAngles.y + 1, (int)rift.transform.eulerAngles.z);
rift.transform.eulerAngles = buffer_y;
Debug.Log(string.Format("i: {0}, j: {1}, eulerangles: {2}", i, j, rift.transform.eulerAngles));
RenderTexture rt = new RenderTexture(resWidth, resHeight, 24);
camera.targetTexture = rt;
Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
camera.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
camera.targetTexture = null;
RenderTexture.active = null; // JC: added to avoid errors
Destroy(rt);
byte[] bytes = screenShot.EncodeToPNG();
string filename = ScreenShotName(rift.transform.eulerAngles, max_x, max_y);
System.IO.File.WriteAllBytes(filename, bytes);
takeHiResShot = false;
}
Vector3 buffer_reset = new Vector3((int)rift.transform.eulerAngles.x, y_buf, (int)rift.transform.eulerAngles.z);
rift.transform.eulerAngles = buffer_reset;
}
}
}
I need to take photograph of a 3d object rift
from different x and y euler angles. My Code works(for the most part) with initializing x=-20 and y=-5 and adding 1. But the code gets stuck at x=-16 and doesn't get any pictures beyond that. I am not understanding my bug at all and have been scratching my head for >3 hrs. How can I correct this?
Logs, if I dont make much sense:
i: 1, j: 0, eulerangles: (342.0, 161.0, 0.0)
i: 1, j: 1, eulerangles: (342.0, 162.0, 0.0)
i: 1, j: 2, eulerangles: (342.0, 163.0, 0.0)
i: 1, j: 3, eulerangles: (342.0, 164.0, 0.0)
i: 1, j: 4, eulerangles: (342.0, 165.0, 0.0)
i: 2, j: 0, eulerangles: (343.0, 161.0, 0.0)
i: 2, j: 1, eulerangles: (343.0, 162.0, 0.0)
i: 2, j: 2, eulerangles: (343.0, 163.0, 0.0)
i: 2, j: 3, eulerangles: (343.0, 164.0, 0.0)
i: 2, j: 4, eulerangles: (343.0, 165.0, 0.0)
i: 3, j: 0, eulerangles: (344.0, 161.0, 0.0)
i: 3, j: 1, eulerangles: (344.0, 162.0, 0.0)
i: 3, j: 2, eulerangles: (344.0, 163.0, 0.0)
i: 3, j: 3, eulerangles: (344.0, 164.0, 0.0)
i: 3, j: 4, eulerangles: (344.0, 165.0, 0.0)
i: 4, j: 0, eulerangles: (344.0, 161.0, 0.0)
i: 4, j: 1, eulerangles: (344.0, 162.0, 0.0)
i: 4, j: 2, eulerangles: (344.0, 163.0, 0.0)
Assuming that it might be a problem for eulerangles to be incremented the way I am doing, I tried using rift.transform.Rotate
with Vector3(1.0F, 0.0F, 0.0F)
for x axis rotation(outer loop) and Vector3(0.0F, 1.0F, 0.0F)
for y axis rotation(inner loop). It also gets stuck at x_angle = 9. I am not sure why rotation is getting stuck.
Logs(I am not incrementing inner loop in this version, so 175.0 values are intentional) :
i: 7, j: 4, eulerangles: (8.0, 175.0, 0.0)
i: 8, j: 0, eulerangles: (9.0, 175.0, 0.0)
i: 8, j: 1, eulerangles: (9.0, 175.0, 0.0)
i: 8, j: 2, eulerangles: (9.0, 175.0, 0.0)
i: 8, j: 3, eulerangles: (9.0, 175.0, 0.0)
i: 8, j: 4, eulerangles: (9.0, 175.0, 0.0)
i: 9, j: 0, eulerangles: (9.0, 175.0, 0.0)
i: 9, j: 1, eulerangles: (9.0, 175.0, 0.0)
i: 9, j: 2, eulerangles: (9.0, 175.0, 0.0)
i: 9, j: 3, eulerangles: (9.0, 175.0, 0.0)
i: 9, j: 4, eulerangles: (9.0, 175.0, 0.0)
i: 10, j: 0, eulerangles: (9.0, 175.0, 0.0)
i
stopped incrementing again at i=9 and continues with same value till i=19(end of loop).
New Code :
Vector3 GenerateXBuffer(Vector3 eulerAngles)
{
Vector3 x_buffer;
x_buffer = new Vector3((int)eulerAngles.x + 2, (int)eulerAngles.y, (int)eulerAngles.z);
return x_buffer;
}
Vector3 GenerateYBuffer(Vector3 eulerAngles)
{
Vector3 y_buffer;
y_buffer = new Vector3((int)eulerAngles.x, (int)eulerAngles.y + 2, (int)eulerAngles.z);
return y_buffer;
}
void StartTakingPictures()
{
for (int i = 0; i < 20; ++i)
{
rift.transform.eulerAngles = GenerateXBuffer(rift.transform.eulerAngles);
int y_buf = 175;
for (int j = 0; j < 5; ++j)
{
rift.transform.eulerAngles = GenerateYBuffer(rift.transform.eulerAngles);
Debug.Log(string.Format("i: {0}, j: {1}, eulerangles: {2}", i, j, rift.transform.eulerAngles));
RenderTexture rt = new RenderTexture(resWidth, resHeight, 24);
camera.targetTexture = rt;
Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
camera.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
camera.targetTexture = null;
RenderTexture.active = null; // JC: added to avoid errors
Destroy(rt);
byte[] bytes = screenShot.EncodeToPNG();
string filename = ScreenShotName(rift.transform.eulerAngles, max_x, max_y);
System.IO.File.WriteAllBytes(filename, bytes);
takeHiResShot = false;
}
Vector3 buffer_reset = new Vector3((int)rift.transform.eulerAngles.x, y_buf, (int)rift.transform.eulerAngles.z);
rift.transform.eulerAngles = buffer_reset;
}
}
void LateUpdate()
{
takeHiResShot = Input.GetKeyDown("k");
resWidth = 256;
resHeight = 256;
if (takeHiResShot)
{
StartTakingPictures();
}
}
Hi @Aizen, as you suggested, I took the calculation out of the update loop and it did help. I am now getting 82 images (was getting 56 before), although I should be getting a 100. Can you see anymore errors that might be causing problems?
Upvotes: 4
Views: 134
Reputation: 8546
You have 2 problems here:
You are manipulating rotations dangerously (see the docs);
You are manipulating floating points numbers dangerously (see the docs).
Unity stores and manipulates all rotations internally as Quaternions, not as Euler Angles, and they had their reasons to do so. Hence, Transform.rotation
is a field of type Quaternion
. Quaternions are less intuitive for people to use so in most situations you want to apply rotations as separate Euler components. That's why they added properties like Transform.eulerAngles
, that returns and takes a Vector3
.
However, when you set this property, like rift.transform.eulerAngles = buffer_x;
there is no Vector3
backing field in the Transform
class storing the same values you passed. Instead, It is converted to Quaternion
and stored in the backing field of Transform.rotation
. Similarly, when you get this property, its internal Quaternion
value is converted into a Vector3
and returned. As a consquence of those 2 internal operations, the value you get back from this property may not be the same value as you passed to it.
I suggest you to do this experiment. Try this snippet inside any reachable part of your Component script:
for (float i = 0f; i <= 360f; i++)
{
rift.transform.eulerAngles = new Vector3(i, 0, 0);
Debug.Log(i.ToString("R") + " -> " + rift.transform.eulerAngles.x.ToString("R"));
}
And take a look at the log:
0 -> 0
1 -> 1
2 -> 2
3 -> 3
4 -> 4
5 -> 5.00000048
6 -> 6
7 -> 7.00000143
8 -> 8
9 -> 9.000001
10 -> 9.999999
11 -> 11
12 -> 12
13 -> 13.000001
14 -> 14
15 -> 15.0000019
16 -> 16.0000038
17 -> 17
18 -> 18.0000019
19 -> 18.9999981
20 -> 20.0000038
21 -> 21
22 -> 22.0000038
23 -> 22.9999981
24 -> 24.0000019
25 -> 25
26 -> 25.9999981
27 -> 27
28 -> 28
29 -> 29
30 -> 30.0000038
31 -> 31.0000019
32 -> 32
33 -> 33
34 -> 34
35 -> 34.9999962
36 -> 36.0000038
37 -> 36.9999962
38 -> 37.9999962
39 -> 39.0000038
40 -> 40.0000076
41 -> 41.0000038
42 -> 42.0000038
43 -> 43.0000038
44 -> 43.9999962
45 -> 45.0000038
46 -> 46
47 -> 47.0000038
48 -> 48
49 -> 49.0000038
50 -> 50.00001
51 -> 51
52 -> 52.0000038
53 -> 52.9999962
54 -> 54.0000038
55 -> 55.0000076
56 -> 56.00001
57 -> 57.0000038
58 -> 58
59 -> 59
60 -> 60.0000038
61 -> 61.0000038
62 -> 61.9999962
63 -> 62.9999924
64 -> 64
65 -> 65
66 -> 66.00001
67 -> 67
68 -> 68.00001
69 -> 69.00001
70 -> 70.0000153
71 -> 71.00001
72 -> 72
73 -> 73.00001
74 -> 74
75 -> 75
76 -> 76.0000153
77 -> 77.0000153
78 -> 78.00002
79 -> 79
80 -> 80.00003
81 -> 80.9999847
82 -> 82.0000153
83 -> 83.00002
84 -> 84.0000153
85 -> 85.00005
86 -> 86.00002
87 -> 87.00004
88 -> 88.00002
89 -> 89.00005
90 -> 90
91 -> 89.00005
92 -> 88.00002
93 -> 87.00004
94 -> 86.00002
95 -> 85.00001
96 -> 84.0000153
97 -> 83.00002
98 -> 81.99998
99 -> 80.9999847
100 -> 80.0000153
101 -> 79
102 -> 78.00001
103 -> 77.0000153
104 -> 76
105 -> 75
106 -> 74.0000153
107 -> 73.0000153
108 -> 72.0000153
109 -> 71.00001
110 -> 70.0000153
111 -> 69.00001
112 -> 68.0000153
113 -> 67
114 -> 66.00001
115 -> 64.99999
116 -> 64
117 -> 63.00001
118 -> 61.9999962
119 -> 61.0000038
120 -> 60.0000038
121 -> 59
122 -> 58.0000076
123 -> 57.0000038
124 -> 56.0000038
125 -> 55.0000038
126 -> 54.0000076
127 -> 53.0000038
128 -> 52.0000038
129 -> 51.0000076
130 -> 50
131 -> 49.0000076
132 -> 48
133 -> 47.0000038
134 -> 46.00001
135 -> 45.0000038
136 -> 44.0000076
137 -> 43.0000038
138 -> 42
139 -> 40.9999962
140 -> 40.0000038
141 -> 39.0000076
142 -> 37.9999962
143 -> 37.0000076
144 -> 36
145 -> 35
146 -> 34.0000076
147 -> 32.9999962
148 -> 32.0000038
149 -> 31.0000019
150 -> 30.0000038
151 -> 28.9999924
152 -> 28
153 -> 27.0000076
154 -> 25.9999981
155 -> 25.0000038
156 -> 23.9999962
157 -> 23
158 -> 22.0000076
159 -> 21
160 -> 20.0000076
161 -> 18.9999943
162 -> 18.0000038
163 -> 17.0000076
164 -> 16.0000038
165 -> 15.00001
166 -> 13.999999
167 -> 13.0000038
168 -> 11.9999952
169 -> 11.000001
170 -> 10.0000076
171 -> 8.999999
172 -> 8.000005
173 -> 6.999997
174 -> 6.000002
175 -> 5.000008
176 -> 4
177 -> 3.00000525
178 -> 1.9999975
179 -> 1.000003
180 -> -5.008956E-06
181 -> 359
182 -> 358
183 -> 357
184 -> 356
185 -> 355
186 -> 354
187 -> 353
188 -> 352
189 -> 351
190 -> 350
191 -> 349
192 -> 348
193 -> 347
194 -> 346
195 -> 345
196 -> 344
197 -> 343
198 -> 342
199 -> 341
200 -> 340
201 -> 339
202 -> 338
203 -> 337
204 -> 336
205 -> 335
206 -> 334
207 -> 333
208 -> 332
209 -> 331
210 -> 330
211 -> 329
212 -> 328
213 -> 327
214 -> 326
215 -> 325
216 -> 324
217 -> 323
218 -> 322
219 -> 321
220 -> 320
221 -> 319
222 -> 318
223 -> 317
224 -> 316
225 -> 315
226 -> 314
227 -> 313
228 -> 312
229 -> 311
230 -> 310
231 -> 309
232 -> 308
233 -> 307
234 -> 306
235 -> 305
236 -> 304
237 -> 303
238 -> 302
239 -> 301
240 -> 300
241 -> 299
242 -> 298
243 -> 297
244 -> 296
245 -> 295
246 -> 294
247 -> 293
248 -> 292
249 -> 290.999969
250 -> 290
251 -> 289
252 -> 288
253 -> 287
254 -> 285.999969
255 -> 285
256 -> 284
257 -> 283
258 -> 282
259 -> 280.999969
260 -> 280
261 -> 279
262 -> 277.999969
263 -> 277.000031
264 -> 275.999939
265 -> 275
266 -> 273.999939
267 -> 272.999878
268 -> 271.999969
269 -> 270.999939
270 -> 270
271 -> 270.999939
272 -> 271.999969
273 -> 273.000031
274 -> 273.999969
275 -> 275
276 -> 276
277 -> 276.999969
278 -> 278
279 -> 279
280 -> 280
281 -> 281
282 -> 282
283 -> 283
284 -> 284
285 -> 285
286 -> 285.999969
287 -> 287
288 -> 288
289 -> 289
290 -> 290
291 -> 290.999969
292 -> 292
293 -> 293
294 -> 294
295 -> 295
296 -> 296
297 -> 297
298 -> 298
299 -> 299
300 -> 300
301 -> 301
302 -> 302
303 -> 303
304 -> 304
305 -> 305
306 -> 305.999969
307 -> 307
308 -> 308
309 -> 309
310 -> 310
311 -> 311
312 -> 312
313 -> 313
314 -> 314
315 -> 315
316 -> 316
317 -> 317
318 -> 318
319 -> 319
320 -> 320
321 -> 320.999969
322 -> 322
323 -> 323
324 -> 324
325 -> 325
326 -> 326
327 -> 327
328 -> 328
329 -> 329
330 -> 330
331 -> 331
332 -> 332
333 -> 333
334 -> 334
335 -> 335
336 -> 336
337 -> 337
338 -> 338
339 -> 339
340 -> 340
341 -> 341
342 -> 342
343 -> 343
344 -> 344
345 -> 344.999969
346 -> 346
347 -> 347
348 -> 348
349 -> 349
350 -> 349.999969
351 -> 351
352 -> 352
353 -> 353
354 -> 354
355 -> 354.999969
356 -> 356
357 -> 357
358 -> 358
359 -> 359
360 -> 1.00179122E-05
Now, look for the output corresponding to i = 345f
and you'll see 344.999969
. Have you figured it out, now? Well, in your code, in the i = 3
iteration, you set rift.transform.eulerAngles
with the value 345f
as the x
component. Then, in the next iteration you do (int)rift.transform.eulerAngles.x
. That will resolve to (int)344.999969
, that is 344
again, and not 345
!! (Remember that explicit conversion from float
to int
just removes the fractionary part, no rounding). It keeps repeating this result from this point onward, that's why your increment stucks.
That's one of the reasons that Unity considers it a mistaken approach and says:
the mistake here is that we are reading, modifying then writing the Euler values from a quaternion. Because these values calculated from a Quaternion, each new rotation may return very different Euler angles, which may suffer from gimbal lock.
Now is an appropriate moment to mention gimbal lock. I will not dive into this, but I very recommend the reading. Moreover, take a look at the log between i = 90f
and i = 270f
to see the danger of what you are doing.
By the way... why are you ever converting the Euler components to int
at all? I can't see why is it necessary there. You can just use the float values and increment them all the way. You could even use a float iteration variable in the do loop, just like in my snippet before.
Avoid the pratice of assuming a whole-number representation from a floating point value. Applying simple operations on a float can break this assumption, as well as using high numbers. Look this:
int a = 1000;
float x = Mathf.Sqrt(a) * Mathf.Sqrt(a);
Debug.Log("a: " + a + "; x: " + x.ToString("R") + " -> (int)x: " + (int)x);
// a: 1000; x: 999.999939 -> (int)x: 999
a = 100000001;
x = a;
Debug.Log("a: " + a + "; x: " + x.ToString("R") + " -> (int)x: " + (int)x);
// a: 100000001; x: 1E+08 -> (int)x: 100000000
If you really, really need to convert the angles to int, I suggest you this approach:
void LateUpdate()
{
// (...)
takeHiResShot = Input.GetKeyDown("k");
if (takeHiResShot)
{
Vector3 startAngles = rift.transform.eulerAngles;
for (int i = 1; i <= 20; ++i)
{
for (int j = 1; j <= 5; ++j)
{
//Setting transform.rotation is safer than setting transform.eulerAngles
rift.transform.rotation = Quaternion.Euler((int)startAngles.x + i, (int)startAngles.y + j, (int)startAngles.z);
Debug.Log(string.Format("i: {0}, j: {1}, eulerangles: {2}", i, j, rift.transform.eulerAngles));
// (...)
}
//It is safe here because you didn't manipulate the value,
//but Quaternion.Euler is still more advisable
rift.transform.eulerAngles = startAngles;
}
}
}
Upvotes: 2