Is it normal this dark image in Cesium? - cesiumjs

I think my Cesium globe is too dark. Here is two images: one from Cesium and other from OpenLayers, both from same location and same geoserver layer.
Already set viewer.scene.globe.enableLighting = true; as you can see in image below:
My setup:
viewer = new Cesium.Viewer('cesiumContainer',{
timeline: false,
animation: false,
baseLayerPicker: false,
geocoder : false,
infoBox : false,
selectionIndicator : true,
navigationHelpButton : false,
});
viewer.scene.globe.enableLighting = true;
var scene = viewer.scene;
var imageryLayers = scene.imageryLayers;
baseLayer = imageryLayers.get(0);
imageryLayers.remove( baseLayer );
var baseProvider = new Cesium.WebMapServiceImageryProvider({
url : myUrl,
layers : 'osm:OSMMapa',
parameters : {
transparent : true,
format : 'image/png',
tiled : true,
}
});
imageryLayers.addImageryProvider( baseProvider );
how can I set my view to be brighter like OpenLayers and show the image as it realy is?

A couple of things you can try here:
First, enableLighting can be false, if you don't care about time or don't want the "night side" of the globe to be dark. It's counter-intuitive that turning off lighting would make things brighter, but really this flag is about turning off the lighting calculations, replacing them with full brightness always.
But the more effective thing, at least in the short term, may be to turn off HDR:
viewer.scene.highDynamicRange = false;
"High Dynamic Range" applies to fancy 3D models and their reflections, and in current versions of Cesium it also involves a color processing technique called tone-mapping. But if you're not using any of that, then this is all irrelevant to you, and is actually hurting the contrast of the images.
The behavior of this may change in a future release to be a little smarter about when and how tone-mapping is applied. But for now, the workaround is to turn off HDR.

Related

Set transparent for specific element

I want set transparent for specific element, i follow this code:
var instanceTree = this.viewer.model.getInstanceTree();
var fragList = this.viewer.model.getFragmentList();
this.listElement.forEach(element => {
instanceTree.enumNodeFragments(element, (fragId) => {
console.log(element.material)
var material = fragList.getMaterial(fragId)
if (material) {
material.opacity = value;
material.transparent = true;
material.needsUpdate = true;
}
});
});
this.viewer.impl.invalidate(true, true, true);
but it overide for all elements have that material. How can i set for selected element?
Appreciate any comments.
UPDATE 1:
i found go around way is clone main material than register it with different name:
var newMaterial = material.clone();
const materials = this.viewer.impl.matman();
materials.addMaterial('mymaterial',newMaterial,true);
fragList.setMaterial(fragId,newMaterial);
newMaterial.opacity = value;
newMaterial.transparent = true;
newMaterial.needsUpdate = true;
but effect is not what i want, it has different color and when set transparent i can only see a couple object behind it
You can create your own, custom THREE.js material and assign it to the fragment using fragList.setMaterial(fragId, material).
For more information on using custom materials or shaders, see https://forge.autodesk.com/blog/custom-shader-materials-forge-viewer.
EDIT:
Regarding the visual anomalies (for example, when you only see some of the objects behind something semi-transparent), this is a known problem, unfortunately with no clear solution. When the Forge Model Derivative service creates an SVF file to be viewed in Forge Viewer, the individual scene elements are stored in a data structure optimized for fast traversal, depending on whether they are semi-transparent or fully opaque. This data structure is fixed, and so unfortunately, when you take an object that was originally fully opaque, and you make it semi-transparent, it will most likely be rendered in a wrong order...

Cesium - Applying color filter to ImageryLayer

Has anyone attempted to do this? As far as I can tell from the documentation, there doesn't seem to be a built in function for achieving this. Does anyone know if this is possible? Is it, possibly, a feature that the authors might intend to add to the platform?
The ImageryLayer documentation shows how to control brightness, contrast, hue, saturation, and gamma correction.
To get a globe with a solid color, you can remove the imagery layers like so:
var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false
});
var globe = viewer.scene.globe;
globe.imageryLayers.removeAll();
globe.baseColor = Cesium.Color.LIGHTSLATEGRAY;
A "minimalist map" (as you mention in the comments) is something you would probably need to get from a custom imagery provider. You may want to check out Stamen Maps for some examples of this. In particular, note their "Toner" map comes in a number of sub-varieties, any of which can be selected in Cesium.
For example, to try the "Toner Background" version, you would use:
var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false,
imageryProvider: Cesium.createOpenStreetMapImageryProvider({
url : 'https://stamen-tiles.a.ssl.fastly.net/toner-background/',
credit : 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
})
});
EDIT: #EmmanuelBuckski (OP) took this idea and ran with it, mixing the above two techniques together to produce a result that looks really nice! Check it out:
var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false
});
var globe = viewer.scene.globe;
globe.imageryLayers.removeAll();
globe.baseColor = Cesium.Color.fromCssColorString('#f3f3f3');
var tonerLayer = globe.imageryLayers.addImageryProvider(
Cesium.createOpenStreetMapImageryProvider({
url : 'https://stamen-tiles.a.ssl.fastly.net/toner-background/',
credit : 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
})
);
tonerLayer.alpha = 0.1;

How to set width to SimplePolylineGeometry primitive in CesiumJS

I have this code, which adds polyline primitive to scene.
function createPolyline(startPosition, endPosition) {
Cesium.SimplePolylineGeometry({
positions : [startPosition, endPosition]
});
var geometry = Cesium.SimplePolylineGeometry.createGeometry(polyline);
return scene.primitives.add(new Cesium.Primitive({
geometryInstances : new Cesium.GeometryInstance({
geometry : geometry,
attributes : {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.SPRINGGREEN)
}
}),
appearance : new Cesium.PerInstanceColorAppearance()
}));
}
How do I set width of this polyline?
The recommended way to add a polyline is with the Entity API, like this
var greenLine = viewer.entities.add({
polyline : {
positions : [startPosition, endPosition],
width : 5,
material : Cesium.Color.SPRINGGREEN
}
});
But, if you want to skip the Entity layer and use the Primitive Graphics layer directly, you can do that too. Your sample code above has some issues. First, you're calling the Cesium.SimplePolylineGeometry constructor without the new keyword, and without saving the result, and this is not the correct use pattern for this kind of code. Second, the SimplePolylineGeometry class itself does not support line widths greater than what the WebGL implementation supports, which on Windows machines running ANGLE, is only 1 pixel wide. To get around this limitation, use the normal (non-simple) polylines, like this:
var polylines = scene.primitives.add(new Cesium.PolylineCollection());
var polyline = polylines.add({
positions : Cesium.PolylinePipeline.generateCartesianArc({
positions : [startPosition, endPosition]
}),
material : Cesium.Material.fromType('Color', {
color : Cesium.Color.SPRINGGREEN
}),
width: 5
});
SimplePolylineGeometry does not support line width. You need to use PolylineGeometry instead and pass the "width" options to the constructor. Also, you should be using PolylineColorAppearance as your appearance, not PerInstanceColorAppearance.

jCanvas imageSmoothingEnabled not working

So I am trying to build a game with pixel art in html using jCanvas. However, when I try to disable imageSmoothing in order to leave the pixels sharp, nothing happens.
$(function() {
$('canvas').drawImage({
source: 'http://i.imgur.com/Y2o59.png',
x:400, y:250,
width: 160, height: 160,
imageSmoothingEnabled: false,
});
});
Edit: Added random piece of pixel art to make it easier to test.
Figured it out.
First of all, its imageSmoothing: false, not imageSmoothingEnabled: false.
Second, you still need to enable smoothing on the context, like this:
var ctxbgd = document.getElementById('background').getContext("2d");
ctxbgd.imageSmoothingEnabled = false;
ctxbgd.webkitImageSmoothingEnabled = false;
ctxbgd.mozImageSmoothingEnabled = false;
There, no smoothing.

OpenLayers, how restricting WMS layer extent

I'm able to create an OpenLayers Map with maxExtent and restrictedExtent properties.
Also I have play with WMS layer and its maxExtent property, but the problem comes when use singleTile in the WMS layer.
What I want is to have a WMS layer that gets only one image from server but restricted to the bounds I want. Because this I used singleTile=true, ratio=1 and maxExtend=my_desired_extent.
But it always request the whole map view.
Any ideas how to achieve it.
Thanks in advance.
Next code shows a map with a base layer and a costline line layer I would like to use in singleTile mode and limiting the are they must request to WMS:
<script type="text/javascript" src="http://openlayers.org/api/2.11/OpenLayers.js"></script>
<div id="map" style="width: 700px; height: 500px;"></div>
<script type="text/javascript">
var map = new OpenLayers.Map("map");
var wms = new OpenLayers.Layer.WMS("OpenLayers WMS Basic", "http://labs.metacarta.com/wms/vmap0",
{
layers: 'basic'
});
map.addLayer(wms);
var restricted = new OpenLayers.Layer.WMS("Coast Line", "http://labs.metacarta.com/wms/vmap0",
{
layers: 'coastline_01,coastline_02'
},
{
opacity: 0.6,
singleTile: true,
ratio: 1,
isBaseLayer: false,
maxExtent: OpenLayers.Bounds.fromString("-10,-90,30,90")
});
map.addLayer(restricted);
map.setCenter(new OpenLayers.LonLat(0,40), 3);
</script>
I'm looking at OpenLayers source and seems what I want is not implemented so I need to create some WMS subclass or redefine some WMs layer methods.
I would appreciate any help.
Thanks.
If you are looking at restricting the whole map to the extent your talking about and not allowing users to pan outside of the extent you can try something like the following.
var extent = new OpenLayers.Bounds({-10,-90,30,90});
function init() {
var options = {
restrictedExtent: extent
};
map = new OpenLayers.Map('map', options);
var restricted = new OpenLayers.Layer.WMS("Coast Line", "http://labs.metacarta.com/wms/vmap0",
{
layers: 'coastline_01,coastline_02'
},
{
opacity: 0.6,
singleTile: true,
ratio: 1,
isBaseLayer: false
});
map.addLayer(restricted);
The difference here is that I have set the extent on the whole map not just the layer. Note that you will need to control the maximum zoom level as well. If you don't a user can still zoom out and data passed the extents will be shown though they will not be able to pan the view on the map.
If you want the map to pan outside of the extent specified but just not that layer then there are a number of approaches.
If you have access the the WMS server that the layer is served from you could add a setting there to restrict the extent of the layer server.
Check this link http://docs.geoserver.org/latest/en/user/webadmin/data/layers.html and read the "Bounding Boxes Section"
If you don't have access to the WMS server and you just want to restrict the area that is requested from the WMS server from the client side you could try using the OpenLayers.layer.WMS class with a different strategy. See below for an example:
var myfilter = new OpenLayers.Filter.Spatial({
type: OpenLayers.Filter.Spatial.BBOX,
value: OpenLayers.Bounds.({-10,-90,20,90})})
var filterStrategy = new OpenLayers.Strategy.Filter({filter: myFilter});
var restricted = new OpenLayers.Layer.WMS("Coast Line", "http://labs.metacarta.com/wms/vmap0",
{
layers: 'coastline_01,coastline_02'
},
{
opacity: 0.6,
singleTile: true,
ratio: 1,
isBaseLayer: false,
strategies: [filterStrategy]
});
map.addLayer(restricted);
Please note that I have not tested this code and it may take a little refining to get it to work.