Customizing the graphics display of Vertices

How can I customize the way a vertex is seen in displayed, highlighted and picked state? i.e. the size, color of the vertices in displayed, highlighted and picked state

Thanks,

  • Shailesh

There are a couple of ways to customize the display of vertices.

A shader controls how a given piece of geometry is displayed. There is also a part of the shader that controls ‘picking’ or how the renderer detects the geometry under the mouse pointer, and another part controls the rendering of highlights.

I have provided a custom example here that shows a custom shader with separate controls for the ‘pointSize’ for display, picking and highlighting.

In the sample, the custom shader is in the file ‘custom-points-shader.js’

Here are the important parts of the sample.

const asset = new CADAsset()
const url = "..."
asset.load(url).then(() => {
  const materials = asset.getMaterialLibrary().getMaterials()
  materials.forEach((material) => {
    // Replace the shader used by the material with the 'CustomPointsShader'
    if (material.getShaderName() == 'PointsShader') {
      material.setShaderName('CustomPointsShader')
      material.getParameter('BaseColor').setValue(new Color(1,1,1))
      material.getParameter('PointSize').setValue(0)
      material.getParameter('PointHighlightSize').setValue(3)
      material.getParameter('PointPickSize').setValue(2)

      // The overlay parameter enables making the points display on top of
      // other geometry. Try setting this value to 0 to see the difference.
      material.getParameter('Overlay').setValue(0.001)
    }
  })
  asset.traverse((item) => {
    if (item instanceof GeomItem) {
      // By default, all the GeomItem share a single material.
      // To enable changing the point size on each point, we duplicate the
      // material.
      const materialParam = item.getParameter('Material')
      materialParam.setValue(materialParam.getValue().clone())
    }
  })

  renderer.frameAll()
  postMessage('done-loading')
})
scene.getRoot().addChild(asset)

Then, we can highlight the points using 2 different methods.
We can add a highlight to a point, or we can change its size.
I think in your case, you would prefer to change the point size than add a highlight.
Note: the highlight adds an outline around the point.

Note: we could also make these points round. That is a tweak to the fragment shader.

let highlightedItem
renderer.getViewport().on('pointerOverGeom', (event) => {
  const item = event.intersectionData.geomItem
  if (item) {
    highlightedItem = item
    const material = highlightedItem.getParameter('Material').getValue()
    const pointSizeParam = material.getParameter('PointSize')
    if (pointSizeParam) pointSizeParam.setValue(8)
    //highlightedItem.addHighlight('pointerOverGeom', new Color(1, 1, 1, 0.1), true)
  }
})
renderer.getViewport().on('pointerLeaveGeom', (event) => {
  const material = highlightedItem.getParameter('Material').getValue()
  const pointSizeParam = material.getParameter('PointSize')
  if (pointSizeParam) pointSizeParam.setValue(0)
  
  //highlightedItem.removeHighlight('pointerOverGeom', true)
  
  highlightedItem = null
})

As you move the mouse around, points will display.


ok, I presume you are pointing out the small points displayed event when pointSize is set to 0.0. I think this is probably caused by some minimum size limit on the point size. I addressed this by adding the following code to the shader

  if (gl_PointSize < 0.001) {
    gl_Position = vec4(-10.0, -10.0, -1.0, -1.0);
  }

What this does is move the points offscreen if they are too small.

You can re-test the glitch demo now.

A few points:
This sample shader is simply a copy/paste of the standard points shader in the engine.

The changes made were:
add 2 new size parameters

    paramDescs.push({ name: 'PointHighlightSize', defaultValue: 2.0 })
    paramDescs.push({ name: 'PointPickSize', defaultValue: 2.0 })

And then I customized the vertex shader to use the different size values depending on whther we are drawing color, picking buffer, or highlights.


  
#if defined(DRAW_COLOR)
  gl_PointSize = pointSize;
#elif defined(DRAW_HIGHLIGHT)
  gl_PointSize = pointHighlightSize;
#elif defined(DRAW_GEOMDATA)
  // Make the geom data point size at least 8 pixels across, else its impossible to hit.
  gl_PointSize = pointPickSize;
#endif

I created a CustomPointShader as described by you (created a Javascript file with its definition code) . However, when I use it in my typescript code as follows:

material.setShaderName(‘CustomPointsShader’);

An exception is raised at run-time:

core.js:6141 ERROR Error: Uncaught (in promise): Error: CustomPointsShader blueprint is not registered
Error: CustomPointsShader blueprint is not registered
at Object.getBlueprint (Registry.js:54)
at bs.setShaderName (Material.js:77)
at product3-dview.component.ts:269
at Array.forEach ()
at product3-dview.component.ts:266
at EventEmitter.js:190
at Array.forEach ()
at _.emit (EventEmitter.js:187)
at zea-cad@3.2.0:5
at ZoneDelegate.invoke (zone-evergreen.js:368)
at resolvePromise (zone-evergreen.js:1209)
at zone-evergreen.js:1279
at ZoneDelegate.invokeTask (zone-evergreen.js:402)
at Object.onInvokeTask (core.js:28500)
at ZoneDelegate.invokeTask (zone-evergreen.js:401)
at Zone.runTask (zone-evergreen.js:174)
at drainMicroTaskQueue (zone-evergreen.js:578)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:487)
at invokeTask (zone-evergreen.js:1596)
at Worker.globalZoneAwareCallback (zone-evergreen.js:1622)

Ok, if you put that same file into your project, you need to make sure it actually loads. (e.g. import it into your code).
At the bottom of the file, it registers the custom shader.

Registry.register(‘CustomPointsShader’, CustomPointsShader)

The error message suggests that the custom shader is not registered. You can put a breakpoint in the file and see if it gets hit.

Here, I have the debugger open and a breakpoint on that line, and as you can see, the debugger has stopped on it to show that the code is being loaded an executed.