Can't produce mesh using CreateGroundFromHeightMap function. Getting ground object in alert popup reports it has 0 subdivisions and 0 vertices - babylonjs

So, I've just picked up BabylonJS and having rendered some basic shapes, I read about the CreateGroundFromHeightMap function and thought I'd give it a go. However, I've been unsuccessful in getting a mesh render in my scene and I can't see anything that obviously explains why what's going wrong. My scene code is as follows:
const createScene = () => {
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 3, new BABYLON.Vector3(0, 0, 0));
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0));
var groundMaterial = new BABYLON.StandardMaterial("ground", scene);
var ground = BABYLON.Mesh.CreateGroundFromHeightMap("ground", "heightmap.jpg", 200, 200, 20, 0, 10, scene);
ground.material = groundMaterial;
return scene;
};
As far as I can tell, I've followed the examples I've seen online and I've confirmed that my image path is valid, but all I get is an empty scene and there are no browser console errors, so I can't really tell what's going wrong. As I said in my question title, I tried passing my ground variable to an alert popup and got this result, clearly indicating that it's not generating the mesh successfully: "Name: ground, isInstance: YES, # of submeshes: 0, n vertices: 0, parent: NONE". Any ideas what might be going wrong? Thanks!

Okay, so in case this is useful to anyone else, I got it working. First, I used BABYLON.MeshBuilder instead of of BABYLON.Mesh. Also, I was unaware that I couldn't just point the function to a local image file path, which I've discovered appears to be the case upon trying a heightmap image from a web URL and finding that it worked. Following this discovery, I tried setting up my scene with all my files on an Apache web server instead and it now works!

Related

MapsUI always shows "own location" marker at LatLng 0,0

I have the issue with MapsUI 2.0.3 that the marker of my own location is always at 0,0 west of Africa. Clicking the focus on own location button obviously also moves me there.
I did add coarse and fine location permissions to manifest and do get permission to access locations, but "you are here" is always 0,0.
I then downloaded the MapsUI repository, and tried the samples, which show the same behavior, mostly. When the map loads, it shows position at 0,0. If I drag the map slightly, the marker slowly moves to my correct position. If I (in the samples) reload the same sample or another one, the marker remains stuck at 0,0, even when I drag the map. In summary, I can "fix" the 0,0 marker by interacting with the map but only once.
My device does have gps location enabled, and other location using apps work fine. This including other home made Xamarin forms apps, so this is an issue for MapsUI only.
It failing for both samples and own code makes this a bit confusing.
Does this ring a bell for anyone? Seems a bit strange to say the least.
Note that this also fails on the xamagin/android device emulator with a set position. Just mentioning this as a "fun" extra detail, map longpress event will never fire on my device, but does work on the emulator. I saw someone else, a long time back, complaining about that same issue, and a developer commenting on it being fixed in 2.0, while I see it in 2.3. All in all MapsUI seems like an extremely rich system that I would love to use, but which has weird little bugs and poor support.
The xaml for adding the mapview
<StackLayout>
<mapsui:MapView x:Name="mapView" IsMyLocationButtonVisible="True" />
</StackLayout>
And the c# setup
void start()
{
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
if(status==PermissionStatus.Denied) return;
var map = new Mapsui.Map
{
Transformation = new MinimalTransformation(),CRS = "EPSG:3857"};
var tileSource = new HttpTileSource(new GlobalSphericalMercator(),
"https://tile.thunderforest.com/landscape/{z}/{x}/{y}.png?
apikey=xxxxxxxxx",new[] { "a", "b", "c" }, name: "OpenStreetMap");
var tileLayer = new TileLayer(tileSource) { Name = "Carto Light" };
map.Layers.Add(tileLayer);
mapView.Map = map;
}
Although not knowing why MyLocationButton not works, but there is a workaround to make the current location to show in MapsUI.
There is a UpdateMyLocation method inside MyLocationLayer,then we can use this method to show the current location programmatically.
In addition, you could use Geolocation to get the current location.
Code as follows:
protected override async void OnAppearing()
{
base.OnAppearing();
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
mapView.MyLocationLayer.UpdateMyLocation(new Position(location.Latitude, location.Longitude), true);
}
The effect:

Best way to force textures upload to GPU at scene load time?

I was wondering the best way to force textures upload to GPU at scene load? I’ve read GPU Texture Preloading section within Best Practices, but I’m not quite sure if that’s something that needs to be done texture by texture and element by element.
There's an old thread talking about it here, but it doesn't seem to have a happy ending so far :(
Would it make sense to make a traverse from the sceneEl, before the scene has loaded, obtain every texture and call document.querySelector('a-scene').renderer.setTexture2D(eachTexture, 0)?
Thanks
setTexture2D no longer exists as of r103. You can use something like this instead
const forceTextureInitialization = function() {
const material = new THREE.MeshBasicMaterial();
const geometry = new THREE.PlaneBufferGeometry();
const scene = new THREE.Scene();
scene.add(new THREE.Mesh(geometry, material));
const camera = new THREE.Camera();
return function forceTextureInitialization(texture) {
material.map = texture;
renderer.render(scene, camera);
};
}();
Yes, that makes sense to do.
Just call sceneEl.renderer.setTexture2D(texture, i), passing in the three.js texture. And I think it's better to cycle i to a different value each call between 1 and 8.

Mapsui adding map pins in Xamarin Forms

I need to add a bunch of pins on a MapsUI map control that uses OpenStreetMap tiles.
The problem is I cant find anything mentioning pins in their documentation so my question is:
Are there any pins available but have different names or i have to draw pins myself (using Geometry and Points as in some examples i found) and if so how do i keep them the same size when zooming the map ?
Maybe someone can point out where should i look in their documentation in case I'm blind and missed it.
Thanks!
Your Mapsui Map View Mapsui.UI.Forms.MapView has property Pins. You can add pins there.
You can access MapView View from code-behind *xaml.cs of your MapView.
For that, first, name your Map View in XAML Page:
<ContentPage
xmlns:mapsui="clr-namespace:Mapsui.UI.Forms;assembly=Mapsui.UI.Forms"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YourProject.Pages.YourMap">
<ContentPage.Content>
<mapsui:MapView
x:Name="selectMapControl"/>
</ContentPage.Content>
</ContentPage>
Then access it from C# code-behind of that Page:
using Mapsui.UI.Forms;
protected override async void OnAppearing()
{
selectMapControl.Pins.Add(new Pin(new MapView())
{
Position = new Position(0, 0),
Type = PinType.Pin,
Label = "Zero point",
Address = "Zero point",
});
}
Hope this simplest example will help.
The idea is that you use your own bitmaps to draw as 'pins'.
Mapsui has features. A feature has a geometry which can be a point, linestring and polygon (and some others). A feature is drawn with some kind of style. What you need to do is create features with point geometry and use a symbolstyle with a bitmap as symbol. You need to register your bitmap and use the bitmapId in the symbol. See the sample here:
https://github.com/Mapsui/Mapsui/blob/master/Samples/Mapsui.Samples.Common/Maps/PointsSample.cs
You can use Xamarin.Forms.GoogleMaps as they give you the feature to add multiple pins of your choice.
Here is the sample code :
var position = new Position(Latitude, Longitude);
var pin = new Pin
{
Type = PinType.Place,
Position = position,
Icon = BitmapDescriptorFactory.FromBundle("pin.png"),
Label = "custom pin",
Address = "custom detail info",
};
MyMap.Pins.Add(pin);
The following works on version 3.02. I've not checked it on any other version of MapSui.
First make sure your pin Bitmap is an embedded resource. You can then get the Bitmap ID like this:
var assembly = typeof(YourClass).GetTypeInfo().Assembly;
var image = assembly.GetManifestResourceStream("YourSolution.YourProject.AFolder.image.png");
If var image returns null, then the image was not found and it's likely not an embedded resource or you got the address/name wrong.
var ID = BitmapRegistry.Instance.Register(image);
The BitmapRegistry method also registers the BitMap for MapSui to use later. I think if it's your first image registered it will be 0.
Then you can create a memory layer as follows:
MemoryLayer PointLayer = new MemoryLayer
{
Name = "Points",
IsMapInfoLayer=true,
DataSource = new MemoryProvider(GetListOfPoints()),
Style = new SymbolStyle { BitmapId = ID, SymbolScale = 0.50, SymbolOffset = new Offset(0, bitmapHeight * 0.5) };
};
The DataSource can be generated as follows (I'm just adding one feature, but you can add as many as you like):
private IEnumerable<IFeature> GetListOfPoints()
{
List<IFeature> list = new List<IFeature>();
var feature = new Feature();
feature.Geometry = new Point(-226787, 7155483);
feature["name"] = "MyPoint";
list.Add(feature);
IEnumerable<IFeature> points = list as IEnumerable<IFeature>;
return points;
}
Then add the new MemoryLayer to your Map as follows:
MapControl.Map?.Layers.Add(PointLayer);

How can I disable, or partially disable, picking of a javafx subscene?

I'm running into an issue on a graph-browsing program that I am building. I have two JavaFX subscenes, one of which browses a very large graph (that is, the mathetmatical construct of a graph, not something simple like a line graph or pie graph; potentially several gigabytes) in a manner similar to a flight simulator. The other one contains a set of controls, which are always at fixed points on the screen.
The only problem that I am running into is, when I attempt to get a pick result from the main Scene, it always stops at the first SubScene (the heads-up display). I've checked PickResult.getIntersectedNode(), it is definitely the SubScene intercepting the pick.
I have attempted this (on both SubScenes, to be sure):
layer.setPickOnBounds(false);
But it has had no effect.
I suspect that some transparent portion of the layered SubScene is still demarcating the space as occupied. I am not certain of this.
How can I set a SubScene to be unpickable, while leaving its contents alone?
As an addendum for discussion, here is a sample of the method I created (in an experiment) to build a heads-up-display. This is before I switched it to simply return a pane. (The parameter "fillPaint" is consistently set to Color.TRANSPARENT).
/**
* Creates a subscene of set parameters
*
* #param scene
* primary scene (into which subscene is injected)
*/
private SubScene makeHeadsUpSubScene(Scene scene, Camera camera, Paint fillPaint,
Node node) {
Group root = new Group();
PointLight light = new PointLight(Color.WHITE);
light.setTranslateX(50);
light.setTranslateY(-300);
light.setTranslateZ(-400);
PointLight light2 = new PointLight(Color.color(0.6, 0.3, 0.4));
light2.setTranslateX(400);
light2.setTranslateY(0);
light2.setTranslateZ(-400);
String title = "Title Stand-in";
boolean msaa = true;
AmbientLight ambientLight = new AmbientLight(Color.color(0.2, 0.2, 0.2));
node.setRotationAxis(new Point3D(2, 1, 0).normalize());
node.setTranslateX(180);
node.setTranslateY(180);
root.getChildren().addAll(new Label(title), ambientLight, light, light2, node);
SubScene subScene = new SubScene(root, 640, 480, true, msaa ? SceneAntialiasing.BALANCED : SceneAntialiasing.DISABLED);
subScene.widthProperty().bind(scene.widthProperty());
subScene.heightProperty().bind(scene.heightProperty());
subScene.setFill(fillPaint);
subScene.setCamera(camera);
return subScene;
}
So, it seems that SubScene takes on the shape of its contents, which generally default to a complete and filled rectangle.
However, If SubScene is used for the field navigation, providing it with its own camera; while a simple Pane is used for the Heads-Up; it is possible to pick from both. Pick-on-bounds must of course be set to false for all appropriate panels.
Make sure that to call setFill(null) on subScene
Setting with a color, even a transparent color, will cause the subScene to be 'picked' if it lays between the camera and the scene.

How to track an object during animation?

I am making a tower defense game. The user places a tower and there is a thread that pools the tower to see if there are any monsters near by. Right now I am working on animating the path using a simple rectangle to test things. The Path is easy to work with and is go to choice, but unlike the Timeline I can not gather the coordinates relative to where the shape is.
I have had success detecting the rectangle position using the Timeline class with Keyframes but I can not create the paths using multiple keyframes and get the visual effects I want.
The Path class gives me the visual effects I want, but seems to have no way of tracking the shape.
Is there a way I can either track the location of the shape along the path, or is there a way to make the same style path using the Timeline class. Also is there an easier API I am missing here?
rectBasicTimeline = new Rectangle (0, 0, 40, 40);
monsterLayer.getChildren().add(rectBasicTimeline);
//gets coordinates of rectangle and see if tower is in range
TowerAttackerService testService = new TowerAttackerService();
testService.start();
Path path = new Path();
boolean isFirst = true;
//gathers path coordinates from search algorithm
for(Coordinate coords : pathCoords){
if(isFirst){
path.getElements().add(new MoveTo(coords.getExactX(),coords.getExactY()));
isFirst = false;
}
else{
path.getElements().add(new LineTo(coords.getExactX(),coords.getExactY()));
}
}
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(10000));
pathTransition.setPath(path);
pathTransition.setNode(rectBasicTimeline);
pathTransition.play();
To get the rectangle location I have been calling the getX() and getY() method which returns 0.0

Resources