Search Unity

Webplayer Fail or Brain Fail?

Discussion in 'Editor & General Support' started by twobob, Apr 9, 2015.

  1. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Hi, TL;DR: When I place Particles Individually it works in the editor but not in a build:

    I had a very simple idea for trees. cheap simple billboard trees like down the side of the old racing games.

    In order to make them as cheap as possible I went for particles.

    which I setup like this:

    upload_2015-4-9_2-24-54.png

    And I attach this rudimentary, but nicely commented script to it.
    Which - if you can't be bothered to read it, simply:
    1) Creates a bunch of random positions on a mesh surface.
    2) Then assigns those positions to a particle list and then
    3) Assigns that list of particles to the system.

    here is that code
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.UI;
    5. using System.Text;
    6.  
    7. public class PlaceParticles : MonoBehaviour
    8. {
    9.  
    10. public bool debugThisMess = true;
    11. public ParticleSystem tree;
    12.  
    13. public Transform ObjectToPopulateWithParticles;
    14.  
    15. private StringBuilder _sb = new StringBuilder(256);
    16.  
    17. // perhaps this is getting called out of sequence?
    18. void Start()
    19. {
    20.  
    21. // should be 1000
    22. int partNum = tree.particleCount;
    23.  
    24. // make a list, of the same length
    25. ParticleSystem.Particle[] ParticleList = new ParticleSystem.Particle[partNum];
    26. tree.GetParticles(ParticleList);
    27.  
    28. if (debugThisMess)
    29. {
    30. _sb.Append("placing " + partNum + " particles as trees");
    31. DisplayError(ref _sb);
    32. }
    33.  
    34. for (int i = 0; i < partNum; ++i)
    35. {
    36. //for sanity we check the positions created by our helper methods.
    37. // "5" is the tree sprite height offset we want, ignore it.
    38. //
    39. // GenerateRandomLocationInArea and ShootRayReturnParticlePosition
    40. // just find a place in a block and shoot a ray down,
    41. // nothing fancy, just puts it on the floor.
    42.  
    43. Vector3 newPlace = ItemSpawner.ShootRayReturnParticlePosition(ItemSpawner.GenerateRandomLocationInArea(ObjectToPopulateWithParticles)) + (Vector3.up * 5); // magic number erk!
    44. // we should have a valid position
    45. // (since this is a "tested as working" method used for non-particle placement)
    46.  
    47. if (debugThisMess)
    48. {
    49. _sb.Append("placing particle " + i + " at " + newPlace);
    50. DisplayError(ref _sb);
    51. }
    52.  
    53. // actually assign the location to the particle in the list
    54. ParticleList[i].position = newPlace;
    55. }
    56.  
    57. //actually assign the particles, with new postions, back to the system
    58. tree.SetParticles(ParticleList, partNum);
    59.  
    60. //tree.gravityModifier = 0; in case your trees sink...
    61. }
    62.  
    63. ///<summary>
    64. /// Ugly helper to spit out stuff to screen and log
    65. ///</summary>
    66. ///<param name="sb"></param>
    67. private void DisplayError(ref StringBuilder sb)
    68. {
    69. Debug.Log(_sb);
    70. // toScreen code elided
    71. _sb.Remove(0, _sb.Length);
    72.  
    73. }
    74. }
    75.  
    looks like

    upload_2015-4-9_2-57-40.png

    This works perfectly in the editor.

    upload_2015-4-9_3-0-21.png

    Giving me thousands of trees for a couple of draw calls...

    upload_2015-4-9_3-1-3.png

    but if I try to do this in the webplayer I get a 0 result for my test.
    and all the particles stay in the default position (since I don't actually set them in that case)


    upload_2015-4-9_3-4-19.png

    any clues on my mistake?
    I don't think it is a code mistake. I am not understanding the Particle System life-cycle probably..


    Many thanks.

    Okay so it's a delay thing. Workaround in the end posts
     
    Last edited: Apr 9, 2015
    Alverik likes this.
  2. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    I tried setting the execution delay for the script to be last..

    didn't help
     
    Alverik likes this.
  3. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Do I need to wait one frame for the particle system to populate? or something?
    I'll give that a try. I thought that was what Pre-warming was. Plus I told it to jam 1000 right at the start...

    Hardcoding the particles to 1000 and jamming them into the system didn't work :(
    And it's not just the webplayer, it does this on anything /outside/ the editor, where it works fine..

    I also tried with and without prewarming to no avail

    upload_2015-4-9_4-20-38.png

    and I tried putting "Infinity" into the value boxes but it looks like that has been noob-nerfed to 100000 (which could be a pain :( )

    workaround below
     
    Last edited: Apr 9, 2015
    Alverik likes this.
  4. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    so. I was right. it was some sort of undocumented (as far as I can find) delay in the particle creation.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlaceParticles : MonoBehaviour
    5. {
    6. public ParticleSystem tree;  // plural. like sheep.
    7.  
    8. public Transform ObjectToPopulateWithParticles;
    9. // a flatish square mesh is a good idea since our helper will take a
    10. // random point sample in the negative Y on a pre-defined square.
    11. // You can write better helpers...
    12.  
    13. // we will just start a loop until we have our particles ready to reposition
    14. void Start()
    15. {
    16. StartRepeatingCheckForParticleCount();
    17. }
    18.  
    19. void CreateTreesFromParticles()
    20. {
    21. // should be 1000 in my case...
    22. int partNum = tree.particleCount;
    23.  
    24. if (partNum == 0)
    25. return;
    26.  
    27. // make a list, of the same length
    28. ParticleSystem.Particle[] ParticleList = new ParticleSystem.Particle[partNum];
    29. tree.GetParticles(ParticleList);
    30.  
    31. for (int i = 0; i < ParticleList.Length; ++i)
    32. {
    33. // "5" is the tree sprite height offset we want, ignore it. change it for your tree height
    34. // GenerateRandomLocationInArea and ShootRayReturnParticlePosition
    35. // just find a place in a block and shoot a ray down,
    36. // nothing fancy, just puts it on the floor.
    37.  
    38. Vector3 newPlace = ItemSpawner.ShootRayReturnParticlePosition(ItemSpawner.GenerateRandomLocationInArea(ObjectToPopulateWithParticles)) + (Vector3.up * 5); // magic number erk!
    39.  
    40. // actually assign the location to the particle in the list
    41. ParticleList[i].position = newPlace;
    42. }
    43.  
    44. //actually assign the particles, with new positions, back to the system
    45. tree.SetParticles(ParticleList, partNum);
    46.  
    47. CancelInvoke("CreateTreesFromParticles");
    48. }
    49. void StartRepeatingCheckForParticleCount()
    50. {
    51. InvokeRepeating("CreateTreesFromParticles", 0, 0.02F);
    52. }
    53. }
    54.  
    EDIT: I removed all the old debug code


    PROS: fixes the issue. well okay - works around it. which I can live with. Is incredibly cheap.
    Does not require additional batching.
    Is fire and forget (well maybe not, not sure what will happen after 100000 counts...)

    CONS: the shadows are never going to be perfect without more work.
    needs a fast dynamic collider system adding and near frustum intersection checking for the camera to seem like "real trees".

    upload_2015-4-9_4-44-1.png

    upload_2015-4-9_4-44-28.png

    an enterprising person could put a fast spacial grid of colliders in the same places and get some extremely cheap trees this way. see below I provide a worked example of this


    I need to figure out a way to fix the shadows being offset but it seems doable; now we have an "only shadows" option more-so than ever

    Enjoy.

    This does have the unfortunate side-effect of shooting rays onto existent buildings etc...
    So you might want to add a few checks to the ray casting

    EDIT: I simply added a similar conditional wait to my main item spawner and check for a GameManager.TreeParticlesCreated flag that I set upon completion.

    this gives us nicely ordered objects:

    upload_2015-4-9_5-49-43.png
     
    Last edited: Apr 10, 2015
    Alverik likes this.
  5. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    for completeness. The helper really does nothing much: Return a random place in a square. Shoot down a Ray.
    Code (csharp):
    1.  
    2. // partial bits shown for clarity
    3. // 256 is my "magic" block size
    4. public static Vector3 GenerateRandomLocationInArea(Transform chosenparent)
    5. {
    6. return new Vector3(Random.Range(10, 246) + chosenparent.position.x, 35f,
    7. Random.Range(10, 246) + chosenparent.position.z);
    8. }
    9.  
    10. public static Vector3 ShootRayReturnParticlePosition(Vector3 location)
    11. {
    12. Vector3 targetPosition = Vector3.zero;
    13. RaycastHit hit;
    14.  
    15. if (Physics.Raycast(location, -Vector3.up, out hit))  // ugh.
    16. { targetPosition = hit.point; }
    17.  
    18. return targetPosition;
    19. }
    20.  
    And HERE https://gist.github.com/twobob/0ab2a30ecb92c4627c0d is a combined version for simplicity

    and here is what I used exactly https://gist.github.com/twobob/f7b34a4b404a9cee44da
    to actually provide a collider system

    and here are the meaningful particle settings

    upload_2015-4-10_0-25-17.png
     
    Last edited: Apr 10, 2015
    Alverik likes this.
  6. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Tested this today. as of 5.3 seems like this no longer places the particles... hey ho. will investigate at some point
     
    Alverik likes this.