How to fix shaking geometry on models with large shared coordinates - autodesk-forge

I'm loading multiple Revit models in the Forge modelviewer. To align them properly I am using the following load options as mentioned here
var modelOptions = {
sharedPropertyDbPath: doc.getPropertyDbPath(),
globalOffset: { x: 0, y: 0, z: 0 },
applyRefPoint: true,
isAEC: true
};
This works fine on Revit files where the project base point doesn't have too large coordinates. However, if the project base point of a Revit file has large coordinates ( like x:6698000, y:297500) then this results in shaking behavior when rotating the model or even a messed up triangulated view.
This problem also seems to happen when you set the placementTransform to a large coordinate as can be seen in the sample here
How can I solve this shaking behavior on these kind of models?

Can you try adjusting the offset using globaloffset...
Here's an example:
Model aggregating in viewer - coordinate issue

Related

How can I use setDisplayEdges() for multi-model loading?

I would like to turn the BIM edges on for all models. I have set setDisplayEdges(true) during the initialization of the viewer as well as adding isAEC: true to the options in loadModel().
Unfortunately, this does not display the edges.
How do you recommend turning on the edges for multi-model loading?
I'm not sure which model format your road model is, but passing the createWireframe: true option should help turn on the model edges with my research.
viewer.loadDocumentNode(doc, bubble, {createWireframe: true, keepCurrentModels: true})

Forge Viewer poor rendering quality

I'm using the Forge Viewer to display some models converted from IFC (2x3) files.
For some of them, the quality is perfect, but for others the rendering is very poor like the picture bellow.
I've tried to export in SVF, SVF2 and same result.
I've tired different settings to load the model
let config = {
keepCurrentModels: true,
applyScaling: { to: "m" },
applyRefPoint: true,
globalOffset: { x: 0, y: 0, z: 0 }}; //make the view flicker on weird rendered model
None of those settings improved the view except globalOffset who makes the view flicker.
Have you any idea how to fix this ?
This kind of deformation of geometries is typically an indication that the model is very far from the origin. So far that the GPU rendering starts running into floating point precision issues.
Loading the model with globalOffset: new THREE.Vector3(0, 0, 0) should help in this case as it would basically force the viewer not to re-apply the original global offset (which is potentially very large) to all geometry vertices. I'm not sure why the view would flicker after using this option, though, that might be a separate issue.

Autodesk Forge Viewer: Change Texture in IFC Model

we run a webapplication using Autodesk Forge. In the webapplication we'd like to change surface apperances. Therefore we use the following Audodesk functions
...
event.fragIdsArray.forEach(frag => {
const model = this.viewer.model;
model.getFragmentList().setMaterial(frag, this.material)
var object = this.viewer.impl.getFragmentProxy(this.viewer.impl.model, frag)
object.updateAnimTransform()
}
The code works fine for Autodesk Revit imported model. Using imported IFC models does not work as expected. Both models were imported to the AD Forge viewer by ADs model derivate api.
To geht our expected results we tried to use MeshBasicMaterial and MeshPhongMaterial. Both with the same result: Revit model is fine, IFC model aint so.
In Order to lookup for some workaround we tried to copy the fragment meshes and creating overlays with the same mashes and changed materials. Code was like
...
var obj = this.viewer.impl.getRenderProxy(this.viewer.impl.model, frag)
var meshProxy = new THREE.Mesh(obj.geometry, this.material);
meshProxy.matrix.copy(obj.matrixWorld);
meshProxy.matrixWorldNeedsUpdate = true;
meshProxy.matrixAutoUpdate = false;
meshProxy.frustumCulled = false;
this.viewer.impl.addOverlay("parkett", meshProxy);
...
The result is shown in the image (right side is the expected result):
Somehow it looks like the image texture is not shown "detailed" enough...
Thanks in advance for any suggestion!
From the question I'm not entirely sure what the problem is. Are there no visible changes when applying a custom material to IFC models? Or is the custom material applied, but in a "wrong way"?
If the custom material is not applied at all, make sure that the model is not consolidated. You can ensure that using viewer.model.unconsolidate();.
If the custom material is applied but its texture doesn't look correct, it could be because the geoemtries in the IFC model do not include proper texture coordinates. In that case you would have to map the texture yourself, for example, using a custom shader: https://github.com/petrbroz/forge-basic-app/blob/custom-texture-mapping/public/CustomTextureExtension.js.

Forge Viewer - Cannot view multiple different models properly

I'm having trouble loading different models in the viewer. I suspect the problem comes from mixing up different units (meters and millimeters) in the models.
So I have 3 Models:
IFC 1, is using millimeters as unit.
When loading the SVF derrivative into the viewer, doing
console.log(model.getUnitScale(), model.getUnitString());
outputs:
0.001, mm
IFC 2, using millimeters as unit. Getting the same output as IFC 1
Obj. Model of a simple cube with center of cube at origin [0, 0, 0]. This does not seem to have any inherent unit.
When loading the SVF derrivative into the viewer, doing
console.log(model.getUnitScale(), model.getUnitString());
outputs:
1, null
In order to load the models with the right coordinates I use the following options:
IFC 1 and 2:
{
globalOffset: {x: 1000000, y: 100000, z: 7000},
sharedPropertyDbPath: doc.getPropertyDbPath(),
}
Obj:
let mat = new THREE.Matrix4();
mat.makeTranslation(1000000, 100000,7000);
{
placementTransform: mat,
sharedPropertyDbPath: doc.getPropertyDbPath(),
}
The rationale here is that the IFC models are located far away from the origin, while the Obj model is located at origin. Using globalOffset for the IFCs seems necessary to get them to align in the viewer, using placementTransform is necessary to put the Obj close to the IFC models.
I'm struggling with the following problems here:
Navigating the models is hard, when highlighting the Obj model, it seems like it is set to using y-up or something, making it hard to do orientation navigation for the other models.
When trying to change zoom, only the Obj seems to be affected. Could this be due to different scale settings?
EDIT 1:
Looks like making the Obj cube the same size as the other models fixes the zooming problem.
Also, if loading the IFC files first, the orientation navigation is right. It's only when loading the OBJ file first that we get the "y-up orientation" problem
Edit 2:
The orientation navigation problem can be fixed with viewer.navigation.setWorldUpVector(new THREE.Vector3(0,0,1), false);.
Is it possible to also control behavior like this globally instead always letting the different models set the behavior?
I think the last loaded model will always have precedence over any previously set world-up vector. So if you want to control the world-up globally, you'll need to use the viewer.navigation.setWorldUpVector method manually after all the models have been loaded.

google maps using three.js and webgl

I have thousands of points that need to be plotted on google maps and got a very responsive maps using the example from https://github.com/ubilabs/google-maps-api-threejs-layer .
Did anyone have a play at this and wondering if it is possible to have different colored markers and possible marker click events?
Appreciate any pointers or examples online.
Millions of clickable data points can be painted on a google map using webgl.
A data point is represented by an x,y pair for a location on the canvas, an int for size, an off screen color, and an on screen color. These values are stored in separate typed arrays.
Each data point has a unique rgb color to act as a key in a lookup table of data point ids.
Create a texture to store the off screen colors and render it to an off screen buffer. On event, load the off screen buffer and use glReadPixels to retrieve the rgb color of the pixel clicked and then find the id in the lookup table. Points on the on screen buffer, what the user sees, can share a common color.
canvas.addEventListener('click', function(ev) {
# insert code to get mouse x,y position on canvas
pixels = new Uint8Array(4);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
if (colorToId[pixels[0] + " " + pixels[1] + " " + pixels[2]]) {
# Pixel clicked is a data point on the map
}
});
Webgl code is lengthy, so only the click event is included.
Here is a live demo and a repo. (angular and coffeescript)
Here is a second example using plain js: webgl-picking-geo-polygons
Here is react-webgl-leaflet
The solution is based on Brendan Kenny's Google Maps + HTML5 + Spatial Data Visualization which explains some of the code in the excerpt above at the 30 min mark, and Displaying WebGL data on Google Maps.
The demo features less than ten data points, but you can just as easily paint over 16 million pickable data points using all combinations of rgb values.
I discovered OpenLayers this past week. Very, very impressive framework. I would strongly suggest taking a look at it. OpenLayers.org is an open source JavaScript web mapping library distinguished from other alternatives, like Leaflet or Google Maps APIs, because of its huge set of components.
I spent the entire weekend creating sample apps by integrating OpenLayers with API's such as MapBox, WebGL etc... After all was said and done, I was extremely impressed with OpenLayers - and I plan to make use of OpenLayers in an upcoming POC/Project.
Here is a link to my test harness. From there you can also download the code for all of the examples, too.
Updates for 2021!!
Google Maps JS now has a WebglOverlayView class and exposes the WebGL context.
const webglOverlayView = new google.maps.WebglOverlayView();
webglOverlayView.onAdd = () => {
// Do setup that does not require access to rendering context.
}
webglOverlayView.onContextRestored = gl => {
// Do setup that requires access to rendering context before onDraw call.
}
webglOverlayView.onDraw = (gl, coordinateTransformer) => {
// Render objects.
}
webglOverlayView.onContextLost = () => {
// Clean up pre-existing GL state.
}
webglOverlayView.onRemove = () => {
// Remove all intermediate objects.
}
webglOverlayView.setMap(map);
Additionally, #googlemaps/three extends this class for easier use with ThreeJS.
// instantiate a ThreeJS Scene
const scene = new Scene();
// Create a box mesh
const box = new Mesh(
new BoxBufferGeometry(10, 50, 10),
new MeshNormalMaterial(),
);
// set position at center of map
box.position.copy(latLngToVector3(mapOptions.center));
// set position vertically
box.position.setY(25);
// add box mesh to the scene
scene.add(box);
// instantiate the ThreeJS Overlay with the scene and map
new ThreeJSOverlayView({
scene,
map,
});
Here is a link to a jQuery/google map app. Not exactly what you are looking for; however you might find the example useful. Feel free to use - it can be downloaded from my site.
Link to app on my website
Click here to download the zip