Shader wireframe of an object
Asked Answered
O

1

1

I want to see a wireframe of an object without the diagonals like

enter image description here

Currently, I add lines according to the vertices, the problem is after I have several of those I experience a major performance degradation.

The examples here are either too new for my version of Three or don't work (I commented there about it).

So I want to try to implement a shader instead.

I tried to use this shader: https://mcmap.net/q/413639/-display-wireframe-and-solid-color but it breaks the shape to parts and I'm getting WebGL errors.

enter image description here

That's how I use it:

const vertexShader = `
varying vec2 vUv;
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`

const fragmentShader = `
#version 150 compatibility                                         
flat in float diffuse;
flat in float specular;
flat in vec3  edge_mask;                                           
in vec2 bary;
uniform float mesh_width = 1.0;
uniform vec3 mesh_color = vec3(0.0, 0.0, 0.0);
uniform bool lighting = true;
out vec4 frag_color ;
float edge_factor(){                                               
  vec3 bary3 = vec3(bary.x, bary.y, 1.0 - bary.x - bary.y);
  vec3 d = fwidth(bary3);
  vec3 a3 = smoothstep(vec3(0.0, 0.0, 0.0), d * mesh_width, bary3);
  a3 = vec3(1.0, 1.0, 1.0) - edge_mask + edge_mask * a3;
  return min(min(a3.x, a3.y), a3.z);
}
void main() {                                                      
  float s = (lighting && gl_FrontFacing) ? 1.0 : -1.0;
  vec4  Kdiff = gl_FrontFacing ?
    gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;
  float sdiffuse = s * diffuse;
  vec4 result = vec4(0.1, 0.1, 0.1, 1.0);
  if (sdiffuse > 0.0) {
    result += sdiffuse * Kdiff +
      specular * gl_FrontMaterial.specular;
  }
  frag_color = (mesh_width != 0.0) ?
    mix(vec4(mesh_color, 1.0), result, edge_factor()) :
    result;
}`     

...

const uniforms = {
  color: {
    value: new THREE.Vector4(0, 0, 1, 1),
    type: 'v4'
  }
}

const material = new THREE.ShaderMaterial({
  fragmentShader: data.fragmentShader,
  vertexShader: data.vertexShader,
  uniforms
})

this._viewer.impl.matman().addMaterial(
  data.name, material, true)

    const fragList = this._viewer.model.getFragmentList()

this.toArray(fragIds).forEach((fragId) => {

  fragList.setMaterial(fragId, material)
})

So to implement this shader, is the right approach would be to basically check the angle between every two vertices, and draw a line if the degree is 90?

How can I have access to all the vertices of the shape from the vertex shader?

And how can I tell the fragment shader to draw a line between two vertices that match the above condition? (also to leave the default shading for everything else as is)

I'm using Autodesk viewer that uses Three.js rev 71.

Optic answered 28/8, 2017 at 11:11 Comment(5)
Interest Q , No answer but - Suggestion 1) if we use draw line mode with right regeneration of vertexIndices and whole geometry (draw only front visible fragments) we can also got a good optimisation (lowest number of vertex points) . 2) Maybe glBlend can help in some way . 3) Make a shader calculation to cut of unwanted values ...Plossl
@NikolaLukic "draw line mode with right regeneration of vertexIndices" what does that mean?Optic
You don't want backside lines , one way to make it possible that idea is to make in runtime (on every drawFrame) new geometry with only wanted visual effect (vertices) . Original object geometry and location/rotation of camera will be base values for calculation . For cube (example) - new cube geometry have 3 ( can be 2 or 1 also ) sides not 6 in usually order . Sorry on my bad english . I hope you understand my commentPlossl
Your shader is not valid for WebGL. This line in particular #version 150 compatibility is not valid WebGL GLSL. Your shader is not compiling successfully and therefore you're getting errors related to a bad shader. These lines as well flat in float diffuse; are also WebGL2 onlyUnknown
I'm still getting errors with those lines and variables removed... @UnknownOptic
P
4
// -- Vertex Shader --
precision mediump float;

// Input from buffers
attribute vec3 aPosition;
attribute vec2 aBaryCoord;

// Value interpolated accross pixels and passed to the fragment shader
varying vec2 vBaryCoord;

// Uniforms
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;

void main() {
    vBaryCoord = aBaryCoord;
    gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition,1.0);
}
// ---------------------

// -- Fragment Shader --
// This shader doesn't perform any lighting
precision mediump float;

varying vec2 vBaryCoord;

uniform vec3 uMeshColour;

float edgeFactor() {
    vec3 d = fwidth(vBaryCoord);
    vec3 a3 = smoothstep(vec3(0.0,0.0,0.0),d * 1.5,vBaryCoord);
    return min(min(a3.x,a3.y),a3.z);
}

void main() {
    gl_FragColor = vec4(uMeshColour,(1.0 - edgeFactor()) * 0.95);
}
// ---------------------

/*
    This code isn't tested so take it with a grain of salt

    Idea taken from
    http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/
*/
Pestilence answered 1/9, 2017 at 8:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.