Effect QML Type
Componente base para crear un efecto de post-procesado. Más...
| Import Statement: | import QtQuick3D |
| Inherits: |
Propiedades
- passes : list
Descripción detallada
El tipo Efecto permite al usuario implementar sus propios efectos de post-procesamiento para QtQuick3D.
Efectos de postprocesamiento
Un efecto de post-procesamiento es conceptualmente muy similar al elemento ShaderEffect de Qt Quick. Cuando un efecto está presente, la escena se renderiza primero en una textura separada. A continuación, el efecto se aplica dibujando un quad texturizado en el objetivo de renderizado principal, dependiendo de la render mode del View3D. El efecto puede proporcionar un sombreador de vértices, un sombreador de fragmentos o ambos. Los efectos se aplican siempre en toda la escena, por View3D.
Los efectos se asocian a SceneEnvironment en la propiedad SceneEnvironment::effects. La propiedad es una lista: los efectos pueden encadenarse; se aplican en el orden en que aparecen en la lista, utilizando la salida del paso anterior como entrada para el siguiente, siendo la salida del último efecto la que define el contenido de View3D.
Nota: SceneEnvironment y ExtendedSceneEnvironment proporcionan un conjunto de efectos incorporados, como profundidad de campo, brillo/floración, destello de lente, gradación de color y viñeta. Considere siempre primero si éstos son suficientes para las necesidades de la aplicación, y prefiera utilizar las facilidades incorporadas en lugar de implementar un efecto de post-procesamiento personalizado.
Los efectos son similares a custom materials en muchos aspectos. Sin embargo, un material personalizado se asocia a un modelo y es responsable del sombreado de esa malla determinada. Mientras que el sombreador de vértices de un efecto siempre recibe un quad (por ejemplo, dos triángulos) como entrada, mientras que su sombreador de fragmentos muestrea la textura con el contenido de la escena.
A diferencia de los materiales personalizados, los efectos admiten múltiples pasadas. Para muchos efectos esto no es necesario, y cuando hay una necesidad de aplicar múltiples efectos, resultados idénticos a menudo se puede lograr mediante el encadenamiento de múltiples efectos en the SceneEnvironment. Esto también se demuestra en el ejemplo Efecto personalizado. Sin embargo, los pases tienen la posibilidad de solicitar búferes de color adicionales (textura), y especificar a cuál de estos búferes adicionales dan salida. Esto permite implementar técnicas de procesado de imagen más complejas, ya que los pases posteriores pueden utilizar uno o más de estos buffers adicionales, además del contenido de la escena original, como entrada. Si es necesario, estos búferes adicionales pueden tener una vida útil más larga, lo que significa que su contenido se conserva entre fotogramas, lo que permite implementar efectos que dependen de la acumulación de contenido de varios fotogramas, como el desenfoque de movimiento.
En comparación con Qt Quick's 2D ShaderEffect, los efectos de postprocesamiento 3D tienen la ventaja de poder trabajar con datos de búfer de profundidad, así como la capacidad de implementar múltiples pasadas con búferes intermedios. Además, se amplían las capacidades relacionadas con las texturas: Qt Quick 3D permite un control más fino sobre los modos de filtrado, y permite que los efectos trabajen con formatos de textura distintos de RGBA8, por ejemplo, formatos de coma flotante.
Nota: Los efectos de posprocesamiento están disponibles actualmente cuando View3D tiene su renderMode ajustado a Offscreen, Underlay o Overlay. Los efectos no se renderizarán para el modo Inline.
Nota: Cuando se utilizan efectos de post-procesamiento, los shaders proporcionados por la aplicación deben esperar datos de color lineales sin tonemapping aplicado. El tonemapping que se realiza durante el pase de renderizado principal (o durante el renderizado de skybox, si hay un skybox) cuando tonemapMode se establece en un valor distinto de SceneEnvironment.TonemapModeNone, se desactiva automáticamente cuando hay al menos un efecto de post-procesado especificado en SceneEnvironment. El último efecto de la cadena (más concretamente, el último pase del último efecto de la cadena) obtendrá automáticamente su fragment shader modificado para realizar el mismo tonemapping que realizaría el pase de renderizado principal.
Nota: Los efectos que realizan su propio tonemapping deben ser utilizados en un SceneEnvironment que tenga el tonemapping incorporado desactivado ajustando tonemapMode a SceneEnvironment.TonemapModeNone.
Nota: Por defecto, la textura utilizada como entrada de los efectos se crea con un formato de textura de coma flotante, como RGBA de 16 bits de coma flotante. El formato de la textura de salida es el mismo ya que por defecto sigue el formato de entrada. Esto puede anularse utilizando Buffer y un nombre vacío. El valor por defecto RGBA16F es útil porque permite trabajar con datos lineales no mapeados sin tener los valores de color fuera del rango 0-1 fijados.
Exponer datos a los shaders
Al igual que con CustomMaterial o ShaderEffect, las propiedades dinámicas de un objeto Efecto pueden ser cambiadas y animadas usando las facilidades habituales de QML y Qt Quick, y los valores son expuestos a los shaders automáticamente. La siguiente lista muestra cómo se asignan las propiedades:
- bool, int, real -> bool, int, float
- QColor color -> vec4, y el color se convierte a lineal, asumiendo el espacio sRGB para el valor de color especificado en QML. Los colores incorporados en Qt, como están en espacio de color sRGB también, y la misma conversión se realiza para todas las propiedades de color de DefaultMaterial y , por lo que este comportamiento de Effect coincide con aquellos.
"green"PrincipledMaterial - QRect, QRectF, rect -> vec4
- QPoint, QPointF, point, QSize, QSizeF, size -> vec2
- QVector2D, vector2d -> vec3
- QVector3D, vector3d -> vec3
- QVector4D, vector4d -> vec4
- QMatrix4x4, matrix4x4 -> mat4
- QQuaternion, quaternion -> vec4, valor escalar es
w - TextureInput -> sampler2D o samplerCube, dependiendo de si se utiliza Texture o CubeMapTexture en la propiedad texture del TextureInput. Establecer la propiedad enabled a false lleva a exponer una textura ficticia al shader, lo que significa que los shaders siguen siendo funcionales pero muestrearán una textura con contenido de imagen negra opaca. Presta atención al hecho de que las propiedades para los muestreadores siempre deben hacer referencia a un objeto TextureInput, no a un Texture directamente. En lo que respecta a las propiedades de Texture, las relacionadas con la fuente, el mosaico y el filtrado son las únicas que se tienen en cuenta de forma implícita con los efectos, ya que el resto (como las transformaciones UV) depende de los sombreadores personalizados para que las implementen como consideren oportuno.
Nota: Cuando un uniforme referenciado en el código del shader no tiene una propiedad correspondiente, causará un error de compilación del shader al procesar el efecto en tiempo de ejecución. Hay algunas excepciones a esto, como los uniformes sampler, que obtienen una textura ficticia cuando no hay una propiedad QML correspondiente, pero como regla general, todos los uniformes y samplers deben tener una propiedad correspondiente declarada en el objeto Effect.
Introducción a los efectos definidos por el usuario
Un efecto de post-procesado personalizado implica como mínimo un objeto Effect y un fragmento de fragment shader. Algunos efectos también necesitarán un sombreador de vértices personalizado.
Como ejemplo simple, vamos a crear un efecto que combina el contenido de la escena con una imagen, mientras que además altera el valor del canal rojo de una manera animada:
Effect { id: simpleEffect property TextureInput tex: TextureInput { texture: Texture { source: "image.png" } } property real redLevel NumberAnimation on redLevel { from: 0; to: 1; duration: 5000; loops: -1 } passes: Pass { shaders: Shader { stage: Shader.Fragment shader: "effect.frag" } } } | void MAIN()
{
vec4 c = texture(tex, TEXTURE_UV);
c.r *= redLevel;
FRAGCOLOR = c * texture(INPUT, INPUT_UV);
} |
Aquí la textura con la imagen image.png está expuesta al shader bajo el nombre tex. El valor de redLevel está disponible en el shader en un uniforme float con el mismo nombre.
El fragment shader debe contener una función llamada MAIN. El color final del fragmento viene determinado por FRAGCOLOR. La textura de entrada principal, con el contenido de la escena View3D's, es accesible en un sampler2D con el nombre INPUT. Las coordenadas UV del quad están en INPUT_UV. Estos valores UV son siempre adecuados para el muestreo INPUT, independientemente de la API gráfica subyacente en tiempo de ejecución (y, por tanto, independientemente de la dirección del eje Y en las imágenes, ya que los ajustes necesarios son aplicados automáticamente por Qt Quick 3D). El muestreo de la textura con nuestra imagen externa se realiza utilizando TEXTURE_UV. INPUT_UV no es adecuado en aplicaciones multiplataforma ya que V necesita ser volteada para atender a las diferencias de sistema de coordenadas mencionadas anteriormente, utilizando una lógica que es diferente para las texturas basadas en imágenes y las texturas utilizadas como objetivos de renderizado. Afortunadamente, el motor se encarga de todo esto, por lo que el sombreador no necesita más lógica para ello.
Una vez que simpleEffect está disponible, puede ser asociado con la lista de efectos de un View3D's SceneEnvironment:
environment: SceneEnvironment {
effects: [ simpleEffect ]
}El resultado sería algo parecido a lo siguiente, con la escena original a la izquierda y con el efecto aplicado a la derecha:
|
|
Nota: El valor de la propiedad shader en Shader es una URL, al igual que la costumbre en QML y Qt Quick, que hace referencia al archivo que contiene el fragmento de shader, y funciona de forma muy similar a ShaderEffect o Image.source. Sólo se admiten los esquemas file y qrc.. También es posible omitir el esquema file, permitiendo especificar una ruta relativa de forma conveniente. Dicha ruta se resuelve de forma relativa a la ubicación del componente (el archivo .qml ).
Nota: El código de sombreado siempre se proporciona utilizando GLSL al estilo Vulkan, independientemente de la API gráfica utilizada por Qt en tiempo de ejecución.
Nota: El código de sombreado de vértices y fragmentos proporcionado por el efecto no son sombreadores GLSL completos por sí mismos. Más bien, proporcionan una función MAIN, y opcionalmente un conjunto de declaraciones VARYING, que luego son modificadas con más código shader por el motor.
Nota: El ejemplo anterior no es compatible con el modo opcional de renderizado multivista que se utiliza en algunas aplicaciones VR/AR. Para que funcione tanto con el modo multiview como sin él, cambia MAIN() así:
void MAIN()
{
vec4 c = texture(tex, TEXTURE_UV);
c.r *= redLevel;
#if QSHADER_VIEW_COUNT >= 2
FRAGCOLOR = c * texture(INPUT, vec3(INPUT_UV, VIEW_INDEX));
#else
FRAGCOLOR = c * texture(INPUT, INPUT_UV);
#endif
}Efectos con vertex shaders
Un sombreador de vértices, cuando está presente, debe proporcionar una función llamada MAIN. En la gran mayoría de los casos el sombreador de vértices personalizado no querrá proporcionar su propio cálculo de la posición del vértice homogéneo, pero es posible utilizando POSITION, VERTEX, y MODELVIEWPROJECTION_MATRIX. Cuando POSITION no está presente en el código del shader personalizado, una sentencia equivalente a POSITION = MODELVIEWPROJECTION_MATRIX * vec4(VERTEX, 1.0); será inyectada automáticamente por Qt Quick 3D.
Para pasar datos entre los sombreadores de vértices y fragmentos, utilice la palabra clave VARYING. Internamente esto se transformará en la declaración apropiada de salida de vértice o entrada de fragmento. El fragment shader puede utilizar la misma declaración, lo que permite leer el valor interpolado para el fragmento actual.
Veamos un ejemplo, que es en efecto muy similar al efecto incorporado DistortionSpiral:
VARYING vec2 center_vec;
void MAIN()
{
center_vec = INPUT_UV - vec2(0.5, 0.5);
center_vec.y *= INPUT_SIZE.y / INPUT_SIZE.x;
} | VARYING vec2 center_vec;
void MAIN()
{
float radius = 0.25;
float dist_to_center = length(center_vec) / radius;
vec2 texcoord = INPUT_UV;
if (dist_to_center <= 1.0) {
float rotation_amount = (1.0 - dist_to_center) * (1.0 - dist_to_center);
float r = radians(360.0) * rotation_amount / 4.0;
mat2 rotation = mat2(cos(r), sin(r), -sin(r), cos(r));
texcoord = vec2(0.5, 0.5) + rotation * (INPUT_UV - vec2(0.5, 0.5));
}
FRAGCOLOR = texture(INPUT, texcoord);
} |
La lista passes del objeto Effect debe especificar ahora tanto los fragmentos de vértice como los fragmentos:
passes: Pass {
shaders: [
Shader {
stage: Shader.Vertex
shader: "effect.vert"
},
Shader {
stage: Shader.Fragment
shader: "effect.frag"
}
]
}El resultado final es el siguiente:
|
|
Palabras clave especiales en shaders de efectos
VARYING- Declara una salida de vértice o una entrada de fragmento, dependiendo del tipo de shader actual.MAIN- Esta función debe estar siempre presente en un sombreador de efectos.FRAGCOLOR-vec4- El color final del fragmento; la salida del sombreador de fragmentos. (sólo sombreador de fragmentos)POSITION-vec4- La posición homogénea calculada en el sombreador de vértices. (sólo sombreador de vértices)MODELVIEWPROJECTION_MATRIX-mat4- La matriz de transformación para el cuadrado de la pantalla.VERTEX-vec3- Los vértices del quad; la entrada al sombreador de vértices. (sólo sombreador de vértices)INPUT-sampler2Dosampler2DArray- El muestreador para la textura de entrada con la escena renderizada en ella, a menos que un pase redirija su entrada a través de un objeto BufferInput, en cuyo casoINPUTse refiere a la textura del buffer de color adicional referenciada por BufferInput. Con el renderizado multivista habilitado, que puede ser relevante para aplicaciones VR/AR, este es un sampler2DArray, mientras que la textura de entrada se convierte en un array de texturas 2D.INPUT_UV-vec2- Coordenadas UV aptas para el muestreoINPUT.TEXTURE_UV-vec2- Coordenadas UV adecuadas para muestrear una Textura con contenidos cargados desde un archivo de imagen.INPUT_SIZE-vec2- El tamaño de la texturaINPUT, en píxeles.OUTPUT_SIZE-vec2- El tamaño del búfer de salida, en píxeles. A menudo es el mismo queINPUT_SIZE, a menos que el pase de salida sea un Buffer extra con un multiplicador de tamaño.FRAME-float- Un contador de fotogramas, incrementado después de cada fotograma en View3D.DEPTH_TEXTURE-sampler2Dosampler2DArray- Una textura de profundidad con el contenido del buffer de profundidad con los objetos opacos de la escena. Al igual que con CustomMaterial, la presencia de esta palabra clave en el sombreador desencadena la generación de la textura de profundidad automáticamente.NORMAL_ROUGHNESS_TEXTURE-sampler2D- Una textura con las normales del espacio-mundo y la rugosidad del material de los objetos opacos en la parte visible de la escena. Al igual que en CustomMaterial, la presencia de esta palabra clave en el sombreador implica una pasada de render adicional para generar la textura normal.VIEW_INDEX-uint- Con el renderizado multivista activado, este es el índice de vista actual, disponible tanto en los sombreadores de vértices como en los de fragmentos. Siempre es 0 cuando no se utiliza el renderizado multivista.PROJECTION_MATRIX-mat4, la matriz de proyección. Tenga en cuenta que con el renderizado multivista, se trata de una matriz de matrices.INVERSE_PROJECTION_MATRIX-mat4, la matriz de proyección inversa. Tenga en cuenta que con el renderizado multivista, se trata de una matriz de matrices.VIEW_MATRIX->mat4, la matriz de vista (cámara). Tenga en cuenta que con el renderizado multivista, se trata de una matriz de matrices.- float
NDC_Y_UP- El valor es1cuando el eje Y apunta hacia arriba en el espacio de coordenadas normalizado del dispositivo, y-1cuando el eje Y apunta hacia abajo. Y apuntando hacia abajo es el caso cuando el renderizado ocurre con Vulkan. - float
FRAMEBUFFER_Y_UP- El valor es1cuando el eje Y apunta hacia arriba en el sistema de coordenadas para framebuffers (texturas), lo que significa que(0, 0)es la esquina inferior izquierda. El valor es-1cuando el eje Y apunta hacia abajo, siendo(0, 0)la esquina superior izquierda. - float
NEAR_CLIP_VALUE- El valor es-1para cuando el rango del plano de recorte comienza en-1y llega hasta1. Esto es así cuando se utiliza OpenGL para el renderizado. Para otros backends de renderizado el valor de esta propiedad será0lo que significa que el rango del plano de recorte es de0a1.
Creación de efectos multipase
Un efecto multipase a menudo utiliza más de un conjunto de shaders, y utiliza las propiedades output y commands. Cada entrada en la lista de pases se traduce en un pase de renderizado que dibuja un cuadrado en la textura de salida del pase, mientras muestrea la textura de entrada del efecto y opcionalmente también otras texturas.
El esquema típico de un efecto multipase puede tener el siguiente aspecto:
passes: [
Pass {
shaders: [
Shader {
stage: Shader.Vertex
shader: "pass1.vert"
},
Shader {
stage: Shader.Fragment
shader: "pass1.frag"
}
// This pass outputs to the intermediate texture described
// by the Buffer object.
output: intermediateColorBuffer
],
},
Pass {
shaders: [
Shader {
stage: Shader.Vertex
shader: "pass2.vert"
},
Shader {
stage: Shader.Fragment
shader: "pass2.frag"
}
// The output of the last pass needs no redirection, it is
// the final result of the effect.
],
commands: [
// This pass reads from the intermediate texture, meaning
// INPUT in the shader will refer to the texture associated
// with the Buffer.
BufferInput {
buffer: intermediateColorBuffer
}
]
}
]¿Qué es intermediateColorBuffer?
Buffer { id: intermediateColorBuffer name: "tempBuffer" // format: Buffer.RGBA8 // textureFilterOperation: Buffer.Linear // textureCoordOperation: Buffer.ClampToEdge }
Las propiedades comentadas no son necesarias si los valores deseados coinciden con los predeterminados.
Internamente la presencia de este objeto Buffer y referenciarlo desde la propiedad output de un Pase lleva a crear una textura con un tamaño que coincide con el View3D, y por tanto con el tamaño de las texturas implícitas de entrada y salida. Cuando no se desea esto, se puede utilizar la propiedad sizeMultiplier para obtener una textura intermedia con un tamaño diferente. Esto puede llevar a que los uniformes INPUT_SIZE y OUTPUT_SIZE en el shader tengan valores diferentes.
Por defecto el Efecto no puede contar con que las texturas preserven su contenido entre fotogramas. Cuando se crea una nueva textura intermedia, se borra a vec4(0.0). Después, la misma textura puede ser reutilizada para otro propósito. Por lo tanto, los pases de efectos deberían escribir siempre en la textura completa, sin hacer suposiciones sobre su contenido al inicio del pase. Hay una excepción a esto: Los objetos Buffer con bufferFlags establecido a Buffer.SceneLifetime. Esto indica que la textura está permanentemente asociada a un pase del efecto y no será reutilizada para otros propósitos. El contenido de estos buffers de color se conserva entre fotogramas. Esto se usa típicamente de forma ping-pong en efectos como el desenfoque de movimiento: la primera pasada toma el búfer persistente como entrada, además de la textura de entrada principal del efecto, dando salida a otro búfer intermedio, mientras que la segunda pasada da salida al búfer persistente. De este modo, en el primer fotograma, el primer pase muestrea una textura vacía (transparente), mientras que en los fotogramas siguientes muestrea la salida del segundo pase del fotograma anterior. Una tercera pasada puede entonces mezclar la entrada del efecto y la salida de la segunda pasada.
El tipo de comando BufferInput se utiliza para exponer buffers de textura personalizados al pase de render.
Por ejemplo, para acceder a someBuffer en los shaders del pase de render bajo el nombre, mySampler, se puede añadir lo siguiente a su lista de comandos:
BufferInput { buffer: someBuffer; sampler: "mySampler" }
Si no se especifica el nombre sampler, se utilizará INPUT por defecto.
Los buffers pueden ser útiles para compartir resultados intermedios entre pases de render.
Para exponer texturas precargadas al efecto, debe utilizarse TextureInput en su lugar. Estas pueden ser definidas como propiedades del propio Efecto, y serán automáticamente accesibles a los shaders por sus nombres de propiedad.
property TextureInput tex: TextureInput {
texture: Texture { source: "image.png" }
}Aquí tex es un muestreador válido en todos los shaders de todas las pasadas del efecto.
Cuando se trata de valores uniformes de propiedades, todos los pases del Efecto leen los mismos valores en sus shaders. Si es necesario, es posible anular el valor de un uniforme sólo para un pase determinado. Esto se consigue añadiendo el comando SetUniformValue a la lista de comandos del pase.
Nota: El target del establecedor de valor de uniforme específico del pase sólo puede referirse a un nombre que sea el nombre de una propiedad del efecto. Puede anular el valor del uniforme correspondiente a una propiedad, pero no puede introducir nuevos uniformes.
Consideraciones sobre el rendimiento
Ten en cuenta el aumento del uso de recursos y la posible reducción del rendimiento cuando utilices efectos de postprocesado. Al igual que con las capas de Qt Quick y ShaderEffect, renderizar la escena en una textura y luego utilizarla para texturizar un quad no es una operación barata, especialmente en hardware de gama baja con una capacidad de procesamiento de fragmentos limitada. La cantidad de memoria gráfica adicional necesaria, así como el aumento de la carga de la GPU, dependen ambos del tamaño de View3D (que, en dispositivos integrados sin sistema de ventanas, puede ser a menudo tan grande como la resolución de la pantalla). Los efectos multipase, así como la aplicación de múltiples efectos, aumentan aún más los requisitos de recursos y rendimiento.
Por lo tanto, es muy aconsejable asegurarse desde el principio del ciclo de vida del desarrollo de que el dispositivo y la pila de gráficos a los que se destina el producto son capaces de hacer frente a los efectos incluidos en el diseño de la escena 3D a la resolución de pantalla del producto final.
Aunque es inevitable con las técnicas que lo necesitan, DEPTH_TEXTURE implica una pasada de renderizado adicional para generar el contenido de esa textura, lo que también puede suponer un golpe en el hardware menos capaz. Por lo tanto, utilice DEPTH_TEXTURE en los shaders del efecto sólo cuando sea esencial.
La complejidad de las operaciones en los sombreadores también es importante. Al igual que con CustomMaterial, un sombreador de fragmentos que no sea óptimo puede reducir fácilmente el rendimiento del renderizado.
Ten cuidado con sizeMultiplier in Buffer cuando se trate de valores superiores a 1. Por ejemplo, un multiplicador de 4 significa crear y luego renderizar a una textura que es 4 veces el tamaño de View3D. Al igual que con los mapas de sombras y el multimuestreo o supermuestreo, el aumento de los costes de recursos y rendimiento puede superar rápidamente los beneficios de una mejor calidad en sistemas con una potencia de GPU limitada.
Consideraciones sobre VR/AR
Cuando se desarrollan aplicaciones para realidad virtual o aumentada utilizando Qt Quick 3D XR, los efectos de postprocesamiento son funcionales y están disponibles para su uso. Sin embargo, los diseñadores y desarrolladores deben tener especial cuidado en comprender qué efectos y de qué tipo tienen sentido en un entorno de realidad virtual. Algunos efectos, incluidos algunos de los incorporados en ExtendedSceneEnvironment o el obsoleto módulo Effects, no conducen a una buena experiencia visual en un entorno de RV, pudiendo incluso afectar físicamente al usuario (provocando, por ejemplo, mareos o cinetosis).
Cuando se activa el modo de renderizado multivista, más eficiente, en una aplicación VR/AR, no hay pases de render separados para los contenidos de los ojos izquierdo y derecho. En su lugar, todo ocurre en una sola pasada, utilizando una matriz de texturas 2D con dos capas en lugar de dos texturas 2D independientes. Esto también significa que muchos buffers intermedios, es decir, texturas de color o profundidad, tendrán que convertirse en matrices de texturas en este modo. Esto tiene implicaciones para los materiales personalizados y los efectos de postprocesado. Texturas como la textura de entrada (INPUT) y la textura de profundidad (DEPTH_TEXTURE) se convierten en matrices de texturas 2D, expuestas en el shader como sampler2DArray en lugar de sampler2D. Esto tiene implicaciones para funciones GLSL como texture(), textureLod(), o textureSize(). La coordenada UV es entonces un vec3, no un vec2. Mientras que textureSize() devuelve un vec3, no un vec2. Los efectos destinados a funcionar independientemente del modo de renderizado, pueden escribirse con un ifdef apropiado:
#if QSHADER_VIEW_COUNT >= 2
vec4 c = texture(INPUT, vec3(INPUT_UV, VIEW_INDEX));
#else
vec4 c = texture(INPUT, INPUT_UV);
#endifTambién puede ser útil definir macros que manejen ambos casos. Por ejemplo:
#if QSHADER_VIEW_COUNT >= 2 #define SAMPLE_INPUT(uv) texture(INPUT, vec3(uv, VIEW_INDEX)) #define SAMPLE_DEPTH(uv) texture(DEPTH_TEXTURE, vec3(uv, VIEW_INDEX)).r #define PROJECTION PROJECTION_MATRIX[VIEW_INDEX] #define INVERSE_PROJECTION INVERSE_PROJECTION_MATRIX[VIEW_INDEX] #else #define SAMPLE_INPUT(uv) texture(INPUT, uv) #define SAMPLE_DEPTH(uv) texture(DEPTH_TEXTURE, uv).r #define PROJECTION PROJECTION_MATRIX #define INVERSE_PROJECTION INVERSE_PROJECTION_MATRIX #endif
Esto no se aplica a NORMAL_ROUGHNESS_TEXTURE que es siempre una textura 2D, incluso cuando el renderizado multivista está activo:
#define SAMPLE_NORMAL(uv) normalize(texture(NORMAL_ROUGHNESS_TEXTURE, uv).rgb)
Nota: La presencia de palabras clave como DEPTH_TEXTURE desencadenan pases de render adicionales, y los uniformes como INVERSE_PROJECTION_MATRIX se calculan y establecen en función de la presencia de la palabra clave en el fragmento de shader en cualquier lugar. Esto es más costoso, tanto en términos de rendimiento como de uso de recursos. Por lo tanto, se recomienda añadir estas #defines sólo cuando las texturas y matrices se vayan a utilizar realmente en el efecto.
Véase también Shader, Pass, Buffer, BufferInput, y Qt Quick 3D - Ejemplo de efecto personalizado.
Documentación de Propiedades
passes : list [read-only]
Contiene una lista de renderizaciones passes implementadas por el efecto.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.


