Webplayer Fail or Brain Fail?

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:

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

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Text;

public class PlaceParticles : MonoBehaviour
{

public bool debugThisMess = true;
public ParticleSystem tree;

public Transform ObjectToPopulateWithParticles;

private StringBuilder _sb = new StringBuilder(256);

// perhaps this is getting called out of sequence?
void Start()
{

// should be 1000
int partNum = tree.particleCount;

// make a list, of the same length
ParticleSystem.Particle[] ParticleList = new ParticleSystem.Particle[partNum];
tree.GetParticles(ParticleList);

if (debugThisMess)
{
_sb.Append("placing " + partNum + " particles as trees");
DisplayError(ref _sb);
}

for (int i = 0; i < partNum; ++i)
{
//for sanity we check the positions created by our helper methods.
// "5" is the tree sprite height offset we want, ignore it.
//
// GenerateRandomLocationInArea and ShootRayReturnParticlePosition
// just find a place in a block and shoot a ray down,
// nothing fancy, just puts it on the floor.

Vector3 newPlace = ItemSpawner.ShootRayReturnParticlePosition(ItemSpawner.GenerateRandomLocationInArea(ObjectToPopulateWithParticles)) + (Vector3.up * 5); // magic number erk!
// we should have a valid position
// (since this is a "tested as working" method used for non-particle placement)

if (debugThisMess)
{
_sb.Append("placing particle " + i + " at " + newPlace);
DisplayError(ref _sb);
}

// actually assign the location to the particle in the list
ParticleList[i].position = newPlace;
}

//actually assign the particles, with new postions, back to the system
tree.SetParticles(ParticleList, partNum);

//tree.gravityModifier = 0; in case your trees sink...
}

///<summary>
/// Ugly helper to spit out stuff to screen and log
///</summary>
///<param name="sb"></param>
private void DisplayError(ref StringBuilder sb)
{
Debug.Log(_sb);
// toScreen code elided
_sb.Remove(0, _sb.Length);

}
}

looks like

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

This works perfectly in the editor.

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

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

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)

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

1 Like

I tried setting the execution delay for the script to be last…

didn’t help

1 Like

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 :frowning:
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

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 :frowning: )

workaround below

1 Like

so. I was right. it was some sort of undocumented (as far as I can find) delay in the particle creation.

using UnityEngine;
using System.Collections;

public class PlaceParticles : MonoBehaviour
{
public ParticleSystem tree;  // plural. like sheep.

public Transform ObjectToPopulateWithParticles;
// a flatish square mesh is a good idea since our helper will take a
// random point sample in the negative Y on a pre-defined square.
// You can write better helpers...

// we will just start a loop until we have our particles ready to reposition
void Start()
{
StartRepeatingCheckForParticleCount();
}

void CreateTreesFromParticles()
{
// should be 1000 in my case...
int partNum = tree.particleCount;

if (partNum == 0)
return;

// make a list, of the same length
ParticleSystem.Particle[] ParticleList = new ParticleSystem.Particle[partNum];
tree.GetParticles(ParticleList);

for (int i = 0; i < ParticleList.Length; ++i)
{
// "5" is the tree sprite height offset we want, ignore it. change it for your tree height
// GenerateRandomLocationInArea and ShootRayReturnParticlePosition
// just find a place in a block and shoot a ray down,
// nothing fancy, just puts it on the floor.

Vector3 newPlace = ItemSpawner.ShootRayReturnParticlePosition(ItemSpawner.GenerateRandomLocationInArea(ObjectToPopulateWithParticles)) + (Vector3.up * 5); // magic number erk!

// actually assign the location to the particle in the list
ParticleList[i].position = newPlace;
}

//actually assign the particles, with new positions, back to the system
tree.SetParticles(ParticleList, partNum);

CancelInvoke("CreateTreesFromParticles");
}
void StartRepeatingCheckForParticleCount()
{
InvokeRepeating("CreateTreesFromParticles", 0, 0.02F);
}
}

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”.

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:

1 Like

for completeness. The helper really does nothing much: Return a random place in a square. Shoot down a Ray.

// partial bits shown for clarity
// 256 is my "magic" block size
public static Vector3 GenerateRandomLocationInArea(Transform chosenparent)
{
return new Vector3(Random.Range(10, 246) + chosenparent.position.x, 35f,
Random.Range(10, 246) + chosenparent.position.z);
}

public static Vector3 ShootRayReturnParticlePosition(Vector3 location)
{
Vector3 targetPosition = Vector3.zero;
RaycastHit hit;

if (Physics.Raycast(location, -Vector3.up, out hit))  // ugh.
{ targetPosition = hit.point; }

return targetPosition;
}

And HERE PlaceParticles.cs Place Unity particles individually. · GitHub is a combined version for simplicity

and here is what I used exactly Combined grid tracking, can handle particle list, terrain trees, GO colliders. Places collider / NavMeshObstacles. Uses trigger value to Invoke · GitHub
to actually provide a collider system

and here are the meaningful particle settings

2060551--134346--upload_2015-4-10_0-25-17.png

1 Like

Tested this today. as of 5.3 seems like this no longer places the particles… hey ho. will investigate at some point

1 Like