VNenad
VNenad

Reputation: 67

Cesium primitives (triangles) shading

I use this code to draw triangles in Cesium:

var mypositions = Cesium.Cartesian3.fromDegreesArrayHeights(triangles);

// unroll 'mypositions' into a flat array here
var numPositions = mypositions.length;

var pos = new Float64Array(numPositions * 3);
var normals = new Float32Array(numPositions * 3);
for (var i = 0; i < numPositions; ++i) {
  pos[i * 3] = mypositions[i].x;
  pos[i * 3 + 1] = mypositions[i].y;
  pos[i * 3 + 2] = mypositions[i].z;
  normals[i * 3] = 0.0;
  normals[i * 3 + 1] = 0;
  normals[i * 3 + 2] = 1.0;
}

console.log(normals)
var geometry = new Cesium.Geometry({
vertexFormat : Cesium.VertexFormat.ALL,
  attributes: {
    position: new Cesium.GeometryAttribute({
      componentDatatype: Cesium.ComponentDatatype.DOUBLE, // not FLOAT
      componentsPerAttribute: 3,
      values: pos
    }),
    normal: new Cesium.GeometryAttribute({
      componentDatatype: Cesium.ComponentDatatype.FLOAT,
      componentsPerAttribute: 3,
      values: normals
    })

  },

  // Don't need the following line if no vertices are shared.
 // indices: new Uint32Array([0, 1, 2, 3, 4, 5]),
  primitiveType: Cesium.PrimitiveType.TRIANGLES,
  boundingSphere: Cesium.BoundingSphere.fromVertices(pos)
});

var myInstance = new Cesium.GeometryInstance({
  geometry: geometry,
  attributes: {
    color: new Cesium.ColorGeometryInstanceAttribute(0.0039215697906911,
          0.7333329916000366,
          0,
          1)
  },
  show: new Cesium.ShowGeometryInstanceAttribute(true)
});

var TIN = viewer.scene.primitives.add(new Cesium.Primitive({
  geometryInstances: [myInstance],
  asynchronous: false,
  appearance: new Cesium.PerInstanceColorAppearance({
    closed: true,
    translucent: false,
    flat: false
    //,
    //vertexShaderSource: "",
    //fragmentShaderSource: ""

  })
  }));

This is what I get: enter image description here

I would like to enable shading, so the result should be similar as on figure below: enter image description here

I tried to write Vertex and Fragment GLSL shader but without success. I am not familiar with GLSL and I was getting a compiling error. Is there any another way to create this kind of shading?

Thanks!

Upvotes: 2

Views: 1147

Answers (1)

Robert Rouhani
Robert Rouhani

Reputation: 14678

Regardless of the fact that you haven't posted your GLSL shaders or gotten that to work, your problem (once you eventually figure out the GLSL stuff) is that you're setting all your normals to point in the +Z direction instead of actually being normal to each triangle, like the second screenshot of yours shows.

var normals = new Float32Array(numPositions * 3);
for (var i = 0; i < numPositions; ++i) {
  pos[i * 3] = mypositions[i].x;
  pos[i * 3 + 1] = mypositions[i].y;
  pos[i * 3 + 2] = mypositions[i].z;
  normals[i * 3] = 0.0;
  normals[i * 3 + 1] = 0;
  normals[i * 3 + 2] = 1.0;
}

What you need to do instead is set the positions and then for the normals, operate on sets of 3 vertices (a triangle) instead of individual vertices. This way you can actually calculate a surface normal. This is one of many explanations of how to do that:

https://math.stackexchange.com/questions/305642/how-to-find-surface-normal-of-a-triangle

I'm not familiar with Cesium, but I'd imagine there'd be some "default" shader that did basic lighting. If not, then the basis for simple lighting like this is called Lambertian reflectance. Your vertex shader would output a color that is calculated as dot(N, L) where N is the normal of your vertex and L is the vector from that vertex to your light source (or just the negative of the direction of your light if it's a directional/environment/sun/etc light). The fragment shader would simply pass that color back out.

Upvotes: 3

Related Questions