Qt Quick 3D - Ejemplo de materiales personalizados
Demuestra cómo escribir materiales personalizados sombreados.

Este ejemplo muestra como escribir sombreados custom materials. Con materiales sombreados, no tenemos que escribir programas de sombreado completos. En su lugar, escribimos funciones que modifican los shaders estándar de Qt. De esta forma, el material resultante participará por defecto en la iluminación, el mapeado de sombras y será compatible con las sondas de luz. Sólo tenemos que escribir lógica personalizada para los casos en que queremos un comportamiento especial. Esto se consigue aumentando el código de sombreado que se generaría para PrincipledMaterial con nuestras propias funciones personalizadas que se llaman en ciertas etapas en los sombreadores de vértices y fragmentos.
Para hacer un material sombreado personalizado, establece la propiedad shadingMode a CustomMaterial.Shaded.
Un material sencillo
El primer modelo utiliza un material simple que no añade ninguna lógica personalizada. Establecemos el material personalizado en el modelo como cualquier otro material:
Model { source: "weirdShape.mesh" scale: Qt.vector3d(100, 100, 100) rotation: Quaternion.fromEulerAngles(-90, 0, 0) x: v3d.radius materials: [ CustomMaterial { shadingMode: CustomMaterial.Shaded fragmentShader: "material_simple.frag" property color uDiffuse: "fuchsia" property real uSpecular: 1.0 } ] }
Además de establecer las propiedades shadingMode y fragmentShader, también añadimos dos propiedades al material: uDiffuse y Specular. Estas serán recogidas por el fragment shader.
El código para el fragment shader es corto:
void MAIN()
{
SPECULAR_AMOUNT = uSpecular;
BASE_COLOR = uDiffuse;
}Todos los shaders tienen que implementar la función MAIN. En éste, usamos las propiedades definidas en los materiales para establecer valores que serán usados por el código estándar del shader de Qt. Nótese que no tenemos que declararlas como uniformes: todo lo que tenemos que hacer es asegurarnos de que los nombres coinciden. Obtendríamos un error de compilación del shader si el material no tuviera propiedades coincidentes.
Las variables especiales SPECULAR_AMOUNT y BASE_COLOR corresponden a specularAmount y baseColor de PrincipledMaterial. Estas son usadas por el código estándar del shader para realizar los cálculos de iluminación como si hubiéramos usado una PrincipledMaterial.
Manejo personalizado de las luces
El siguiente objeto utiliza un material más complejo que implementa iluminación personalizada. El material tiene diferentes nombres uniformes, pero por lo demás lo utilizamos de la misma manera:
materials: [ CustomMaterial { shadingMode: CustomMaterial.Shaded fragmentShader: "material_customlights.frag" property color uDiffuse: "orange" property real uShininess: 150 } ]
El fragment shader implementa lógica personalizada para todos los diferentes tipos de luz:
void MAIN()
{
SPECULAR_AMOUNT = 1.0;
ROUGHNESS = 0.5;
BASE_COLOR = uDiffuse;
}
void AMBIENT_LIGHT()
{
DIFFUSE += uDiffuse.rgb * TOTAL_AMBIENT_COLOR;
}
void DIRECTIONAL_LIGHT()
{
DIFFUSE += uDiffuse.rgb * LIGHT_COLOR * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(NORMAL), TO_LIGHT_DIR)));
}
void POINT_LIGHT()
{
DIFFUSE += uDiffuse.rgb * LIGHT_COLOR * LIGHT_ATTENUATION * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(NORMAL), TO_LIGHT_DIR)));
}
void SPOT_LIGHT()
{
DIFFUSE += uDiffuse.rgb * LIGHT_COLOR * LIGHT_ATTENUATION * SPOT_FACTOR * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(VAR_WORLD_NORMAL), TO_LIGHT_DIR)));
}Aquí utilizamos muchas nuevas palabras clave especiales que hacen referencia a propiedades de los distintos tipos de luz. Consulte la documentación de CustomMaterial para una descripción de cada palabra clave. Tenga en cuenta que cada tipo de luz tiene su propia función. Cualquier función no implementada utilizará la implementación por defecto, comportándose como PrincipledMaterial. Por ejemplo: en este shader, no hemos implementado SPECULAR_LIGHT(), por lo que obtendremos la reflexión especular incorporada.
Añadir un sombreador de vértices
Un material personalizado también puede utilizar un sombreador de vértices para modificar la geometría del modelo. Aquí especificamos tanto el fragment shader como el vertex shader, y añadimos varias propiedades más que serán recogidas como valores uniformes:
materials: [ CustomMaterial { id: material shadingMode: CustomMaterial.Shaded vertexShader: "material_distortion.vert" fragmentShader: "material_customlights.frag" property real uTime: 0.0 property real uAmplitude: 0.3 property color uDiffuse: "yellow" property real uShininess: 50 NumberAnimation { target: material property: "uTime" from: 0.0 to: 31.4 duration: 10000 loops: Animation.Infinite running: true } } ]
El sombreador de vértices es muy corto:
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
void MAIN()
{
VERTEX.y += sin(uTime + VERTEX.x*10.0) * uAmplitude;
}Deforma el modelo desplazando cada vértice según una onda senoidal que cambia con el tiempo.
Un material transparente
Por último, añadimos una esfera con un material que sea transparente. Por razones de rendimiento, Qt no implementa la transparencia de forma completamente realista. En su lugar, Qt renderiza todos los objetos opacos de la escena en una textura, y luego los materiales transparentes leen de esta textura. Esto significa que los materiales transparentes darán el mejor resultado cuando se coloquen delante de otros objetos:
Model { id: screenSphere source: "#Sphere" scale: Qt.vector3d(0.75, 0.75, 0.75) y: 60 z: 750; materials: [ CustomMaterial { shadingMode: CustomMaterial.Shaded fragmentShader: "material_transparent.frag" } ]
Para este ejemplo, implementamos una función de distorsión simplista que no intenta hacer una refracción física real:
void MAIN()
{
vec2 size = vec2(textureSize(SCREEN_TEXTURE, 0));
vec2 uv = FRAGCOORD.xy / size;
vec3 view = normalize(VIEW_VECTOR);
vec3 projection = view - view * normalize(NORMAL);
vec3 refraction = projection * projection;
uv += refraction.xy * 0.5;
vec3 col = texture(SCREEN_TEXTURE, uv).rgb;
col = col * 0.8 + vec3(0.2);
BASE_COLOR = vec4(col, 1.0);
}SCREEN_TEXTURE se refiere a la textura que muestra todos los objetos opacos de la escena. Primero calculamos las coordenadas uv dentro de esta textura que coincide con la posición en pantalla del vértice actual. A continuación, añadimos un desplazamiento a esta posición, simulando un efecto de refracción, antes de hacer una búsqueda de textura.
Por último, mezclamos un 20% de blanco para obtener una ligera nubosidad. Tenga en cuenta que la salida se asigna a BASE_COLOR, por lo que Qt añadirá la iluminación en la parte superior de este. Por eso podemos ver reflejos en la superficie de la esfera.
Materiales sin sombreado
También es posible tener materiales personalizados que utilicen programas de sombreado completos (sin dejar de utilizar las palabras clave de conveniencia). El ejemplo customshaders demuestra el otro grupo de materiales personalizados: materiales personalizados sin sombreado.
© 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.