Open henning101 opened 4 years ago
I made some minimal progress. When I don't parent the instantiated prefabs to the ve.GameObject.transform
the instances stay at their locations. Unfortunately they are not cleared anymore. I checked the name of the vector entities and for some reason there are vector entities with the same name at multiple locations?
This is the code I use as mesh modifier (primitive type: Point):
public class RoadJointPointModifier : MeshModifier
{
public override ModifierType Type
{
get { return ModifierType.Preprocess; }
}
public override void SetProperties(ModifierProperties properties)
{
}
public override void Run(VectorFeatureUnity feature, MeshData md, float scale)
{
AddVertices(feature, md);
}
public override void Run(VectorFeatureUnity feature, MeshData md, UnityTile tile = null)
{
AddVertices(feature, md);
}
public void AddVertices(VectorFeatureUnity feature, MeshData md)
{
foreach (List<Vector3> segment in feature.Points)
{
foreach (Vector3 point in segment)
{
md.Vertices.Add(point);
}
}
}
}
and this is the code I use for the game object modifier:
public class RoadJointPrefabModifier : GameObjectModifier
{
private Dictionary<string, GameObject> _objects;
[SerializeField]
private SpawnPrefabOptions _options;
//private List<GameObject> _prefabList = new List<GameObject>();
public override void Initialize()
{
if (_objects == null)
{
_objects = new Dictionary<string, GameObject>();
}
}
public override void SetProperties(ModifierProperties properties)
{
_options = (SpawnPrefabOptions)properties;
_options.PropertyHasChanged += UpdateModifier;
}
public override void Run(VectorEntity ve, UnityTile tile)
{
if (_options.prefab == null)
{
return;
}
for (int i = 0; i < ve.Mesh.vertices.Length; i++)
{
GameObject instance = null;
string id = ve.GameObject.name + "_" + i;
if (_objects.ContainsKey(id))
{
// instance = _objects[id];
}
else
{
instance = Instantiate(_options.prefab);
//_prefabList.Add(instance);
_objects.Add(id, instance);
instance.transform.position = new Vector3(
ve.Mesh.vertices[i].x + ve.GameObject.transform.position.x,
ve.Mesh.vertices[i].y + ve.GameObject.transform.position.y,
ve.Mesh.vertices[i].z + ve.GameObject.transform.position.z
);
}
}
Debug.Log(ve.GameObject + " position: " + ve.GameObject.transform.position);
}
public override void Clear()
{
base.Clear();
foreach (var gameObject in _objects.Values)
{
if (Application.isEditor && !Application.isPlaying)
{
DestroyImmediate(gameObject);
} else
{
Destroy(gameObject);
}
}
_objects.Clear();
}
}
I still can't figure out how exactly the buffering works. Is there maybe an overview of the complete pipeline?
Another bit of progress. So the problem occurs if I try to create multiple objects at mesh vertex positions inside a GameObjectModifier
instead of spawning a single object and parenting it to ve.GameObject
. I guess it has to do with how buffered tiles are activated and deactivated? My solution for now is a slight modification of the original Mapbox prefab generator. Instead of calculating the centroid by averaging over all vertex positions I simple select a single vertex position randomly. This way I can make sure I have a single prefab instance somewhere along the street for each vector entity. Also "Combine Meshes" must be unchecked.
If anyone could help me make this work for object spawning per mesh vertex I'm still highly interested in a solution!
using UnityEngine;
using Mapbox.Unity.MeshGeneration.Data;
using Mapbox.Unity.MeshGeneration.Components;
using Mapbox.Unity.MeshGeneration.Interfaces;
using System.Collections.Generic;
using Mapbox.Unity.Map;
using System;
using Mapbox.Unity.MeshGeneration.Modifiers;
public class RoadJointPrefabModifier : GameObjectModifier
{
private Dictionary<GameObject, GameObject> _objects;
[SerializeField]
private SpawnPrefabOptions _options;
private List<GameObject> _prefabList = new List<GameObject>();
public override void Initialize()
{
if (_objects == null)
{
_objects = new Dictionary<GameObject, GameObject>();
}
}
public override void SetProperties(ModifierProperties properties)
{
_options = (SpawnPrefabOptions)properties;
_options.PropertyHasChanged += UpdateModifier;
}
public override void Run(VectorEntity ve, UnityTile tile)
{
if (_options.prefab == null)
{
return;
}
GameObject go = null;
if (_objects.ContainsKey(ve.GameObject))
{
go = _objects[ve.GameObject];
} else
{
go = Instantiate(_options.prefab);
_prefabList.Add(go);
_objects.Add(ve.GameObject, go);
go.transform.SetParent(ve.GameObject.transform, false);
}
PositionScaleRectTransform(ve, tile, go);
if (_options.AllPrefabsInstatiated != null)
{
_options.AllPrefabsInstatiated(_prefabList);
}
}
public void PositionScaleRectTransform(VectorEntity ve, UnityTile tile, GameObject go)
{
RectTransform goRectTransform;
IFeaturePropertySettable settable = null;
var centroidVector = new Vector3();
/*
foreach (var point in ve.Feature.Points[0])
{
centroidVector += point;
}
centroidVector = centroidVector / ve.Feature.Points[0].Count;
*/
centroidVector = ve.Feature.Points[0][UnityEngine.Random.Range(0, ve.Feature.Points[0].Count)];
go.name = ve.Feature.Data.Id.ToString();
goRectTransform = go.GetComponent<RectTransform>();
if (goRectTransform == null)
{
go.transform.localPosition = centroidVector;
if (_options.scaleDownWithWorld)
{
go.transform.localScale = _options.prefab.transform.localScale * (tile.TileScale);
}
} else
{
goRectTransform.anchoredPosition3D = centroidVector;
if (_options.scaleDownWithWorld)
{
goRectTransform.localScale = _options.prefab.transform.localScale * (tile.TileScale);
}
}
settable = go.GetComponent<IFeaturePropertySettable>();
if (settable != null)
{
settable.Set(ve.Feature.Properties);
}
}
public override void Clear()
{
base.Clear();
foreach (var gameObject in _objects.Values)
{
gameObject.Destroy();
}
foreach (var gameObject in _prefabList)
{
gameObject.Destroy();
}
}
}
👆Here is a video of the effect when I use the following code:
// ...
if (_objects.ContainsKey(ve.GameObject))
{
go = _objects[ve.GameObject];
} else
{
go = Instantiate(_options.prefab);
_prefabList.Add(go);
_objects.Add(ve.GameObject, go);
go.transform.SetParent(ve.GameObject.transform, false);
foreach (var segment in ve.Feature.Points)
{
foreach (var point in segment)
{
GameObject instance = Instantiate(_options.prefab);
instance.transform.SetParent(go.transform, true);
instance.transform.position = new Vector3(
go.transform.position.x + point.x,
go.transform.position.y + point.y,
go.transform.position.z + point.z
);
}
}
}
// ...
Hey @henning101, Object positioning and hierarchy can be really difficult, I have been through that a lot of times. I don't have a quick solution on top of my head for this case but
ve.Mesh.vertices[i]
is very very costly (to call multiple times). You might not even need gameobject modifier in this case. If I remember correct, you can create your gameobjects in mesh modifier and child them to feature.Tile
. Feature Position
option under Behaviour Modifiers
part. I think if you set it to tile center
and then child your objects to tile as I described above, it might work.public override void OnPoolItem(VectorEntity vectorEntity)
if you need (i.e. want to pool your custom objects yourself as well). That method is only in gameobject modifier but I think it shouldn't be too hard to add it to mesh modifiers as well.
Hi everyone! I am trying to instantiate prefabs at road joints (not at road centers or first vertex - which is possible with the prefab modifier). I copied the prefab modifier code and added the following:
this works fine after a fresh map reload (after clearing the Mapbox file cache in the editor) but as soon as a I move the center transform (map set to "range around transform") the vertex positions seem random. It looks like some of them are not cleared from the buffer and others are randomly generated.
I don't quite understand why this happens because I thought the modifier is called for every road segment each of which has a defined number of points.
I'd be super glad if someone can point me in the right direction!