2017-08-14 3 views
1

Je voudrais savoir comment je pourrais déplacer des shaders qui sont réellement inclus dans mon html vers des fichiers externes. De cette façon, je serai en mesure de les inclure dans mes tâches de gulp. J'ai jeté un oeil à la façon dont les fichiers de shaders JavaScript sont écrits mais je ne comprends pas très bien. Par exemple avec le code Glow shader ci-dessous, comment pourrais-je le déplacer vers un fichier externe?Comment déplacer des scripts shader dans des fichiers externes?

<script type="x-shader/x-vertex" id="vertexShaderGlow"> 
    uniform vec3 viewVector; 
    uniform float c; 
    uniform float p; 
    varying float intensity; 
    void main() 
    { 
     vec3 vNormal = normalize(normalMatrix * normal); 
     vec3 vNormel = normalize(normalMatrix * viewVector); 
     intensity = pow(c - dot(vNormal, vNormel), p); 
     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 
    } 
</script> 
<script type="x-shader/x-vertex" id="fragmentShaderGlow"> 
    uniform vec3 glowColor; 
    varying float intensity; 
    void main() 
    { 
     vec3 glow = glowColor * intensity; 
     gl_FragColor = vec4(glow, 1.0); 
    } 
</script> 
+0

Vous avez seulement besoin du code de shader sous forme de chaîne, donc tout moyen permettant d'introduire une chaîne à partir d'un fichier externe pourrait être utilisé. – 2pha

+0

Pouvez-vous me montrer un exemple s'il vous plaît? – ClassikD

+0

J'ai édité la réponse donnée par Shao – 2pha

Répondre

0

La réponse suggérant de joindre un tableau de lignes glsl est un modèle qui peut être rencontré avec trois, mais devrait probablement être évitée dans ce cas d'utilisation.

Il peut être utile dans une sorte de module, où il s'agit en quelque sorte d'un instantané "compilé" d'un shader, non destiné à être modifié. Dans le cas contraire, les principaux inconvénients de cette approche sont le manque de coloration syntaxique et la verbosité.

De nos jours, la plupart des codes js sont transformés dans un sens ou dans l'autre. Le code Shader devrait être en ligne comme ceci.

const myShader = new THREE.ShaderMaterial({ 
    vertexShader: require('./myVert.vs'), 
    fragmentShader: require('./myFrag.vs'), 
}) 

modifier

myVert.vs:

//this is all nicely highlighted in sublime text for example 
void main(){ 
    gl_Position = vec4(position.xy, 0., 1.); 
} 

myVert.fs:

void main(){ 
    gl_FragColor = vec4(1.,0.,0.,1.); 
} 

myClass.js:

class myMaterial extends THREE.ShaderMaterial{ 
    constructor(){ 
    super({ 
     vertexShader: require('./myVert.vs'), 
     //^ becomes vertexShader: 'void main() {...}' 
     ... 
+0

Cette méthode semble bonne, mais elle augmentera le nombre de requêtes HTTP, n'est-ce pas? Les shaders inclus dans les fichiers Javascript étaient une bonne chose pour moi parce que je pouvais les réduire/fusionner et charger un seul Javascript pour tout mon site. Est-ce que le code dans les fichiers .vs est le même que le code dans les balises de script ou dois-je l'adapter? – ClassikD

+0

Non, ceci doit être utilisé conjointement avec webpack ou d'autres outils de groupage. '.vs' est juste un fichier txt. Une fois que l'outil de regroupement traite cela, le 'require (..)' serait remplacé par le contenu du fichier. Aucune demande supplémentaire n'est faite, ceci est juste en ligne dans votre paquet principal. – pailhead

+0

** Veuillez noter ** que les shaders ne sont rien de plus que des chaînes, le problème ici est d'obtenir la chaîne, la synchronisation, asynchrone, formatée ou non. Trois lui-même offre quelques fonctionnalités pour traiter ces chaînes spéciales telles que l'instruction '#import ...' qui ne fait pas partie de GLSL. C'est donc à vous de choisir le format le plus approprié. Plain old javascript ne peux pas faire une chaîne multiligne, c'est pourquoi vous devez ajouter '\ n' ou joindre les lignes dans un tableau. L'étape suivante est es6 cordes où vous pouvez simplement écrire plusieurs lignes. – pailhead

-2

Vous pouvez déplacer le code du shader dans un fichier JS distinct et inclure ce fichier après trois.js.
Voici un exemple de https://github.com/timoxley/threejs/blob/master/examples/js/shaders/ColorifyShader.js

/** 
* @author alteredq/http://alteredqualia.com/ 
* 
* Colorify shader 
*/ 

THREE.ColorifyShader = { 

    uniforms: { 

     "tDiffuse": { type: "t", value: null }, 
     "color": { type: "c", value: new THREE.Color(0xffffff) } 

    }, 

    vertexShader: [ 

     "varying vec2 vUv;", 

     "void main() {", 

      "vUv = uv;", 
      "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);", 

     "}" 

    ].join("\n"), 

    fragmentShader: [ 

     "uniform vec3 color;", 
     "uniform sampler2D tDiffuse;", 

     "varying vec2 vUv;", 

     "void main() {", 

      "vec4 texel = texture2D(tDiffuse, vUv);", 

      "vec3 luma = vec3(0.299, 0.587, 0.114);", 
      "float v = dot(texel.xyz, luma);", 

      "gl_FragColor = vec4(v * color, texel.w);", 

     "}" 

    ].join("\n") 

}; 

Avec ce qui précède, vous devez créer notre matériel comme celui-ci:

material = new THREE.ShaderMaterial({ 
    uniforms : THREE.ColorifyShader.uniforms, 
    vertexShader : THREE.ColorifyShader.vertexShader, 
    fragmentShader : THREE.ColorifyShader.fragmentShader 
}); 

ofcourse vous n'avez pas besoin d'appeler l'objet THREE.ColorifyShader, vous pouvez l'appeler tout tu veux.

+0

pas sûr pourquoi cela a obtenu un vote vers le bas, semble être une réponse raisonnable à moi et c'est comment je l'ai parfois fait dans le passé. – 2pha

+0

Je sais déjà que je peux déplacer le code du shader dans un fichier JS séparé et inclure ce fichier après three.js, ce n'était pas ma question. – ClassikD

+0

J'aimerais connaître la méthode pour convertir une syntaxe en une autre, le code semble être écrit de deux manières différentes. – ClassikD

1

L'autre réponse fournie consiste simplement à prendre du code GLSL et à transformer chaque ligne en une chaîne. Chaque chaîne est une valeur dans un tableau. L'appel join concatène toutes les chaînes avec un caractère \n pour faciliter la lecture du code lors du débogage. Je l'ai fait de cette façon plusieurs fois auparavant, et c'est une solution légitime à ce que vous essayez de faire. Mais si vous préférez avoir des fichiers externes avec du code GLSL brut, vous pouvez également le faire. Considérons les deux fichiers:

  • glow_vertex.glsl
  • glow_fragment.glsl

Ces fichiers contiennent le code de shaders que vous auriez normalement dans les balises de script. Vous pouvez utiliser un XMLHTTPRequest pour récupérer les fichiers et utiliser le texte renvoyé comme code de shader.

var vertexShader = null; 
var fragmentShader = null; 

function shadersDone(){ 
    var material = new THREE.ShaderMaterial({ 
     uniforms: { /* define your uniforms */}, 
     vertexShader: vertexShader, 
     fragmentShader: fragmentShader 
    }); 
} 

function vertexDone(code){ 
    vertexShader = code; 
    if(fragmentShader !== null){ 
     shadersDone(); 
    } 
} 

function fragmentDone(code){ 
    fragmentShader = code; 
    if(vertexShader !== null){ 
     shadersDone(); 
    } 
} 

var xhr1 = new XMLHttpRequest(); 
var xhr2 = new XMLHttpRequest(); 

xhr1.open("GET", "/server/glow_vertex.glsl", true); 
xhr2.open("GET", "/server/glow_fragment.glsl", true); 

xhr1.responseType = "text"; 
xhr2.responseType = "text"; 

xhr1.onload = function(){ 
    if(xhr1.readyState === xhr1.DONE && xhr1.status === 200){ 
     vertexDone(xhr1.resultText); 
    } 
}; 
xhr2.onload = function(){ 
    if(xhr2.readyState === xhr2.DONE && xhr2.status === 200){ 
     fragmentDone(xhr2.resultText); 
    } 
}; 

xhr1.send(null); 
xhr2.send(null); 

Notez que tout cela est asynchrone. En outre, votre serveur devra être configuré pour envoyer des fichiers GLSL en texte brut.

Tant que nous parlons du web moderne ...

Il y a aussi la possibilité de import votre code shader. TRÈS GRAND MAIS Actuellement, il est seulement supporté par Chrome et Opera (bien qu'il existe des polyfills). Microsoft Edge répertorie la fonctionnalité comme "sous examen", et Firefox ne pas indenter pour l'implémenter dans son état actuel. Alors, prenez ce qui suit avec un gros grain de sel, et de garder un oeil sur: http://caniuse.com/#search=import

Dans votre code HTML, et avant le JavaScript qui l'utiliser ...

<link id="vertexImport" rel="import" href="/server/glow_vertex.glsl" /> 
<link id="fragmentImport" rel="import" href="/server/glow_fragment.glsl" /> 

Puis, plus tard dans votre JavaScript:

var material = new THREE.ShaderMaterial({ 
    vertexShader: document.getElementById("vertexImport").import.body.childNodes[0].data, 
    fragmentShader: document.getElementById("fragmentImport").import.body.childNodes[0].data, 
}); 

De nouveau, ceci est asynchrone. Vous devrez peut-être ajouter un gestionnaire onload pour chaque lien, de sorte que vous n'essayez pas d'accéder au code avant qu'il ne soit chargé.

+0

Cela ne devrait pas être une solution légitime. C'est la deuxième moitié de l'année 2017, '(glsl | vert | frag | fs | vs)' devraient toutes être des extensions que vous pouvez 'require' et inline dans votre code, ou faire une requête xhr. La deuxième approche devrait être dépréciée. – pailhead

+0

@pailhead Vous pouvez trouver mon ajout intéressant, si un peu inutile pour cross-browser. – TheJim01

+0

Très intéressant, le point négatif pour moi est qu'il a besoin d'une configuration serveur, et c'est un peu plus lourd à gérer:/ – ClassikD