Three.js: Material: Agregado onBeforeCompile ()

Creado en 9 jun. 2017  ·  75Comentarios  ·  Fuente: mrdoob/three.js

A lo largo de los años, una solicitud de característica común ha sido poder modificar los materiales incorporados. Hoy me di cuenta de que podría implementarse de manera similar a Object3D 's onBeforeRender() .

https://github.com/mrdoob/three.js/commit/e55898c27a843f69a47e602761c60d9bbe91ee35

WebGLPrograms agrega onBeforeCompile.toString() al hash del programa, por lo que esto no debería afectar a otros materiales incorporados utilizados en la escena.

A continuación, se muestra un ejemplo de la función en acción:

http://rawgit.com/mrdoob/three.js/dev/examples/webgl_materials_modified.html

material.onBeforeCompile = function ( shader ) {

    // console.log( shader )

    shader.uniforms.time = { value: 0 };

    shader.vertexShader = 'uniform float time;\n' + shader.vertexShader;
    shader.vertexShader = shader.vertexShader.replace(
        '#include <begin_vertex>',
        'vec3 transformed = vec3( position.x + sin( time + position.y ) / 2.0, position.y, position.z );'
    );

    materialShader = shader;

};

No solo podemos alterar el código de sombreado, sino que también podemos agregar uniformes personalizados.

if ( materialShader ) {

    materialShader.uniforms.time.value = performance.now() / 1000;

}

¿Es demasiado hacky?

/ cc @WestLangley @bhouston @tschw

Enhancement

Comentario más útil

@mrdoob Creo que es difícil (o imposible) serializar Materiales pirateados con .onBeforeCompile() . ¿Crees que los usuarios deberían usar ShaderMaterial si quieren materiales incorporados modificados completamente funcionales (renderizar, copiar, clonar, serializar, etc.)?

No esperaba (consideraba) el uso de onBeforeCompile() para ser serializado ...

Todos 75 comentarios

Parece un poco engañoso requerir una manipulación personalizada de cadenas cuando WebGLProgram.js ya realiza mucho procesamiento. Hay un caso de uso relacionado, que consiste en agregar nuevos #includes en lugar de anular los existentes. Puede hacer esto hoy modificando THREE.ShaderLib en tiempo de ejecución, pero se siente igualmente sucio.

Quizás una mejor solución para ambos es permitirle proporcionar un ShaderLib personalizado para un material, que anularía / aumentaría los fragmentos incorporados sin manipulación manual de cadenas y sin golpearlos permanentemente. Eso no excluye un gancho onBeforeCompile para otros usos, pero parece más en línea con lo que su ejemplo está tratando de hacer.

Dicho esto, la composición de sombreadores basada en inclusiones sin formato siempre será muy frágil de una versión a la siguiente. Si no le importa incluir todo el código esqueleto (como meshphong_vert.glsl ), ya puede ampliar los materiales incorporados con algo como esto:

export class MyPhongMaterial extends ShaderMaterial {
  constructor({ color, radius, map, normalMap, emissiveMap }) {
    super();
    this.vertexShader = "...."
    this.fragmentShader = "....";
    this.uniforms = UniformsUtils.clone(ShaderLib.phong.uniforms);

    this.isMeshPhongMaterial = true;
    this.lights = true;

    this.uniforms.time = { value: 1 };
    //...
  }
}

En todos los casos, debe confiar en la organización interna de los sombreadores integrados para no cambiar demasiado de una versión a la siguiente. Cada inclusión ya es una función disfrazada, con una firma mal especificada. Sospecho que va a ser mucho más limpio y fácil de mantener en ambos lados para proporcionar anulaciones a nivel de función en lugar de a nivel de inclusión.

Hoy pensé ...

¡Bonito! Yo también lo pensé el 10 de febrero cuando hice esta solicitud de extracción:

https://github.com/mrdoob/three.js/pull/10791

Parece que la única diferencia es que lo estás haciendo a través de una devolución de llamada. Aproveché el argumento no utilizado en WebGLRenderer.

Me gusta usar esto, por ejemplo, para que threejs funcione con mapas normales, pero he vinculado algunos problemas que parecen ser triviales de resolver con esto.

Puedes mirar mi rama y probar esto o ver este ejemplo súper simple (solo prueba una deformación personalizada con iluminación / sombras, etc., y agrega algunos uniformes).

http://dusanbosnjak.com/test/webGL/three-material-shader-override/webgl_materials_shader_override.html

Quizás una mejor solución para ambos es permitirle proporcionar un ShaderLib personalizado para un material, que anularía / aumentaría los fragmentos incorporados sin manipulación manual de cadenas y sin golpearlos permanentemente.

Resume exactamente lo que sucede en: https://github.com/mrdoob/three.js/pull/10791 Desearía poder escribir mejores descripciones :)


Debo admitir que no sé qué está pasando aquí. Creo que conozco a alguien que dejó de contribuir a tres, no lo entendía entonces, pero ahora lo encuentro un poco frustrante.

Frustrante principalmente porque estoy teniendo un deja vu cuando leo el primer párrafo:

... de forma similar a onBeforeRender () de Object3D.

Exactamente lo mismo sucedió con onBeforeRender() https://github.com/mrdoob/three.js/pull/9738 , cuando se necesitó un año de convencer para incorporar la función.

Dios, dos veces, ¿con el mismo desarrollador? Obviamente estoy haciendo algo mal aquí, pero ¿qué? La primera vez fue que se registraron los archivos de compilación, no sabía qué hacer y simplemente se olvidó. Pero esta vez estaba al tanto de esta solicitud de extracción, hay un conflicto en este momento pero se resuelve fácilmente, no hubo conflictos durante meses.

No me malinterpretes, no creo que sea vanidad en las obras aquí, creo que solo quiero transmitir ideas por personas y obtener comentarios. @inconed , es obvio que está familiarizado con el problema y probablemente haya intentado cosas diferentes. ¿Qué pudo haber causado que un usuario como usted se perdiera el otro PR?

Me sentí bastante bien con el shaderlib por material, pero encontré una función en el renderizador que miraba / comparaba sombreadores completos como cadenas para descubrir el almacenamiento en caché, no me sentía tan bien con eso. Ojalá hubiera algún comentario dado ...

¿Fue erróneo el ejemplo? La cabeza puede hacer que sea mucho más obvio lo que está sucediendo que mi bola de púas abstracta, pero todo el ejemplo funciona con sombras que cubren más terreno. Es pesado por alguna razón, pero creo que es porque sin / cos en muchas verts.

Supongo que si estás comenzando de nuevo ... Aunque el kit de escenas es absolutamente horrible, esta API es realmente agradable:

https://developer.apple.com/documentation/scenekit/scnshadable

Aunque está horriblemente documentado, no puedo encontrar la parte que es de más interés, pero básicamente han abstraído ganchos en muchas etapas diferentes del sombreador.

A principios de este año hice una solicitud de extracción que parece hacer algo similar, si no exactamente lo mismo:

https://github.com/mrdoob/three.js/pull/10791

Parece que la única diferencia es que lo estás haciendo a través de una devolución de llamada. Aproveché el argumento no utilizado en WebGLRenderer.

Lo siento por no poder ocuparme de ese PR todavía @pailhead. Supongo que la principal ventaja de mi enfoque es que solo requirió 3 líneas nuevas.

Habiendo dicho eso, ahora dedicaré un tiempo a estudiar las suyas y @inconed .

Este definitivamente se siente más elegante, solo tres líneas. Seguía un patrón diferente en el otro. Iba a decir que puede ser un poco más detallado, pero no tan seguro. Supongo que la única ventaja del otro es que estuvo bueno para ir hace unos meses :)

Dios, dos veces, ¿con el mismo desarrollador? Obviamente estoy haciendo algo mal aquí, pero ¿qué?

Lo siento por eso. Lo único que se me ocurre es que probablemente me sentí abrumado. Tal vez una discusión larga o un RP complicado que consumiría demasiadas energías, así que decido dejarlo para más tarde y pasar a RP más simples.

No eres solo tú @pailhead. @bhouston ha tenido muchas relaciones públicas como esta, incluso @WestLangley y @ Mugen87.

Una vez más, no es que no me gusten las relaciones públicas, es que las relaciones públicas requieren una atención que no puedo ofrecer en ese momento. Un buen ejemplo es el Instancing PR. Me las arreglé para encontrar tiempo para leerlo, hice mi propia experimentación y sugerí simplificaciones. Ojalá pueda volver a visitarlo pronto.

Es difícil gestionar todo esto y dar a cada RP la atención que se merecen.

¿Fue erróneo el ejemplo? La cabeza puede hacer que sea mucho más obvio lo que está sucediendo que mi bola de púas abstracta, pero todo el ejemplo funciona con sombras que cubren más terreno. Es pesado por alguna razón, pero creo que es porque sin / cos en muchas verts.

Ahora lo mencionas ... Sí, se ejecuta a 10 fps en una nueva MacBook Pro al hacer zoom 😮

Creo que son las sombras y el rand, sin cos y esas cosas, pero sí, parece que se necesita demasiado.

De cualquier manera, me sorprende que lo hayas logrado en tres líneas, estaba demasiado concentrado en cómo los params materiales se convierten en uniformes y siguen ese patrón. La diferencia es que proporciono un diccionario alternativo como ShaderLib , por lo que #include <> trae un código diferente. Elimina la inclusión antes de que esto suceda y la reemplaza con glsl. Creo que si devuelve algún tipo de envoltorio alrededor del sombreador, tal vez esta sintaxis podría ser más limpia (solo proporcione el nombre del fragmento + glsl, en lugar de replace() . Pero puede terminar pareciéndose mucho más al otro .

Sería muy bueno tener esto, no he trabajado con tantos motores 3D, pero la unidad y el kit de escena parecen tener algo como esto.

@inconed

Supongo que un beneficio del onBeforeCompile() es que las propiedades del material permanecen sin cambios. Entonces se siente más como extender los materiales incorporados.

export class MyMeshPhongMaterial extends MeshPhongMaterial {
  constructor( parameters ) {
    super( parameters );
    this.onBeforeCompile = function ( shader ) {
      shader.vertexShader = shader.vertexShader.replace(
        '#include <begin_vertex>',
        'vec3 transformed = vec3( position.x + sin( position.y ) / 2.0, position.y, position.z );'
      );
    };
  }
}

var material = new MyMeshPhongMaterial();
material.color.setRGB( 1, 0, 0 ); // this still works

Jugar con ShaderLib es realmente complicado. Sin embargo, debería ser factible agregar ganchos sin cambios para siempre:

    #include <begin_vertex>
    % vertex %
    #include <morphtarget_vertex>
    #include <skinning_vertex>
    % transformed_vertex %
    #include <project_vertex>
    % projected_vertex %

El código de reemplazo se convertirá en esto:

this.onBeforeCompile = function ( shader ) {
  shader.vertexShader = shader.vertexShader.replace(
    '% vertex %',
    'transformed.x += sin( position.y ) / 2.0;'
  );
);

Luego, eliminaremos cualquier gancho que no se haya utilizado antes de compilar, por supuesto.

así es como se ve en comparación con los ShaderChunks por instancia

//given some material
var material = new THREE.MeshNormalMaterial();

//and some shader snippet
var myShader = [
    'float theta = sin( time + position.y ) / 2.0;',
    'float c = cos( theta );',
    'float s = sin( theta );',
    'mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );',
    'vec3 transformed = vec3( position ) * m;', //and making assumptions about THREE's shader framework
    'vNormal = vNormal * m;'
].join( '\n' );

https://github.com/mrdoob/three.js/pull/10791 igual que el enfoque Material.defines :

material.shaderIncludes = {

        begin_vertex: myShader,

    //uv_pars_vertex: [
    //  THREE.ShaderChunk['uv_pars_vertex'], //this doesn't have to be
    //  "uniform float time;",
    //].join('\n')
};

material.shaderUniforms = { time: { value: 0, type: 'f' || 'float' } }; //because this could just inject it in the right place (but needs type)

_Es solo un diccionario de nombres fragmentados, y los uniformes se oponen. La manipulación de cadenas aquí es más en la línea de "quiero reutilizar este fragmento y hacer algo sobre él" _

este PR:

material.onBeforeCompile = function ( shader ) {

    shader.uniforms.time = { value: 0 };

    shader.vertexShader = 'uniform float time;\n' + shader.vertexShader; //this feels hacky

    shader.vertexShader = shader.vertexShader.replace( //this is more verbose
        '#include <begin_vertex>',
        myShader
    );

};

Supongo que uno de los beneficios de onBeforeCompile () es que las propiedades del material permanecen sin cambios.

Funciona igual en las otras relaciones públicas, así que creo que no importa cómo se haga.


Un beneficio probablemente irrelevante en el que puedo pensar es que puede mantener la lógica para manipular el material en el mismo bloque y en el mismo nivel. Si tenía un fragmento de código en algún lugar que cambia de color y luego agrega GLSL personalizado a ese material, puede agregar el código para cambiar el uniforme con el color. (saltar la pared del texto)


Si el uv_pars_vertex es confuso, creo que una buena pregunta es:

"¿Dónde inyecto mi función GLSL personalizada, como float rand( vec2) ?"

Entonces este podría tener sentido https://github.com/mrdoob/three.js/pull/11050


Otro argumento podría ser: asumiendo que conoce GLSL, asumiendo que conoce el marco de sombreado de THREE, aún debe ser creativo y pensar dónde inyectar qué. Tuve que pensar un poco y mirar a través de la mayoría de los sombreadores para descubrir que uv_pars_vertex es un lugar conveniente para hacer mi extensión de material.

Sería mejor pasar de algo como esto a una abstracción, tener ganchos lightingPhase , objectTransformation , perspectiveTransformation etc. O al menos un fragmento ficticio de guaranteedToBeAboveMainButBelowCommonsAndExtensionCalls que se incluye en cada programa de sombreado. Parece que vas por eso con % vertex % ? Pero no estoy familiarizado con esa sintaxis.

Este PR, como está, parece que va en la dirección opuesta. Además de saber dónde debe tocar, también debe ser explícito y manipular cadenas, repitiendo parte del trabajo que el renderizador ya hace por usted. Además, si hace otra pregunta además de la primera

¿Cómo uso una función, declarada en el fragmento común, dentro de la función que estoy inyectando?

es posible que se encuentre haciendo más manipulación de cadenas que simplemente anteponer los uniformes a todo el sombreador.

Tuve que pensar un poco y mirar a través de la mayoría de los sombreadores para descubrir que uv_pars_vertex es un lugar conveniente para hacer mi extensión de material.

No creo que haya una forma de evitar eso a menos que hagamos un exceso de ingeniería. La idea con % vertex % es intentar ayudar un poco con eso nombrando los ganchos y más o menos decirle en qué estado está inyectando código, pero sería difícil documentar qué variables están disponibles en qué punto .

Estamos abriendo una puerta para permitir la piratería de materiales integrados, pero no creo que podamos brindar el "soporte" adecuado. El usuario debe ser consciente de que existe la posibilidad de que algo se rompa.

Traté de abordarlo en las otras relaciones públicas. Agregué un gancho falso al menos para las funciones, variaciones, atributos y uniformes. Mucha de la lógica GLSL ya ocurre en estructuras, scenekit documentó cada variable (aunque ya no puedo encontrar la misma documentación).

Probablemente debería ser refactorizado a medida que avanzamos, pero algo en este sentido:

#ifdef PHASE_FOO

#include <shader_foo> 
//someGlobalStruct.mvPosition = modelViewMatrix * myLogic( transformed );
//if there is glsl provided for phase "foo" document that it should operate on "transformed" 
//and that it should return "mvPosition" 
#end including <shader_foo>

#else 

  //default
  #ifdef USE_SKINNING

    vec4 mvPosition = modelViewMatrix * skinned;

  #else

    vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );

  #endif

#ifdef PHASE_BAR

#include <something_like_this>
//mvPosition = myPostDefaultTransformationLogic( mvPosition );

#endif

gl_Position = projectionMatrix * mvPosition;

#endif

Por supuesto, ifdefs e includes probablemente no funcionarían así. Pero puedo ver que es relativamente sencillo con el otro enfoque. Podríamos agregar #include <some_phase> siempre, con cadenas vacías. Algo podría ayudar a administrar lo que se activa al usar #ifdef s. Entonces, por ejemplo, si proporciona lógica para la fase "vertex_transformation", el sombreador definirá lo que proporcione. En general, sería útil documentar lo que hace cada fragmento con GLSL. Sin profundizar en la abstracción, creo que sería genial tener este mapa de cómo están estructurados los fragmentos ahora.

Estamos abriendo una puerta para permitir la piratería de materiales integrados, pero no creo que podamos brindar el "soporte" adecuado. El usuario debe ser consciente de que existe la posibilidad de que algo se rompa.

Ya tenemos las cosas definidas disponibles en cada material. https://github.com/mrdoob/three.js/issues/10764 sugirió modificar THREE.ShaderLib y luego definir una propiedad .defines en una instancia de Material . De acuerdo, la propiedad no estaba documentada hasta que escribí la entrada (pero usted la aprobó :)) y aún no está

Pero la forma en que esto funciona actualmente, y es heredado por cada material, es compatible; si pones algo en él, afectará el sombreador de ese material . Además, si define algo que ya es parte de la biblioteca de sombreadores, puede romper cosas .

No tratando de ser un sabelotodo, sino tratando de dar un ejemplo. Usé principalmente define con ShaderMaterial pero afecta a todos los materiales, solo porque funciona WebGLRenderer . No hay lógica que diga:

si es mucho más inteligente, una superficie como la abstracción de un material como Phong entonces no tenga en cuenta las definiciones. Debido a que tres no está diseñado para que se anulen sus fragmentos de sombreado, y la plantilla Phong es la autoridad final sobre lo que debe hacer GLSL, y sirve para ocultar esto del uso, tiene sentido que las definiciones de GLSL no interfieran con esto.

Sin embargo, no estoy del todo seguro de si se puede romper, tendría que intentarlo.

Habiendo dicho eso, me gustaría tener la opción de romper cosas, si proporciona mucha ganancia. Con un fragmento de GLSL bastante encapsulado y pequeño, podría cambiar fácilmente mi versión de tres para representar mapas normales de manera diferente. Tomar una normal y transformarla para obtener otra normal es muy sencillo, a menos que comencemos a hacer gráficos por computadora de una manera completamente diferente, no puedo ver que esto se rompa nunca :)

Instanciar fue otro ejemplo:

oh, me gustaría usar ANGLE_INSTANCED_ARRAYS, tres no parecen apoyarlo con sus sombras o materiales PBR, permítanme agregar estas dos líneas y hacer que funcionen para mí "

Estoy feliz de ver que estas características finalmente llegarán a three.js :). Sí, también creé un yet another material modifier PR (https://github.com/mrdoob/three.js/pull/7581) Era tan antiguo que el código ya no es relevante, pero básicamente está inyectando ganchos como @mrdoob propone y luego simplemente reemplácelos por su propio código.
Me gusta la idea de ganchos predefinidos, ya que es fácil entender lo que estás modificando, ya que creo que la mayoría de las personas que quieren usar esta función quieren modificar "ligeramente" el material predeterminado en lugar de reescribirlo por completo.

Me gusta la simplicidad de este PR, pero si buscamos una forma más estructurada / limpia de hacer las cosas, preferiría tener ya un diccionario de ganchos para reemplazar con su código y una forma más sencilla de agregar uniformes o código personalizado que simplemente reemplazando cadenas.

@fernandojsg en cualquier oportunidad que pueda ver # 10791, dar su opinión, parece muy similar a lo que hizo, excepto que puse el gancho adicional fuera de main (algo así como su "pre_vertex") y hay un poco más de administración.

@fernandojsg Me había olvidado de tus relaciones públicas 😚. Creo que su relaciones públicas se parece mucho a cómo estaba empezando a ver que esto funcionaba. ¿Subconsciente?

No tratando de ser un sabelotodo, sino tratando de dar un ejemplo. Usé principalmente define con ShaderMaterial pero afecta a todos los materiales, solo porque funciona WebGLRenderer .

Me alegro de que la biblioteca se pueda piratear de esa manera, pero no deberíamos usar las funciones de abuso de manera inernal para cosas para las que no fueron diseñadas. Es fácil terminar con un código frágil de esa manera.

Leyendo # 7581 de nuevo ... En la parte superior de https://github.com/mrdoob/three.js/commit/e55898c27a843f69a47e602761c60d9bbe91ee35 podemos agregar el % HOOKS % y luego crear una clase como esta:

THREE.ExtendedMaterial = function ( material, hooks ) {

    material.onBeforeCompile = function ( shader ) {
        var vertexShader = shader.vertexShader;
        var fragmentShader = parameters.fragmentShader;
        for ( var name in hooks ) {
           vertexShader = vertexShader.replace( '%' + name + '%', hooks[ name ] );
           fragmentShader = fragmentShader.replace( '%' + name + '%', hooks[ name ] );
        }
        shader.vertexShader = vertexShader;
        shader.fragmentShader = fragmentShader;
    };

    return material;

};

Entonces podemos hacer esto:

`` js
var material = new THREE.ExtendedMaterial (
nuevo THREE.MeshBasicMaterial (),
{vértice: 'transformado.x + = sin (posición.y) / 2.0;' }
);

Entonces la pregunta es, ¿qué ganchos deberíamos tener?

VERTEX
TRANSFORMED_VERTEX
PROJECTED_VERTEX

NORMAL
TRANSFORMED_NORMAL

FRAGMENT_UNIFORMS
INPUT_FRAGMENT
OUTPUT_FRAGMENT

@mrdoob Como ejemplo, puede ver en esta esencia donde el código debe inyectarse en el sombreador de vértices MeshBasicMaterial para admitir la creación de instancias.

Y aquí para el resto de materiales :)

https://github.com/mrdoob/three.js/pull/10750

VERTEX_UNIFORMS suena demasiado obstinado, ¿dónde debería agregar una función, un atributo o una variación? PRE_VERTEX o algo así?

NORMAL_MAP definitivamente se necesita

vert:

PRE_VERTEX
VERTEX
TRANSFORMED_VERTEX
PROJECTED_VERTEX

NORMAL
TRANSFORMED_NORMAL

UV
fragment:

PRE_FRAGMENT
INPUT_FRAGMENT
LIGHT
NORMAL

OUTPUT_FRAGMENT

VERTEX_UNIFORMS suena demasiado obstinado, ¿dónde debería agregar una función, un atributo o una variación? PRE_VERTEX o algo así?

Hmm, ¿obstinado? ¿Cómo es eso?

attribute vec4 aMyAttribute; no es un uniforme :)

float myRand( vec4 foo ) { /*logic*/ return vec4(bar,baz)} no es un uniforme

varying vec3 vMyVarying; tampoco es un uniforme

o no plural, o no uniformes en absoluto

¿Cuál es el caso de uso de atributos de "inyección"?
¿No debería usar geometry.addAttribute( 'aMyAttribute', ... ) lugar?

No sabía que no tienes que declararlo. ¿Todavía deja variaciones y funciones?

¿Todavía deja variaciones y funciones?

Buen punto.

¿Realmente ya no tienes que declarar atributos en GLSL? Pensé que funcionaba más como uniformes, declaras en GLSL pero no tienes que escribirlo en JS.

Creo que esta lista puede crecer bastante rápido, cuando se trata de ciertas cosas, el código se vuelve bastante disperso. Una forma de hacer mapas normales implica dos atributos adicionales, variaciones y lógica de transformación tanto en vert como en frag.

Me gustan los últimos cambios, sigue siendo simple y elegante. Estoy de acuerdo con @pailhead en que necesitamos un lugar para colocar el código en el ámbito global. En https://github.com/mrdoob/three.js/pull/7581 tenía preMainVertex preMainFragment para inyectar globalmente para que pudiera usarlos para variar y funciones. Probablemente un nombre como globalVertex/Fragment o similar podría ser mejor.

GLOBAL_VERTEX y GLOBAL_FRAGMENT suenan bien 👌

exactamente como los nombré en el otro PR 😆 👍

@pailhead Pero ahora conoces el secreto para fusionar tu código: simplemente abre un PR, déjalo ahí algún tiempo, luego espera a que @mrdoob eventualmente piense en hacer algo similar, espera su PR y luego comente allí haciendo referencia al exacto de la misma manera que lo hiciste en tus relaciones públicas para que él pueda pensar que fue su idea, lo agregará, fusionará ... ¡ganancias!

image

Ahora en serio, también me gustan esos nombres y con eso creo que estamos listos para empezar, ¿o me estoy perdiendo algo? Intentaré convertir el ejemplo de mi PR a este nuevo código;)

La parte sobre la entrada del código está bien, la línea de tiempo está un poco fuera de lugar. # 7581 se sugirió hace casi dos años. No se mencionó en https://github.com/mrdoob/three.js/issues/10789 , por lo que probablemente se salió del radar. Lo habría golpeado o bifurcado.

Incluso cuando se importan módulos y se eligen tres, la gente no está muy contenta con el uso de módulos centrales no oficiales. Es mucho más fácil decir "hey, hay un paquete npm que maneja foo". Es por eso que siento que las relaciones públicas como esta son importantes, tres no es lo suficientemente flexible.

¡lucro!

¿Qué beneficio? 😆

La parte sobre la entrada del código está bien, la línea de tiempo está un poco fuera de lugar. # 7581 se sugirió hace casi dos años. No se mencionó en https://github.com/mrdoob/three.js/issues/10789 , por lo que probablemente se salió del radar. Lo habría golpeado o bifurcado.

¿Qué? ¿No marcó todos los PR abiertos antes de crear uno nuevo? #trololol

cierto :)

ok marque en la lista y tengamos esto lo antes posible: D

Este sombreador (por ejemplo):

#include <shadowmap_pars_vertex>

void main() {

    #include <begin_vertex>
    #include <project_vertex>
    #include <worldpos_vertex>
    #include <shadowmap_vertex>

}

se parece a esto:

#include <shadowmap_pars_vertex>

void main() {

    % begin_vertex %
    % project_vertex %
    % worldpos_vertex %
    % shadowmap_vertex %

}

Umm, no estoy seguro de si reemplazarlos todos o simplemente inyectar el código dejando parte del comportamiento actual:

#include <shadowmap_pars_vertex>

%GLOBAL_VERTEX% 
void main() {
       %PRE_VERTEX% 
    #include <begin_vertex>
...
}

Mi enfoque inicial fue inyectar el código adicional dejando intacto el resto de la inclusión.

Entonces % hook % es solo para los ganchos reales, si uno quiere reemplazar <begin_vertex> todavía tiene que buscarlo en una cadena, es decir. no habrá un begin_vertex gancho?

En mi PR, solo quería modificar ligeramente el comportamiento del material, por lo general, hacer algunas correcciones de color después de que el fs se ejecutó por completo o frente a transformaciones similares a la que @mrdoob mostró en su ejemplo.
Pero sí, si queremos reemplazar completamente cada una de las inclusiones, debemos usar los ganchos en lugar de las inclusiones y agregar la lógica para inyectar la inclusión en sí en caso de que no haya vinculado el gancho.

Me gustaría hacer eso para los normales (no usar derivados y usar información TBN real de 3ds max o maya o en cualquier lugar donde se genere el mapa normal). La adaptación de MeshPhongMaterial para trabajar con instancias también requirió reemplazar algunos fragmentos por completo, pero esto se siente como un caso tan avanzado.

Esos son los dos en los que puedo pensar, me pregunto si hay más.

Entonces % hook % es solo para los ganchos reales, si uno quiere reemplazar <begin_vertex> todavía tiene que buscarlo en una cadena, es decir. no habrá un begin_vertex gancho?

Puede reemplazar ambos. El código actual ya te permite reemplazar lo que sea. %HOOK% son para su conveniencia.

Como mencioné en el n. ° 11562, ¿qué tal el concepto de fragmentos de sombreado reemplazables?

Ejemplo:

const material = new THREE.MeshPhongMaterial({
  color: 0xffffff,
  map: texture,

  parts: {
    frag: {
      map_pars_fragment: `
        uniform sampler2D map;
        uniform sampler2D map2;
     `,

      map_fragment: `
        vec4 texelColor = texture2D( map, vUv );
        vec4 texelColor2 = texture2D( map2, vUv );

    texelColor = mapTexelToLinear( 
          mix( texelColor, texelColor2, progress)
        );

    diffuseColor *= texelColor;
      `
    }
  }
});

material.uniforms.progress = {value: 1};
material.uniforms.map2 = {value: texture2};

Así de simple puede ser el código de transición entre múltiples texturas en 1 material.

Se puede implementar fácilmente y evitar hacer código innecesario.

@ sasha240100

https://github.com/mrdoob/three.js/pull/10791 se ve exactamente como el que está sugiriendo, excepto que parts se llaman shaderChunks y no lo toma como un argumento.
: roll_eyes: 😆

Tampoco necesita el diccionario frag{} , ya que los fragmentos ya están marcados. Todos tienen _fragment y _vertex .

Este hace lo mismo, excepto que tiene que buscar en la cadena para encontrar lo que necesita reemplazar.

@pailhead Sí, dejemos caer el frag: {} . Lo usé como argumento porque debería pasarse antes de concatenar el sombreador de material. En este caso, simplemente podemos evitar reemplazar las piezas existentes después de la concatenación.

De hecho, podemos agregar ambos: como argumento y como propiedad. Como hace color

¿Dónde está esto ahora mismo? Veo que el ejemplo está haciendo .replace() y no veo ganchos / trozos reemplazables. @mrdoob

Aún no he podido volver a esto.

¿Le gustaría hacer un PR para la cosa % hook % ?

¿Quieres el material ampliado, del comentario anterior?

THREE.ExtendedMaterial = function ( material, hooks ) {

    material.onBeforeCompile = function ( shader ) {
        var vertexShader = shader.vertexShader;
        var fragmentShader = parameters.fragmentShader;
        for ( var name in hooks ) {
           vertexShader = vertexShader.replace( '%' + name + '%', hooks[ name ] );
           fragmentShader = fragmentShader.replace( '%' + name + '%', hooks[ name ] );
        }
        shader.vertexShader = vertexShader;
        shader.fragmentShader = fragmentShader;
    };

    return material;

};

¿Elegir el lugar para los ganchos y documentarlos podría no ser tan trivial? ¿Quizás reemplazaría hooks pasado con chunks y buscaría las inclusiones, con la adición de global_vert y global_frag por ahora? Ahora que lo escribí, parece que ni siquiera debería ser responsabilidad de tres, pero por otro lado, ¿restaría los THREE.ExtendedMaterial por % hook % s en el futuro?

No sé si conoce la extensión THREE.BAS. Utiliza marcadores de posición en los materiales originales a los que se puede acceder desde el material personalizado como matrices, como:

  var material = new BAS.PhongAnimationMaterial({
    flatShading: true,
    vertexColors: THREE.VertexColors,
    side: THREE.DoubleSide,
    uniforms: {
      uTime: {type: 'f', value: 0}
    },
    vertexFunctions: [
      // cubic_bezier defines the cubicBezier function used in the vertexPosition chunk
      BAS.ShaderChunk['cubic_bezier'],
      BAS.ShaderChunk['quaternion_rotation']
    ],
    vertexParameters: [
      'uniform float uTime;',
      'attribute vec2 aDelayDuration;',
      'attribute vec3 aStartPosition;',
      'attribute vec3 aEndPosition;',
      'attribute vec3 aControl0;',
      'attribute vec3 aControl1;',
      'attribute vec4 aAxisAngle;'
    ],
    vertexInit: [
      'float tProgress = mod((uTime + aDelayDuration.x), aDelayDuration.y) / aDelayDuration.y;',
      'vec4 tQuat = quatFromAxisAngle(aAxisAngle.xyz, aAxisAngle.w * tProgress);'
    ],
    vertexPosition: [
      'transformed = rotateVector(tQuat, transformed);',
      'transformed += cubicBezier(aStartPosition, aControl0, aControl1, aEndPosition, tProgress);'
    ]
  });

Me gusta el hecho de que se basa en convenciones simples: vertexInit y fragmentInit estarán en la parte superior de la función main (), por ejemplo. vertexParameters y fragmentParameters están en la parte superior del sombreador, para definir uniformes o atributos. vertexFunctions y fragmentFunctions están antes de la función main (). Y así sucesivamente para normales, posición, etc.

Como puede ver en la posición, cambia la variable transformed para cambiar la posición final. Algo similar para normales ( objectNormal ) o colores ( diffuseColor ) en el sombreador de fragmentos, por ejemplo.

Así es como se ve el material de Phong, solo agrega los marcadores de posición: https://github.com/zadvorsky/three.bas/blob/master/src/materials/PhongAnimationMaterial.js

Hola chicos, estaba tratando de seguir la conversación, pero honestamente estoy perdido ya que vengo de Front end y no de desarrollador de juegos.

Estoy tratando de cargar un MTL y obtengo:

material.onBeforeCompile.toString () no está definido.

Mi archivo MTL apuntaba originalmente a un archivo .psd y lo cambié a uno de los pocos png que contienen la misma carpeta (Normal) Supongo que no es posible cargar el psd, pero de todos modos incluso con psd está fallando.

# Blender MTL File: 'goblin.blend'
# Material Count: 1

newmtl Material
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.001617 0.005682 0.002517
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd Normal.png

La salida de la consola es:

THREE.WebGLRenderer 87
bundle.js:54570 OBJLoader: 29.447998046875ms
bundle.js:28429 Uncaught TypeError: Cannot read property 'toString' of undefined
    at WebGLPrograms.getProgramCode (bundle.js:28429)
    at initMaterial (bundle.js:32350)
    at setProgram (bundle.js:32542)
    at WebGLRenderer.renderBufferDirect (bundle.js:31605)
    at renderObject (bundle.js:32335)
    at renderObjects (bundle.js:32308)
    at WebGLRenderer.render (bundle.js:32072)
    at bundle.js:9658
    at bundle.js:53976
    at XMLHttpRequest.<anonymous> (bundle.js:40153)

y el código que estoy usando es principalmente:

OBJLoader(THREE);

const modelLoader = new THREE.OBJLoader();
const textureLoader = new MTLLoader();
textureLoader.setTexturePath( 'models/' );
    textureLoader.load('models/goblin.mtl', function( materials ) {

            materials.preload();

            modelLoader.setMaterials( materials );
            modelLoader.load('models/goblin.obj', function ( obj ) {
                 scene.add( obj );
                renderer.render( scene, camera );


            });

        }); 


    renderer.render( scene, camera );

}

¿Es esto un problema en el modelo? ¿en tres? en el cargador mtl? tiene solución?

Cualquier ayuda sería apreciada.
Gracias.

¿Tenemos que hacer algo como material.shader = shader en material.onBeforeCompile(shader=>...) ?

Creo que se siente algo torpe, podría valer la pena revisar la otra sugerencia en algún momento :)

Está siendo causado por esto, pero ¿qué está causando que Material no tenga esta función?
https://github.com/mrdoob/three.js/blob/35a26f178c523514673d992da1aece23c1cfca6e/src/renderers/webgl/WebGLPrograms.js#L244

@mrdoob

¿Es posible que estos sombreadores extendidos no se estén almacenando en caché correctamente? Estoy tratando de usar dos materiales diferentes, uno tiene dithering_fragment cambiado, el otro no. Cuando agrego ambos a la escena, aparece como solo el que no tiene el fragmento dithering_fragment se está utilizando.

No he podido recrearlo con este violín
https://codepen.io/anon/pen/KQPBjd

Pero con este código en mi ejemplo

const dithering_fragment = 
`
gl_FragColor.xyz *= foobar
`
// in onBeforeCompile
console.log(shader.fragmentShader)



md5-0f1a3ac67268b230968df20abdbd03d1



/**
#if defined( DITHERING )
  gl_FragColor.rgb = dithering( gl_FragColor.rgb );
#endif

gl_FragColor.xyz *= foobar

}
*/

Pero no se produce un error si agrego otro material a la escena que comparte otras inclusiones y definiciones.

Es por esto:

https://github.com/mrdoob/three.js/blob/35a26f178c523514673d992da1aece23c1cfca6e/src/renderers/webgl/WebGLPrograms.js#L244

Tengo la misma función con algo de lógica proporcionada a ambos materiales, las variables de la lógica están fuera del alcance de la devolución de llamada, por lo que ambos materiales obtienen el mismo hash.

array.push( material.onBeforeCompile( obtainShaderSomehow ) )

https://github.com/mrdoob/three.js/pull/10791 lo resolvió así:

https://github.com/pailhead/three.js/blob/879d52349bd5ef72c64fc962d8ca26bacaf489bf/src/renderers/webgl/WebGLPrograms.js#L242

¿Reconsideraría la otra solicitud de extracción si elimino los marcadores global_fragment posición / ganchos global_vertex y global_fragment ? Con aquellos a los que tocaba muchos archivos, sin ellos, es menos código. No son tres líneas, pero tiene el hash correcto :)

Comenta #41 en este violín https://codepen.io/anon/pen/KQPBjd
y el material de la otra malla en escena cambiará.

¿Se ha incluido esto en una versión reciente o todavía está todo en desarrollo?

@mrdoob Creo que es difícil (o imposible) serializar Materiales pirateados con .onBeforeCompile() . ¿Crees que los usuarios deberían usar ShaderMaterial si quieren materiales incorporados modificados completamente funcionales (renderizar, copiar, clonar, serializar, etc.)?

_Por favor, lea lo siguiente de la manera más amable, constructiva y sin confrontaciones posible_ :)

@takahirox, ¿

Creo que es difícil (o imposible) serializar Materiales pirateados

Cuando "piratea" materiales con onBeforeCompile , simplemente agregas uniformes que son los mismos que con cualquier otro material. No hay diferencia. Si puede serializar material.color ¿por qué no puede serializar material.userData.myColor ?

No estoy tratando de iniciar una pelea, paredes de texto ni nada. En los términos más simples y cortos posibles, ¿podría explicarme, o al menos indicarme la dirección correcta, por qué es imposible o difícil? Estoy abierto a la posibilidad de que me esté perdiendo algo obvio, pero si lo estoy, me gustaría entender qué es :)

A partir de una muestra muy pequeña, generada por artículos , en este experimento no parece que la gente quiera usar el enfoque ShaderMaterial .


¿Esto acaba de venir a la mente? ¿Existe algún tipo de prueba que demuestre que esto es difícil o imposible? Igual que:

runSerializationTest( someMaterialWithOnBeforeCompile ).expect( something )

Como el método onBeforeCompile podría contener un código muy arbitrario, es ciertamente imposible serializar de manera robusta esa devolución de llamada. Por ejemplo, el método podría hacer un XMLHttpRequest sincrónico y hacer algo con el resultado. 😅

Sin embargo ... por la forma en que se usa prácticamente (para parchear los sombreadores), estoy de acuerdo en que no es imposible. Pero las API fáciles (por ejemplo, fn.toString() ) son piratas y las API robustas son más complejas.

Sigo sin entender el problema. ¿Qué tal este punto de vista?

Tome rN que tenía MeshPhongMaterial y no tenía MeshStandardMaterial .

Puede serializar MeshPhongMaterial ie. escribe un JSON como este:

{
  color: 'red',
  specular: 'very',
  glossy: 'not much'
}

Tome rN + 1 que tiene ambos materiales:

Aún puede serializar ambos de la misma manera:

//phong
{
  color: 'red',
  specular: 'very',
  glossy: 'not much'
}

//standard
{
  color:'red',
  shininess: 'shiny',
  metalness: 'not much'
}

En ninguna parte serializó el GLSL desde MeshStandardMaterial .

De la misma forma, serializando cualquier material extendido .

//extended PhongMaterial
{
   color: 'red',
   specular: 'very',
   glossy: 'not much',
   hamburger: 'medium rare'
}

Deserializando:

if ( data.userData.hamburger && HamburgerPhongMaterial )
   mat = new HamburgerPhongMaterial( data ) 
else{ 
   console.warn(`I'm terribly sorry, but you don't have the HamburgerPhongMaterial extension, using default fallback`)
   mat = new PhongMaterial( data ) 
}

que me estoy perdiendo aqui?


Como onBeforeCompile ... serialice esa devolución de llamada.

¿Por qué, por qué lo considerarías? Creo que este es el quid de mi confusión, ¿por qué se le da alguna idea a este gancho? No es parte de la definición material, descripción, nada. Tiene algo que ver con el motor, los complementos, las aplicaciones, etc., no con los datos.

El ejemplo que dio anteriormente me parece bien, solo requiere que el código de usuario que deserializa el material sepa sobre la existencia de HamburgerPhongMaterial. No tengo ningún problema con eso, ni siquiera requiere necesariamente cambios en la API si adopta un enfoque similar al # 14099 y anula toJSON y fromJSON.

¿Quizás hemos interpretado la pregunta de @takahirox de manera diferente aquí?

... es difícil (o imposible) serializar Materiales pirateados con .onBeforeCompile (). ¿Crees que los usuarios deberían usar ShaderMaterial si quieren materiales incorporados modificados completamente funcionales (renderizar, copiar, clonar, serializar, etc.)?

Intentaré dividir eso en pedazos:

  • si el usuario llama a toJSON () en un MeshStandardMaterial simple, donde el GLSL que ha sido modificado por su onBeforeCompile , los cambios al GLSL no se serializarán automáticamente.
  • si el usuario serializa un MeshStandardMaterial con algunas propiedades adicionales que indican un cambio en el GLSL, y lo carga con un código personalizado que sabe qué hacer con esas propiedades adicionales, entonces ciertamente está bien.
  • varias otras opciones (ShaderMaterial, NodeMaterial, glTF's KHR_techniques_webgl , ...) están disponibles para serializar materiales personalizados arbitrarios.

Si el caso del que estamos hablando no es uno de esos, supongo que lo estoy entendiendo mal. Si se trata de # 14099, (todavía) estoy a favor de fusionarlo.

Hmmm, en realidad no estaba distinguiendo entre los dos primeros. Estoy tratando de pensar en algo que no requiera uniformes, podría ser un gl_FragColor.xyz /= gl_FragColor.a; por ejemplo. Pero no puedo imaginar un escenario en el que quieras serializar algo como esto (¿ junto con el material? ). Parece que entraría en el alcance de algún renderizador de efectos o algo así, no de datos materiales.

materials = loadSerializedMaterials()

effect = new Effect()

effect.load( 'alphaDivide').then(()=>materials.forEach(mat.onBeforeCompile = effect.getOnBeforeCompile('alphaDivide')))

El segundo ejemplo es lo que tenía en mente desde el principio. Junto con varias entradas, serialice una pista sobre qué hacer con ellas userData.extension === 'hamburger' .

Creo que escribí mal. Lo que quería mencionar es

  • El material incorporado pirateado con .onBeforeCompile() no se copia, clona ni serializa correctamente en la misma API que los materiales incorporados '. Se maneja como material no pirateado.
  • Si los usuarios quieren el resultado correcto, necesitan un trabajo adicional en el lado del usuario.
  • Si los usuarios quieren el material incorporado pirateado con la API central de Three.js sin ningún trabajo adicional del lado del usuario, deberían pensar en otras opciones, como ShaderMaterial .

Mi pregunta es solo para la política de .onBeforeCompile() lugar de para el caso específico. Quería aclarar la limitación y agregar una nota en el documento.

Si me olvido de three.js y de todo el sistema de renderizado, creo que veo el punto. Como objeto genérico, si tiene .clone() , desea poder clonar y tener expectativas consistentes. El problema es que ambas soluciones (clonar esto, no clonarlo) parecen tener un argumento válido. No clona a los oyentes, pero también espera algo que influye en el dibujo para que sea consistente.

Sigo pensando que mi propuesta anterior es una forma válida de hacer esto, ya que he encontrado el mismo problema en otras áreas (como compartir búferes de profundidad entre objetivos también se puede resolver con ownThing || outsideThing .

En lugar de almacenar en caché la función, que no funciona, básicamente almacenaría en caché userData pero un subconjunto de ella. No tiene sentido almacenar en caché userData.hamburger: 'rare' pero sí userData.effectOn: true". The ownInput | ownChunks | ownWhatever` resolvería este problema.

También resuelve el problema de:

Como el método onBeforeCompile podría contener un código muy arbitrario, ciertamente es imposible serializar de manera robusta esa devolución de llamada.

Ha pasado mucho tiempo, la gente ha usado onBeforeCompile ya deberíamos saber qué tipo de código arbitrario se puede encontrar allí. Creo que solo opera en el objeto shader que se pasa. Mutas ese objeto, pero solo las mutaciones que tienen sentido con ShaderMaterial tendrían un efecto de todos modos. Establecer algunas cosas gl usted mismo probablemente se anularía, y eso es lo único que me viene a la mente.

Es esencialmente un paso de pre three parse , donde tiene la oportunidad de analizar el sombreador usted mismo junto con la interfaz obligatoria uniforms:{} , ya que no lo tiene disponible en Material ( defines:{} por otro lado, y ambos son hermanos en ShaderMaterial ).

No importa cómo lo haga, es decir, cualquiera que sea el código arbitrario. No devuelve nada, pero muta shader:{} y luego el renderizador lo usa.

Enfoques que sugiero:

  1. Agregue ownThing a varias clases. THREE.WebGLRenderTarget podría tener .ownStencilDepthBuffer . Aquí, como he sugerido anteriormente, sería una versión de ownGLSL:{} ownInput | ownUniforms . Elimina la necesidad de un código arbitrario para mutar el objeto shader:{} :

Dada una entrada como esta que se origina desde el interior de WebGLRenderer (superprivado):

const shader = {
  uniforms: buildFromMaterial(mat),
  vs: getVSTemplate(key),
  fs: getFSTemplate(key)
}

Nuke esto:

shader = onBeforeCompile( shader )

shader.vs //invalid GLSL
shader.uniforms //you got some extra ones that onBeforeCompile may have mutated, maybe removed some others

shader = ___parse(shader) //private step

shader.vs //valid glsl, (not a template)

compile(shader)

Utilizar esta:

function parseShader(shader){
   return {
     uniforms: shader.uniforms,
     vs: parseChunks(shader.vs)
     fs: parseChunks(shader.fs)
   }
}
//FIX FOR HASHING BUG
function parseChunk( material, chunkName ){
  return material.ownChunks[chunkName] || THREE.ShaderChunks[chunkName]
}

//do whatever you want with the templates, maybe remove an `#include <>`
shader = onBeforeParse(shader)

shader.vs //template || valid glsl

shader = parseShader(shader) //sample OWN || PRIVATE 

shader.vs //valid GLSL 

//if you want to apply a regex on the entire valid glsl, or compile node material or something else
shader = onBeforeCompile( shader )

compile(shader)
  1. Hacer que WebGLRenderer no sepa nada más que ShaderMaterial .

Donde quiera que tuvieras

const mat = new THREE.MeshBasicMaterial()
const sm = new THREE.ShaderMaterial()

Tengo

const mat = nodeMaterial.compile() //returns ShaderMaterial, with a friendly interface (same as StandardMaterial for example)

const mat = chunkMaterial.compile()

El TL: dr de las cosas de arriba es el usuario no se preocupa por el punto determinado en el tiempo cuando se produce "compilación" (análisis sintáctico). Creo que les importa más lo que sucede, y lo que sucede se puede aislar en un puñado, si no en un solo caso de uso in: shaderString, out: shaderString . Creo que vale la pena investigar y comprender la razón por la que tiene que hacerse en ese punto particular de la tubería. Parece interferir en las cosas más que ayudar.

@mrdoob Creo que es difícil (o imposible) serializar Materiales pirateados con .onBeforeCompile() . ¿Crees que los usuarios deberían usar ShaderMaterial si quieren materiales incorporados modificados completamente funcionales (renderizar, copiar, clonar, serializar, etc.)?

No esperaba (consideraba) el uso de onBeforeCompile() para ser serializado ...

Me acabo de morder duro al usar onBeforeCompile. Tengo una clase auxiliar de sombreado que me permite realizar modificaciones en los sombreadores integrados de una manera definida. Utilizo el método onBeforeCompile para hacer esto. Aparentemente, como se indicó en el primer comentario, WebGLProgram usa onBeforeCompile.toString () como hash. Pero como mi función es genérica (sustituye partes de los sombreadores de vértices y fragmentos con variables), onBeforeCompile.toString () no se ve diferente para diferentes sombreadores. Esto significó que todos mis diferentes sombreadores se almacenaron en caché como el mismo programa. Una llamada de evaluación y un uuid y ahora todas mis funciones se ven diferentes. Me tomó una eternidad darme cuenta de esto.

@donaldr Ver https://github.com/mrdoob/three.js/issues/13192. Creo que sería bueno documentar estas limitaciones.

¿Podrías compartir cómo estás usando la evaluación? Estuve pensando en eso, pero parecía demasiado sucio. Básicamente, podría agregar const fdscxnmdrek435rkjl a la parte superior del cuerpo y luego evaluar?

Esto significó que todos mis diferentes sombreadores se almacenaron en caché como el mismo programa. Una llamada de evaluación y un uuid y ahora todas mis funciones se ven diferentes. Me tomó una eternidad darme cuenta de esto.

Eso suena muy frustrante, lo siento. 😞 Si las modificaciones que necesitaba hacer parecen tener sentido en la propia biblioteca, no dude en abrir los números también.

también siéntase bienvenido a abrir ediciones.

¿Consideraría reabrir los existentes? # 13192 parece ser el mismo pero estaba cerrado: crying_cat_face: Sería muy bueno si se publicara una solución allí si se considerara una característica.

Mmm...

const _obc = shader => {...}
const obc = `
function (shader){
  const _${ hash() }
  ${ _obc.toString() }
  _obc(shader)
}
`
material.onBeforeCompile = eval(obc)

^ ¿Funcionaría esto? Nunca usé eval .

La introducción de Material.customProgramCacheKey () a través de # 17567 asegura que los desarrolladores ahora tengan la posibilidad de que los programas de sombreado no se compartan para materiales modificados a través de onBeforeCompile() con declaraciones condicionales.

Discuta otros problemas o mejoras existentes en el contexto de onBeforeCompile() en nuevos hilos (como # 13446).

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

Horray picture Horray  ·  3Comentarios

seep picture seep  ·  3Comentarios

donmccurdy picture donmccurdy  ·  3Comentarios

clawconduce picture clawconduce  ·  3Comentarios

makc picture makc  ·  3Comentarios