Three.js: El offset / repetición UV debe ser parte de los materiales en lugar de las texturas.

Creado en 10 ene. 2015  ·  73Comentarios  ·  Fuente: mrdoob/three.js

El desplazamiento y la repetición de UV (y probablemente algunas de las otras propiedades de la textura) son uniformes que se pasan de forma extraña de la textura al material, lo que genera problemas en los que tiene que clonar texturas por material (desperdiciando una tonelada de memoria) si así lo desea. -desplazamientos / repeticiones de material, o enrolle su propio sombreador personalizado. Es muy ineficiente obligar a las personas a hacer esto, el mejor de los casos es si alguien quiere colocar una textura en una superficie en función del tamaño del objeto al que se aplica, o usar una textura como una hoja de sprites para animaciones. Solo puedo ver el sistema actual como un obstáculo sin ventajas reales, ya que la probabilidad de necesitar compensaciones / repeticiones de UV compartidas en una textura "compartida" es baja y, normalmente, sería mejor compartir un material. En cualquier caso, actualizar los uniformes de la textura es extraño, ya que realmente no tiene por qué ser parte de la textura y termina siendo confuso para el usuario final. Por ejemplo, cambiar el desplazamiento / repetición cuando se aplica más de un mapa al material, ejemplo difuso + mapa normal, solo usa el desplazamiento / repetición del mapa difuso, por lo que el valor del desplazamiento / repetición de mapas normales es completamente inútil en ese contexto , cuando realmente sugiere que debería afectar el desplazamiento / repetición normal del mapa. Todo es confuso.

Estoy bastante seguro de que el cambio es necesario en la función "refreshUniformsCommon", pero probablemente haya más. También se requieren algunos cambios en el complemento de sprite. Esto probablemente rompería los proyectos de muchas personas, pero es una inconsistencia bastante grande en la API de textura / material. Podría ser una mejor idea convertirlo en una anulación que normalmente es nula para los materiales, y cuando se establece ignora los valores en las texturas, solo para que no rompa las cosas de todos.

Suggestion

Comentario más útil

este hilo es TL; DR para mí. pero acabo de descubrir este código en r68 (proyecto antiguo, sí):

        // uv repeat and offset setting priorities
        //  1. color map
        //  2. specular map
        //  3. normal map
        //  4. bump map
        //  5. alpha map

        var uvScaleMap;

        if ( material.map ) {

            uvScaleMap = material.map;

        } else if ( material.specularMap ) {

            uvScaleMap = material.specularMap;

        } else if ( material.normalMap ) {

            uvScaleMap = material.normalMap;

        } else if ( material.bumpMap ) {

            uvScaleMap = material.bumpMap;

        } else if ( material.alphaMap ) {

            uvScaleMap = material.alphaMap;

        }

        if ( uvScaleMap !== undefined ) {

            var offset = uvScaleMap.offset;
            var repeat = uvScaleMap.repeat;

            uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );

        }

Así que sí...

Si va a proponer un cambio fundamental en la biblioteca, como el que ha propuesto aquí, debe proporcionar un argumento claro y convincente para ese cambio.

Estaba tratando de establecer una repetición diferente en mapas difusos y normales y tirando de mi cabello porque no funcionó. dado que API coloca esta configuración en textura, pensé que podía hacer eso. así que sí, ¿qué tal si me guardo el pelo para un argumento convincente? este ticket todavía está abierto, 3js todavía tiene esta configuración en texturas, y solo se respeta para una de las texturas = esto, en efecto, ya es una configuración por material.

Si no va a mover esto a donde pertenece, al menos diga que no tiene ningún efecto en los documentos.

Todos 73 comentarios

Publicación relacionada: https://github.com/mrdoob/three.js/issues/3549

tienes que clonar texturas por material (desperdiciando un montón de memoria)

¿En qué sentido se desperdician toneladas de memoria?

la probabilidad de necesitar compensaciones / repeticiones de UV compartidas en una textura "compartida" es baja

¿Qué quieres decir con eso?

Si mantenemos el enfoque actual, una cosa que debe cambiarse es cuando se clona una textura, la imagen compartida solo debe pasarse a la GPU una vez.

Si tiene un objeto con una gran cantidad de fotogramas / hojas, se crean muchos objetos inútiles y, como dijo, la imagen se copia varias veces en la GPU, lo cual es un desperdicio extremo. Aún más derrochador, si tiene varios objetos que deben estar en diferentes puntos en diferentes animaciones, tendrá que crear un conjunto único de texturas por material / objeto único, por lo que rápidamente se vuelve molesto de manejar, donde un material uniforme podría manipularse mucho más fácilmente sin tener estas estructuras de datos de desplazamiento / repetición de texturas adicionales construidas alrededor de una API mal pensada solo para que funcione. Tengo una desaceleración importante en cierto caso de uso de mi aplicación en el que tengo que crear estos grupos de texturas únicos en todas partes, y siento que la única solución sería reemplazar todos los materiales de stock que uso con materiales de sombreado para solucionar este problema único. o bien bifurque mi versión THREE.js y haga las modificaciones necesarias.

En cuanto a la segunda declaración:

Quise decir que el paradigma actual solo facilita el trabajo en los casos en que desea aplicar la misma textura con el mismo desplazamiento / repetición de UV, pero ese es generalmente un caso raro, ya que parece mucho más probable que desee definir esto como otro uniformes, por material, y comparten un material en lugar de solo la textura.

La principal advertencia con el sistema actual. es que el desplazamiento / repetición solo existe realmente como un único uniforme que afecta a todas las texturas en el sombreador, sin embargo, el hecho de que esté adjunto a TRES. La textura significa que no se puede usar correctamente como uniforme y engaña a la gente haciéndoles pensar que compensa / repite se puede elegir de manera diferente para las diversas texturas que se pueden aplicar en los materiales de stock (es decir, puede definir un desplazamiento difuso y un desplazamiento de mapa normal diferentes, pero esto no es realmente posible a pesar de que se pueden establecer de forma única en las diferentes texturas). Puedo ver que podría haber sido un remanente del renderizador de lienzo, pero simplemente no tiene sentido con el sistema de material webGLrender / GLSL, que lo ha usurpado en gran medida.

mrdoob declaró que tendría que ser de la siguiente forma como una razón para no tenerlo por material,

material.map
material.mapOffset
material.mapRepeat
material.env
material.envOffset
material.envRepeat
... etc.

pero de nuevo, el desplazamiento / repetición no funciona por tipo de mapa incluso ahora, por lo que este no es realmente un argumento válido. De todos modos, desperdiciaría demasiados uniformes tenerlo por tipo de mapa (sin mencionar que generalmente solo usa un conjunto de UV, por lo que realmente no tendría múltiples compensaciones para un mapa normal / mapa de relieve / mapa difuso / mapa especular). Creo que si sopesas todas las opciones de manera razonable, realmente debería ser una propiedad del material en lugar de una propiedad de textura. Realmente no creo que el sistema actual tenga ventajas. Siento que animar materiales a través del offset UV es una razón importante para tener la propiedad, y ni siquiera puedo usarla adecuadamente para eso. Sin mencionar que si no necesitabas esos uniformes, podrían omitirse de la compilación de sombreadores, mientras que ahora están ahí mientras esté un mapa.

@QuaziKb Con el debido respeto, si va a proponer un cambio fundamental en la biblioteca, como el que ha propuesto aquí, debe proporcionar un argumento claro y convincente para ese cambio. Discutir desde el marco de referencia de su aplicación particular no va a ser suficiente.

Dicho esto, a mí también me gustaría que el desplazamiento / repetición se moviera de Texture a los materiales.

Creo que es razonable asumir que los siguientes mapas tienen los mismos valores de desplazamiento / repetición:

specularMap
normalMap
bumpMap
alphaMap
aoMap (future)
glossMap (future)
displacementMap (future)

La única excepción es


Esta es la forma en que se implementa ahora; aunque cada mapa tiene sus propios valores de desplazamiento / repetición, no se respetan.

Entonces, podríamos agregar a MeshPhongMaterial , MeshLambertMaterial , MeshBasicMaterial y SpriteMaterial , agregaríamos

mapOffset // or mapTranslate
mapRepeat // or mapScale

Quitaríamos offset y repeat de Texture .

De esta manera, implementar una hoja de sprites es sencillo. Cada objeto tiene un material y esos materiales comparten una única textura. La textura tiene una imagen. Ya no es necesario clonar la textura. En el lado de la GPU, los materiales compartirían un solo programa de sombreado.

En mi humilde opinión, esta es una API más natural.

Estoy tratando de recordar por qué se implementó la API de la forma en que estaba. Supongo que hubo una buena razón.

Lo siento, no quise sugerir que fuera particular de mi ejemplo, simplemente que la API actual conduce a una hinchazón significativa cuando se usa para animar hojas de sprites / compensaciones por objeto / material único, sin una solución real. Naturalmente, el propósito principal de tener esto como un uniforme en lugar de simplemente hornear el desplazamiento / repetición en los vértices UV del modelo es animar el desplazamiento, y estaba sugiriendo que esto no se puede hacer sin pasar por la API, haciendo que el uniforme mucho menos útil adherido a texturas que si fuera al material.

Creo que es razonable asumir que los siguientes mapas tienen los mismos valores de desplazamiento / repetición:
mapa
...
alphaMap

FWIW, este comportamiento (la implementación actual) me está causando una gran frustración en este mismo momento. Estoy intentando animar la revelación de una malla interpolando el desplazamiento alphaMap del material de la malla independientemente de su mapa difuso (que permanece fijo). Después de un poco de frustración, descubrí a través de https://github.com/mrdoob/three.js/pull/4987 y este error que esto no es posible.

@jcarpenter ¿Cuál es el "error" al que te refieres? ¿Cuál es su sugerencia de mejora?

Corrección: por "error" me refería a este problema. Una confusión debido al tiempo excesivo en una cultura Bugzilla. : p Entiendo que esto no es un error, sino el comportamiento previsto.

WRT a una mejora, según mi experiencia con las aplicaciones tradicionales de creación de contenido 3D como Cinema 4D, imagino que el usuario puede:

  • definir desplazamiento / escala / repetición para cada textura dentro de un material, independientemente de las otras texturas, _y_
  • definir el desplazamiento / escala / repetición del material principal

Alternativamente, para el caso de uso en el que estoy trabajando ("intentar animar la revelación de una malla"), sería fantástico tener una opción para wrapS y wrapT que no se ajuste en absoluto. Según el GIF adjunto de Cinema4D, que tiene una opción para deshabilitar el mosaico por completo para el mapeo UVW. Basado en pruebas bastante extensas con los métodos wrapS y wrapT existentes, nada como esto es posible. Lo que significa que mis opciones para animar la revelación de elementos en three.js parecen estar limitadas a la posición de interpolación y la opacidad de toda la malla ... A menos que me falte algo.

c4d-tile-2

Acordado. El plan es simplificar todo esto (usando una única matriz3 en el sombreador) y tener un desplazamiento / repetición (o traducción / escala) por textura.

¡Cualquiera que quiera ayudar con esto será muy apreciado!

@jcarpenter

Lamentablemente, la única forma de hacer esto en este momento es con múltiples mallas con diferentes materiales o un material de sombreado personalizado. Ambos están involucrados para un usuario que acaba de saltar al flujo de trabajo de three.js.

Existe un compromiso constante entre usabilidad, rendimiento y extensibilidad. Mi sugerencia sería reescribir la forma en que las texturas y los materiales funcionan actualmente en la api, de modo que las texturas sean estrictamente parámetros que conecte, y los valores que en realidad son uniformes en el sombreador como el modo de desplazamiento / repetición / envoltura estén vinculados específicamente al material. En algunos casos, no desea que se desperdicie un uniforme controlando los rayos UV para texturas que nunca necesitan que cambien (sería un gran desperdicio tener 4 * 5 uniformes adicionales en un material phong si solo lo necesita para la difusión), por lo que sería genial si hubiera algo de magia detrás de escena que detectara si se necesitan UV específicos y la textura se reconstruye para cumplir con esas demandas, o si algún parámetro podría pasarse opcionalmente para especificar el número de UV ajustables requeridos y qué mapas que compensan y cómo, pero es un problema difícil de resolver.

El plan es simplificar todo esto (usando una única matriz3 en el sombreador) y tener un desplazamiento / repetición (o traducción / escala) por textura.

@mrdoob

  1. ¿Te refieres a _per material.map_ entonces la transformación de textura está en el material? Desafortunadamente, hay muchos mapas de materiales. Podríamos seguir asumiendo que todas las transformaciones de textura son iguales, excepto el mapa de luz.
  2. ¿Quieres apoyar la rotación también? Si es así, también debe agregar el centro de rotación, a menos que desee conectar el centro de rotación al centro de la textura.

Este sería un cambio muy apreciado. Tener que clonar texturas solo para ponerlas en valores de repetición únicos se siente terriblemente engorroso. ¿Es así como lo hacen otras bibliotecas?

  1. ¿Te refieres a _per material.map_ entonces la transformación de textura está en el material? Desafortunadamente, hay muchos mapas de materiales. Podríamos seguir asumiendo que todas las transformaciones de textura son iguales, excepto el mapa de luz.

Creo que deberíamos tener un mat3 por mapa y debería estar compuesto por las propiedades Texture .

  1. ¿Quieres apoyar la rotación también? Si es así, también debe agregar el centro de rotación, a menos que desee conectar el centro de rotación al centro de la textura.

Rotación sí. Centro o no ... No estoy seguro, pero hasta donde tengo entendido, todo esto se puede codificar en un solo mat3 para el sombreador (por mapa).

Aquí hay un prototipo que muestra cómo un Matrix3 puede pasarse a un sombreador y representar una transformación definida por offsetX , offsetY , repeatX , repeatY , rotation , rotationCenterX y rotationCenterY .

Si center no está permitido como opción, entonces debería estar cableado a ( 0.5, 0.5 ) .

Comentarios bienvenidos.

EDITAR: demostración actualizada

rotateuvs

¡ESTO ES GENIAL! : +1:: +1:

Creo que iría con translation y scale (en lugar de offset y repeat ).

¿Cuáles deberían ser exactamente las nuevas propiedades del material? Hay muchos mapas de materiales.

¿Qué se debe eliminar de las propiedades de la textura?

Supongo que wrapS/T debería permanecer en la textura.

Creo que texture.offset y texture.repeat deberían eliminarse.

Creo que las nuevas propiedades deberían ser ... texture.translation , texture.rotation , texture.scale , texture.center y texture.matrix . Probablemente también necesitemos un método texture.updateMatrix() que se llamaría en el momento del render. Esto, por supuesto, tiene el desafío de asegurarnos de que solo lo hagamos una vez, incluso si la textura se reutiliza.

Refiriéndome al título de esta publicación y a los argumentos en https://github.com/mrdoob/three.js/issues/5876#issuecomment -69483293, pensé que el punto era mover estas propiedades al material.

/ ping @bhouston para comentarios.

Mi pensamiento es que el desplazamiento / repetición de la textura debe hornearse en los rayos UV tanto como sea posible. Es más fácil. Así es como UE4 / Unity 5 lo hace en su mayor parte.

Sin embargo, la excepción es que Unity 5 tiene la capacidad de especificar un desplazamiento / repetición global por material que se comparte en todas las texturas, pero no afecta lo que se considera mapas horneados, como los mapas lightMap o ambientOcclusion (aquellos no tiene sentido ser ajustado.)

La razón por la que no defiendo mucha flexibilidad aquí es que los modelos creados profesionalmente tienen UV adecuados que hacen que esto generalmente no sea necesario: las herramientas de creación de contenido tienen formas de hornear esto. El otro problema es que WebGL tiene un límite inferior ridículamente bajo para los uniformes de fragmentos: 16 Vec4. Si tiene que tener una repetición / desplazamiento por mapa, y pronto obtendremos muchos mapas, estamos desperdiciando Uniformes de fragmentos por muy poco valor.

De hecho, recientemente agregué controles de repetición / compensación y luego de brillo / ganancia por textura en Clara.io y deshaceré estos cambios porque está llevando a desbordar los uniformes de fragmentos en dispositivos de gama baja, como todos los dispositivos iOS de Apple. Aunque tener repetición / compensación y brillo / ganancia funciona muy bien en computadoras de escritorio con NVIDIA 980, tenemos que diseñar para todos, no para las máquinas de gama alta. ;)

Tenemos que tratar a los Fragment Uniforms con respeto y solo usarlos cuando sea necesario. Creo que este no es uno de esos casos.

La excepción es que Unity 5 tiene la capacidad de especificar un desplazamiento / repetición global por material.

Esto es básicamente lo que está haciendo three.js ahora, aunque obtiene el desplazamiento / repetición del mapa difuso, y todas las demás texturas de materiales usan la configuración de ese mapa.

La propuesta es eliminar el desplazamiento / repetición de la textura y agregarlo al material, tal vez con un cambio de nombre. Nuevamente, todas las texturas del material compartirían la misma configuración (aunque algunos usuarios no estarían contentos con eso). Esto mantendría bajo el uso uniforme.

Desafortunadamente, no estamos obteniendo mucho consenso al respecto.

Hacer lo que hace Unity 5 es una buena idea. También lo pondría sobre el material en lugar de la textura. Tienes mi apoyo.

Por mapa no es realmente ideal, pero podría resolverse especificándolo con banderas / claves de alguna manera cuando se construyen los materiales, en caso de que sea necesario.

Generalmente, la única razón para modificar los UV en el sombreador es porque los quiere animados. Si solo desea transformar los UV de forma estática, no deberíamos modificar el sombreador para agregar esta funcionalidad.

El único cambio propuesto para el sombreador es reemplazar

vUv = uv * offsetRepeat.zw + offsetRepeat.xy;

con

vUv = ( uvTransform * vec3( uv, 1 ) ).xy;

Está bien. ¿Qué tal esto ... Agregamos texture.dynamic ( false por defecto) que produce:

vUV = uv;

Si el usuario establece texture.dynamic en true entonces calculamos texture.matrix de texture.translation , texture.rotation , texture.scale y texture.center , lo pasamos al programa y producimos:

vUv = ( uvTransform * vec3( uv, 1 ) ).xy;

Por supuesto, si texture.dynamic cambia, necesitamos recompilar el programa.

¿De esa manera obtenemos lo mejor de ambos mundos?

@mrdoob

  1. En su opinión, ¿es scale una propiedad de la textura o es texture.scale una propiedad del material? Espero que sea lo último, porque de eso se trata este hilo.
  2. No necesitamos una propiedad .matrix . El nuevo Matrix3 es un uniforme que reemplaza al uniforme de material offsetRepeat . Se calcula a partir de los otros parámetros del renderizador y se pasa a la GPU como cualquier otro uniforme.
  1. En su opinión, ¿es scale una propiedad de la textura o es texture.scale una propiedad del material? Espero que sea lo último, porque de eso se trata este hilo.

No estoy de acuerdo con este hilo. No creo que debamos contaminar los materiales con mapMatrix , envMapMatrix , ... ni mapTranslation , mapRotation , mapScale . Creo que es más limpio si THREE.Texture tiene translation , rotation , scale y, tal vez center .

  1. No necesitamos una propiedad .matrix . El nuevo Matrix3 es un uniforme que reemplaza al uniforme de material offsetRepeat . Se calcula a partir de los otros parámetros del renderizador y se pasa a la GPU como cualquier otro uniforme.

Necesitamos algo así. Digamos que se reutiliza la misma textura en diferentes mapas. No queremos calcular los Matrix3 para cada instancia.

No estoy de acuerdo con este hilo. No creo que debamos contaminar los materiales con mapMatrix, envMapMatrix, ... ni mapTranslation, mapRotation, mapScale. Creo que es más limpio si TRES. La textura tiene traslación, rotación, escala y, tal vez, centro.

¿Se necesitaría clonar una textura para tener diferentes propiedades de repetición? En escenas pequeñas, esto probablemente no sea gran cosa, pero en las grandes, donde ya hay más de 40 texturas, esto es una pesadilla de memoria.

@titansoftime image debe estar desacoplado de THREE.Texture . Idealmente, un solo THREE.Image podría ser utilizado por diferentes THREE.Texture cada uno con diferentes configuraciones translation , rotation , ....

La imagen de

Eso tiene sentido. ¿Texture.clone () ya funciona de esta manera, o tiene que configurarse manualmente?

texture.clone() funciona de esa manera, pero WebGLRenderer no puede saber que la imagen es la misma, por lo que la carga de textura es innecesaria ...

No estoy de acuerdo con este hilo. No creo que debamos contaminar los materiales con mapMatrix, envMapMatrix, ... ni mapTranslation, mapRotation, mapScale. Creo que es más limpio si TRES. La textura tiene traslación, rotación, escala y, tal vez, centro.

Esto es básicamente lo que hacemos ahora. Cada textura tiene su propia propiedad offset , y las compensaciones individuales no se respetan; el renderizador usa la misma compensación para cada mapa del material.

FWIW, creo que deberíamos hacer lo que dije en https://github.com/mrdoob/three.js/issues/5876#issuecomment -69483293.

No veo por qué la API no puede permitir hacer lo que @jcarpenter quiere hacer (animar el desplazamiento de alphaMap , mientras que map permanece igual). Se podría hacer eso en lienzo, pero creo que es una tarea de la GPU.

Hay un montón de cosas que uno podría hacer jugando con compensaciones de diferentes mapas ... compensando el alphaMap solamente, escalando el normalMap , etc.

Tener solo un uvTransform por material parece muy, muy limitante.

Oh espera. Creo que entiendo por qué ustedes prefieren por material. De esa manera, se calcula un solo vUv en el sombreador de vértices, en lugar de calcular el uv por píxel en el sombreador de fragmentos. ¿Derecha?

por material es ideal porque las compensaciones en realidad solo se implementan usando un uniforme del material y no tienen nada que ver con la textura, por lo que terminamos con una solución alternativa sin sentido si necesitamos cambiar el uniforme por material que se tiene que hacer toneladas de nuevos objetos / texturas (lo cual es bastante malo en JS / terrible en WebGL) solo para controlar algo que en realidad es solo una característica de los uniformes materiales que están ocultos a los usuarios. De ninguna manera tenerlo como parte de la textura es ventajoso, más eficiente o incluso más claro, y significa que la única aplicación real de especificar UV que cambian en tiempo de ejecución, la animación, se vuelve lenta e ineficiente debido a la API.

Las texturas deben especificar una imagen y todo lo que pertenezca a esa imagen. Las compensaciones UV no tienen nada que ver con las propiedades de la imagen / imagen, y todo que ver con el material que muestra la textura, es una tontería incluso tener esta característica si no es parte del material, ya que es necesario que haya toneladas de clonación por ejemplo, y la actualización de muchas texturas simultáneamente si se quiere usar la función en muchos casos.

imagina que uno tiene una imagen diferente para cada fotograma de un mosaico animado, y también quiere controlar el desplazamiento / repetición de ese mosaico. Tendrían que actualizar cada fotograma entrante con las compensaciones, así como tener copias de cada fotograma para cada instancia única de material que usa ese mosaico, rápidamente se convierte en bolas de nieve en cientos de nuevos objetos y asignaciones adicionales, para algo que en realidad solo está controlando unas cuantas carrozas por material detrás de escena usando todos estos objetos sin una buena razón.

En cuanto a las transformaciones por mapa, aunque sería bueno, el costo uniforme es demasiado alto sin ninguna razón en la mayoría de los casos, excepto si tenemos una API compleja para controlar cuándo y cómo las transformaciones deben ser únicas o compartidas o dinámicas, IMO. tener ese control sería algo bueno, pero habría que pensarlo cuidadosamente.

Oh espera. Creo que entiendo por qué ustedes prefieren por material. De esa manera, se calcula un solo vUv en el sombreador de vértices, en lugar de calcular el uv por píxel en el sombreador de fragmentos. ¿Derecha?

No. El uv se calcula en el sombreador de vértices como siempre.

Imagina una hoja de sprites y 20 sprites. Actualmente, necesitamos 20 materiales clonados y 20 texturas clonadas, como en http://threejs.org/examples/misc_ubiquity_test2.html. (Por cierto, tenga en cuenta que ya tenemos SpriteMaterial.rotation .)

Moviendo el offset al material, necesitaríamos 20 materiales clonados y una textura.

De hecho, moviendo el desplazamiento al sprite, necesitaríamos 1 material y 1 textura.

Imagina una hoja de sprites y 20 sprites. Actualmente, necesitamos 20 materiales clonados y 20 texturas clonadas

Ohm, no estaba considerando este caso de uso. ¡Gracias!

Pensaré en esto ...

Yo abogo por no transformaciones UV en la textura.

Por dos razones: (1) es confuso, (2) hay más eventos para propagar y (2) es un desperdicio.

Confusión: la razón es que solo tenemos una única variable UV para los mapas principales, pero si hay una transformación UV en una de las texturas, es confuso que esta transformación UV se aplique a todos los mapas que usan el primer UV canal, ya sea que las otras texturas tengan una transformación o no. Si permitiéramos que cada mapa tenga su propia transformación UV en el material, estaría más de acuerdo con la transformación UV asociada con la textura, pero eso es difícil de hacer debido a su uso uniforme de fragmentos.

Más propagación de eventos: el otro problema que encontré en Clara.io es la propagación de eventos al intentar animar los parámetros de textura. Uno necesita cada textura para realizar un seguimiento de cada material que la está usando, y luego decirle a esos materiales que están sucios y necesitan ser recalculados. No es imposible hacer esto, solo más trabajo.

Desperdicio: el otro problema es que si tiene varias instancias de un modelo 3D o despecho y todas tienen la misma textura animada. En ese caso, tendría que tener copias distintas de la textura en la memoria solo para que se animen de manera diferente, aunque los datos de textura en sí sean los mismos. En ese sentido, es un poco derrochador en comparación con poner los datos de transformación UV en los materiales.

Por lo tanto, si solo tuviéramos una Transformación UV permitida por material, la pondría en el material en sí. Seguiría el modelo Unity 5 donde tienen un desplazamiento UV, rotación en el material. Los desarrolladores de juegos ya están familiarizados con este enfoque.

Creo que los sprites también se manejan bien con UV Transform en los materiales; es muy similar al caso del modelo 3D anterior.

Having only one uvTransform per material seems very very limiting.

Totalmente de acuerdo aquí. No tener esta funcionalidad es extremadamente limitante. Hay efectos fantásticos que podrían proporcionarse aquí que simplemente no lo son porque cada desplazamiento está bloqueado.

Pero, ¿cómo puede estar disponible esta funcionalidad sin atragantarse con los clones?

Creo que tener los valores en el Material en lugar de la textura tiene sentido para el caso de uso común en el que todas sus texturas coincidirían.

Totalmente de acuerdo aquí. No tener esta funcionalidad es extremadamente limitante. Hay efectos fantásticos que podrían proporcionarse aquí que simplemente no lo son porque cada desplazamiento está bloqueado.

Pero, ¿cómo puede estar disponible esta funcionalidad sin atragantarse con los clones?

THREE.ShaderMaterial o THREE.RawShaderMaterial le darían esta habilidad, y dado que no funciona actualmente con materiales regulares, esta es la ruta que tendría que usar de todos modos.

Si está haciendo algo más funky, probablemente será más funky que simplemente ajustar las repeticiones y compensaciones de mapas de forma independiente, por lo que probablemente se inclinará de esta manera de todos modos.

+1 por esto, chicos.

Sería muy útil cuando tienes una hoja de sprites gigante (también conocida como atlas) y quieres reutilizar su textura en múltiples instancias THREE.Sprite .

¿Alguna noticia sobre esto? Este problema sigue siendo un defecto bastante evidente en la API. La mayoría de los tipos de mapas tienen compensaciones / repeticiones que no se utilizan, y la propagación de eventos hace que algo como un sprite animado en un plano sea mucho más lento / pesado de memoria de lo necesario.

La flexibilidad para mapas animados NO EXISTE en el sistema actual. Sigue surgiendo el argumento de que estaríamos reduciendo la flexibilidad al vincular la configuración al material. Este argumento es discutible porque esta flexibilidad no existe en el sistema actual. Solo puede establecer el desplazamiento / repetición globalmente para el material, y se toma del mapa difuso (?). Esto conduce a un problema aún peor en el que hay configuraciones redundantes de "compensación" / "repetición" en la mayoría de los mapas en uso, y siempre que desee compartir texturas para la animación que no puede, debe hacer un clon, por lo que la flexibilidad es significativamente reducido. Espera que cada textura / mapa tenga compensaciones únicas, pero esto no es posible tal como están las cosas, y en la mayoría de los casos realmente desea un conjunto de compensaciones UV porque sería molesto establecer las compensaciones en lo mismo para normal / spec / difuso (un mapa normal de desplazamiento sobre un mapa difuso fijo es un uso de nicho donde se podría usar un material de sombreado).

Si observa los sombreadores reales que se están construyendo, el desplazamiento / repetición de la textura está vinculado al material, pero extrañamente copiado de un mapa que de ninguna manera debería tener el control. El material NECESITA tener el control para que sea rápido y elegante sin redundancia.

Lo mejor de ambos mundos es posible con toneladas de banderas adicionales, pero no creo que esta sea una mejor solución que simplemente indicar a los usuarios que intenten usar el material de sombreado en su lugar para este tipo de casos de borde específicos.

La solución a esto es NodeMaterial de @sunag por cierto.

¡También agrego mi +1 para esto! Haría mucho más agradable trabajar con hojas de sprites.

: +1: Encontré esto sorprendente. Tuve que comenzar a duplicar mis texturas para cada sprite en el juego, ya que todos mis sprites repetidos se animaban entre sí. ¿Parece que esto significa que estoy cargando datos de sprites redundantes en la GPU?

¿Alguien tiene una solución para este problema? ¿Podría ser posible manipular el desplazamiento UV configurando directamente el uniforme en el sombreador, sin pasar por la interfaz de textura?

La solución a esto es NodeMaterial de @sunag por cierto.

@bhouston , ¿podría proporcionar un enlace? No hay un repositorio público en la cuenta de @sunag con ese nombre.

@ rhys-vdw Se encuentra aquí solo en la rama de desarrollo:

https://github.com/mrdoob/three.js/tree/dev/examples/js/nodes

Es nuevo, así que no estoy seguro de si está listo para usar en sprites, pero es un sistema de sombreado completamente basado en gráficos, por lo que te dará la flexibilidad de modificar los accesos a las texturas de forma arbitraria.

Es nuevo, así que no estoy seguro de si está listo para usar en sprites, pero es un sistema de sombreado completamente basado en gráficos, por lo que te dará la flexibilidad de modificar los accesos a las texturas de forma arbitraria.

@bhouston Puedo crear un ejemplo con Node, esto se ve bien.

Acerca de THREE.SpriteMaterial , puede acceder a la compensación / escala para crear spritesheet con esto, por ejemplo:

var offsetX = frameX / mapWidth;
var scaleX = mapWidth / frameWidth;

sprite.material.map.offset.x = offsetX;
sprite.material.map.repeat.x = scaleX;

https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/plugins/SpritePlugin.js#L53

El sistema basado en nodos no es una solución ... Todavía no aborda los problemas con la API. Se necesitan 2 segundos para agregar desplazamiento / repetición al prototipo de material y hacer que el renderizador lea eso en lugar de la textura. Ya lo he hecho para mi proyecto, pero el hecho es que es una falla obvia en la API que debería cambiarse oficialmente para evitar dolores de cabeza a los nuevos usuarios que se encontrarán con este problema si están tratando de hacer algo común.

... por lo que le dará la flexibilidad de modificar los accesos a las texturas de forma arbitraria.

tbh no sé lo que eso significa. Para animar uniformes de sombreadores de conjuntos individuales para "compensar" y "repetir" por material.

Acerca de THREE.SpriteMaterial, puede acceder a offset / scale para crear la hoja de sprites con esto, por ejemplo ...

@sunag , quizás el tema no esté claro. El código que ha compartido muta la textura, que es compartida por todas las instancias de ese material. Esto significa que es imposible tener dos materiales compartiendo una textura, pero con compensaciones únicas, por ejemplo, dos sprites enemigos que muestran diferentes cuadros de animación.

Ya lo he hecho para mi proyecto, pero el hecho es que es una falla obvia en la API que debería cambiarse oficialmente para evitar dolores de cabeza a los nuevos usuarios que se encontrarán con este problema si están tratando de hacer algo común.

@QuaziKb ¿Hay un PR al que pueda apuntar para mi proyecto?

Aunque todo esto no sería un problema si, como dijo @WestLangley , lo siguiente fuera cierto:

Si mantenemos el enfoque actual, una cosa que debe cambiarse es cuando se clona una textura, la imagen compartida solo debe pasarse a la GPU una vez.

¿Es eso correcto?

@sunag , quizás el tema no esté claro. El código que ha compartido muta la textura, que es compartida por todas las instancias de ese material. Esto significa que es imposible tener dos materiales compartiendo una textura, pero con compensaciones únicas, por ejemplo, dos sprites enemigos que muestran diferentes cuadros de animación.

Hmm, para esto NodeMaterial ciertamente resolvería, podrás compartir la misma textura con diferentes materiales y compensación UV independiente y ventajas como filtros personalizados y otras cosas que un material basado en nodos puede ofrecer.

https://github.com/mrdoob/three.js/issues/7522

Pero en el momento en que alguien intentó instanciar el uuid así :?

THREE.Texture.prototype.createInstance = function() {

    var inst = this.clone();

    inst.uuid = this.uuid;
    inst.version = this.version;

    return inst;

}

si usa needsUpdate actualice todas las instancias version también.

Ejemplo:

var uniqueTextureOffset = map.createInstance();
var material = new THREE.SpriteMaterial( { map: uniqueTextureOffset } );

Mantenga el mismo uuid y version compartirán el texture en la GPU.

https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L2832
https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLProperties.js#L11

Aunque para mí es una solución provisional. Creo en NodeMaterial para el futuro.

¿Podemos mover las transformaciones ultravioleta a material?

¿Qué tal lo mejor de ambos mundos? Agregue una bandera overrideOffsetRepeat en el material con un nuevo uvOffset y uvRepeat en el material. De esta manera, si la bandera es falsa, es compatible con versiones anteriores, y ese es el valor predeterminado. Y si es cierto, usa el material offset / repeat. Yo apoyaría esto, ya que parece que la necesidad es intensa y generalizada. @WestLangley? @mrdoob?

(Aunque realmente apoyo el uso de NodeMaterial para todo lo que está en el futuro, pero es una molestia cambiar a él).

Sigo pensando que la solución para esto es crear THREE.Image . https://github.com/mrdoob/three.js/issues/5876#issuecomment -81189892

THREE.Image

@mrdoob , ¿significaría eso que cada Texture asignado se clonaría junto con un Material ?

@mrdoob escribió:

Sigo pensando que la solución para esto es crear TRES.

Sí, eso funcionaría, sin embargo, sería un poco menos compatible con versiones anteriores (si ahora requerimos que todos creen imágenes antes de crear texturas), pero un diseño general más limpio. Tal vez sea posible crear una imagen automáticamente por textura si uno no lo especifica por separado, ¿entonces eso lograría compatibilidad con versiones anteriores? Y solo necesitaría manipular la imagen directamente si quisiera hacer algo complicado.

Supongo que esta solución requeriría el doble de objetos nuevos para un conjunto de sprites: ¿una textura para cada sprite y un material? ¿Dónde está el otro enfoque que solo requeriría un nuevo Material por cada objeto?

Sé que Unity admite la repetición / desplazamiento por material, pero las herramientas VFX de gama alta como 3DS Max, Maya, Softimage no lo hacen; solo tienen un nodo de mapa de bits y un nodo de textura (que contiene tanto el nodo de mapa de bits como un mapeo UV). nod), que es similar al diseño de

UE4 también es similar a lo que propone @mrdoob , tienen un nodo "Textura" que es un cargador de mapa de bits, y luego tienen una serie de nodos de mapeo UV para hacer varios tipos de mapeos UV.

Las herramientas avanzadas dividen la imagen / mapa de bits de la textura y también dividen un nodo de mapeo UV separado, de esta forma:

 -> Bitmap
 -> UVMapping

No permitimos muchas opciones de mapeo UV en el material estándar principal en este momento. Pero varios tipos de UVMappings utilizados en UE4, Maya, Softimage, 3DS Max, serían qué canal usar, una transformación para aplicarle, usar las coordenadas mundiales como fuente, o si se debe hacer una proyección esférica, cúbica o plana. basado en los parámetros requeridos para esas proyecciones.

UE4 tiene una textura de sprite que permite la repetición / desplazamiento dentro del material:

https://docs.unrealengine.com/latest/INT/Engine/Paper2D/Sprites/index.html

Maya, Softimage, 3DS Max y UE4 tienen la separación de mapa de bits / imagen de textura (y de la generación UV) como sugiere @mrdoob , pero también todos usan gráficos de sombreado para lograr esto. Unity3D, que no tiene gráficos de sombreado, es la herramienta que incorpora el desplazamiento / repetición en el propio material, probablemente porque no puede separarlo correctamente en un nodo de gráfico de sombreado.

Tal vez sea posible crear una imagen automáticamente por textura si uno no lo especifica por separado, ¿entonces eso lograría compatibilidad con versiones anteriores? Y solo necesitaría manipular la imagen directamente si quisiera hacer algo complicado.

Exactamente 😊

Probablemente un poco fuera de lugar mencionarlo, pero me gustaría recomendar que se incorpore PTEX lo antes posible.
http://ptex.us/PtexFile.html
Si hay una manera de hacer proyecciones típicas, etc., emitir / convertir a una NodeTexture (?) ¿O una opción que es un nuevo sistema de mapeo de textura de nivel base más poderoso y completo? ... bueno, entonces tal vez eso sea algo a considerar antes de tiempo.
[Más allá del mismo punto:]
El concepto con ptex no es realmente una imagen 2d sino una relación ultravioleta, por lo que puede pintar / estampar / proyectar alrededor de una superficie compleja sin el concepto / desafío de cómo traducir 2d a 3d, que es matemáticamente un truco en el mejor de los casos en comparación ( siempre luchando técnicamente con la destorsión).
Solo señalo que ptex debería haber tenido más sentido y ser una prioridad hace más de 20 años y no debería ser considerado una extensión o un ejecutante de segunda clase, pero realmente para mí es al revés. Debería ser la antigua forma original de decir declarativamente cómo se proyecta / estampa una imagen 2d en el único sistema de nivel base verdadero y siempre funcional de ptex. De todos modos solo haciendo cumplir la idea debería integrarse si no lo mejor para tomar un rol más central.
Gracias por la oportunidad de hacer grandes sugerencias. Estaba tan feliz de que el ptex se hiciera con una especificación. Yo mismo lo pensé más de 10 años antes, pero cuando era niño no tenía poder para definir nuevas especificaciones, etc. En retrospectiva, debería haber visto que tal vez podría haber intentado hacer una diferencia en lugar del rol de observador que todavía mantengo. Así que aquí hay un intento de deshacer un error de larga data.

Tal vez alguien pueda comenzar un nuevo hilo si alguien con una comprensión más profunda de los métodos actuales potencialmente en Flux puede hacer una propuesta más aplicable de cómo funcionaría eso en THREEjs.
Nuevamente gracias por la oportunidad de ser escuchado.

@MasterJames es un poco fuera de tema ... ¿crear un nuevo hilo, por favor?

Incluso si tuviéramos una imagen para poder usar la "textura", todos los materiales tendrían que ser reescritos, ya que en realidad no admiten más de un desplazamiento / repetición uv. Obviamente, esto podría cambiar, pero probablemente terminaría agregando complejidad, ya que entonces se necesitarían uniformes redundantes (¿con qué frecuencia desea más de un conjunto de compensaciones / repeticiones para que, por ejemplo, un mapa normal esté compensado de uno difuso) creo que al final para la web donde el rendimiento es premium, el caso de uso más común es aquel en el que hay un desplazamiento / repetición global que afecta a cada mapa, y tiene sentido que esto esté en el material, ya que termina siendo parte de la arquitectura de materiales. Los materiales de sombreado personalizados pueden manejar los casos de borde perfectamente.

@QuaziKb Sí. Eso es lo que aborda NodeMaterial .

¿No es el caso de que Texture usa la misma instancia de textura OpenGL para cada .clone() , o me falta algo? ¿Realmente lo está recargando para cada clon? Si ese es el caso, entonces este es un problema _muy_ serio.

@evrimoztamur , creo que copia la textura cada vez. Puede comprobar qué está pasando con WebGL Inspector .

Intenté probar todos los enfoques que se me ocurrieron , incluida la solución alternativa de @sunag , pero nada funcionó. Basándome en mi experimentación que no arrojó resultados, y en la discusión anterior, eché un vistazo a cómo otras bibliotecas manejan la animación de sprites. Descubrí que la API Sprite y SpriteManager de Babylon.js es una solución que satisface mis necesidades particulares. Maneja hojas de sprites, offset y repetición, y animaciones. Tal vez este sea un nivel de abstracción más alto que el que THREE.js pretende proporcionar, pero podría valer la pena verlo como referencia.

@ rhys-vdw: Para un proyecto actual terminé con una versión bastarda de MeshBasicMaterial:
https://gist.github.com/karimbeyrouti/790d2e1a8c0137b16bae

Cuando configura el Mapa, esto asigna automáticamente los uniformes de desplazamiento / repetición (que están en material escondido). Puede configurarlos fácilmente por separado, lo que evitará que tenga que clonar texturas por ahora. (trabajando con r73)

Acabo de enviar un PR que debería abordar este problema, PR # 8278

@WestLangley escribió:

Creo que es razonable asumir que los siguientes mapas tienen los mismos valores de desplazamiento / repetición:

mapa
specularMap
normalMap
mapa de relieve
alphaMap
aoMap (futuro)
glossMap (futuro)
mapa de desplazamiento (futuro)

No siempre. Actualmente estoy usando diferentes valores de repetición para un mapa y un mapa de relieve en el mismo material (asfalto) para ocultar el hecho de que ambos están en mosaico con mosaicos bastante pequeños. De esa manera, no necesito generar / tener una gran textura. Es muy conveniente. :-)

EDITAR: Bueno, eso es al menos lo que pensé que había hecho. El truco probablemente fue ignorado. Y puedo lograr resultados similares agregando ruido en el sombreador o algo así. La demostración de Matrix3 de WestLangley es genial.

Creo que esto resuelve el problema de las instancias con diferentes UV en Sprite. Es posible modificar vertex y pixel shader conservando la misma textura.

https://threejs.org/examples/#webgl_sprites_nodes

Utiliza SpriteNodeMaterial y Mesh con un PlaneBufferGeometry compartido. La interfaz no es apropiada para Sprite pero funciona. Tal vez pueda evolucionar a SpriteMesh para hacer una interfaz más amigable

este hilo es TL; DR para mí. pero acabo de descubrir este código en r68 (proyecto antiguo, sí):

        // uv repeat and offset setting priorities
        //  1. color map
        //  2. specular map
        //  3. normal map
        //  4. bump map
        //  5. alpha map

        var uvScaleMap;

        if ( material.map ) {

            uvScaleMap = material.map;

        } else if ( material.specularMap ) {

            uvScaleMap = material.specularMap;

        } else if ( material.normalMap ) {

            uvScaleMap = material.normalMap;

        } else if ( material.bumpMap ) {

            uvScaleMap = material.bumpMap;

        } else if ( material.alphaMap ) {

            uvScaleMap = material.alphaMap;

        }

        if ( uvScaleMap !== undefined ) {

            var offset = uvScaleMap.offset;
            var repeat = uvScaleMap.repeat;

            uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );

        }

Así que sí...

Si va a proponer un cambio fundamental en la biblioteca, como el que ha propuesto aquí, debe proporcionar un argumento claro y convincente para ese cambio.

Estaba tratando de establecer una repetición diferente en mapas difusos y normales y tirando de mi cabello porque no funcionó. dado que API coloca esta configuración en textura, pensé que podía hacer eso. así que sí, ¿qué tal si me guardo el pelo para un argumento convincente? este ticket todavía está abierto, 3js todavía tiene esta configuración en texturas, y solo se respeta para una de las texturas = esto, en efecto, ya es una configuración por material.

Si no va a mover esto a donde pertenece, al menos diga que no tiene ningún efecto en los documentos.

@sunag Para relaciones públicas:
https://github.com/mrdoob/three.js/pull/11531

Un problema que encontré:
https://jsfiddle.net/f0j2v3s8/

Parece que la transparencia SpriteNodeMaterial se pierde, no hay una combinación de combinación que pueda usar para que este ejemplo funcione.

¿Algunas ideas?

@karimbeyrouti escribió:

Cuando configura el Mapa, esto asigna automáticamente los uniformes de desplazamiento / repetición (que están en material escondido). Puede configurarlos fácilmente por separado, lo que evitará que tenga que clonar texturas por ahora. (trabajando con r73)

Creo que esto es obsoleto ya que uniforms.offsetRepeat se cambia a uniforms.uvTransform (r88).

Con respecto al caso de uso de 'reutilizar un atlas de texturas con múltiples instancias de Object3D', sugiero un simple paseo:

  1. almacenar los datos de UV (desplazamiento, repetición) en un objeto atlas json;
  2. engancha el par de funciones onBeforeRender\onAfterRender de Object3D;
  3. en la devolución de llamada de renderizado anterior, cargue los datos UV del objeto atlas json y configúrelos en material.map;
  4. en la devolución de llamada posterior a la renderización, reiníciela;

Dará como resultado:

  1. solo una textura y un material compartidos por varios objetos, no se necesita ningún clon y el contador de info.memory.textures no aumentará;
  2. pero todos los demás mapas (normal, ao, desplazamiento ...) deben cumplir con la misma traducción UV;
¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

jack-jun picture jack-jun  ·  3Comentarios

Horray picture Horray  ·  3Comentarios

makc picture makc  ·  3Comentarios

fuzihaofzh picture fuzihaofzh  ·  3Comentarios

seep picture seep  ·  3Comentarios