2017-08-28 5 views
0

Je veux voir un wireframe d'un objet sans les diagonales commeShader wireframe d'un objet

enter image description here

Actuellement, j'ajouter des lignes selon les sommets, le problème est après que j'ai plusieurs de ceux que je éprouver une dégradation majeure des performances.

Les exemples here sont trop nouveaux pour ma version de Three ou ne fonctionnent pas (j'ai commenté là-dessus).

Donc, je veux essayer d'implémenter un shader à la place.

J'ai essayé d'utiliser ce shader: https://stackoverflow.com/a/31610464/4279201 mais il casse la forme en parties et j'obtiens des erreurs WebGL.

enter image description here

Voilà comment je l'utilise:

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) 
}) 

Donc, pour mettre en œuvre ce shader, est la bonne approche serait de vérifier fondamentalement l'angle entre tous les deux sommets, et tracez une ligne si le degré est de 90?

Comment puis-je avoir accès à tous les sommets de la forme à partir du vertex shader?

Et comment puis-je dire au fragment shader de dessiner une ligne entre deux sommets qui correspondent à la condition ci-dessus? (Également de laisser l'ombrage par défaut pour tout le reste est)

J'utilise Autodesk spectateur qui utilise Three.js rev 71.

+0

intérêt Q, mais pas de réponse - Suggestion 1) si nous utilisons dessiner le mode ligne avec la régénération droite des vertexIndices et la géométrie entière (dessiner seulement les fragments visibles avant) nous pouvons également obtenir une bonne optimisation (le plus petit nombre de points du vertex). 2) Peut-être que glBlend peut aider d'une manière ou d'une autre. 3) Faire un calcul de shader pour couper des valeurs indésirables ... –

+0

@NikolaLukic "dessine le mode ligne avec la régénération droite des vertexIndices" qu'est-ce que cela signifie? – shinzou

+0

Vous ne voulez pas de lignes de backside, une façon de rendre possible cette idée de faire en runtime (sur chaque drawFrame) une nouvelle géométrie avec seulement l'effet visuel voulu (sommets). La géométrie de l'objet original et l'emplacement/rotation de la caméra seront des valeurs de base pour le calcul. Pour le cube (exemple) - la nouvelle géométrie de cube a 3 (peut être 2 ou 1 également) côtés pas 6 dans l'ordre habituel. Désolé pour mon mauvais anglais. J'espère que vous comprenez mon commentaire –

Répondre

3
// -- 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/ 
*/