Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2022-05-02 10:22:14 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-05-02 10:35:45 +0300
commit8ece0816d9ddf25c4fc695bf244ed2e261433ee2 (patch)
tree087bf6a6a1890609801bb71aecd100856c7ea44a /source/blender/draw/engines/eevee_next/shaders
parentf0f44fd92f1684552ee0275d14bb6dd72405c8fd (diff)
EEVEE: Rewrite: Implement nodetree support with every geometry types
This commit introduce back support for all geometry types and all nodetree support. Only the forward shading pipeline is implemented for now. Vertex Displacement is automatically enabled for now. Lighting & Shading is placeholder. Related Task: T93220 # Conflicts: # source/blender/draw/engines/eevee_next/eevee_engine.cc # source/blender/gpu/CMakeLists.txt
Diffstat (limited to 'source/blender/draw/engines/eevee_next/shaders')
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl305
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl37
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl46
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl20
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_world_vert.glsl21
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl360
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl19
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl72
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl73
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl104
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl29
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh176
12 files changed, 1262 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
new file mode 100644
index 00000000000..abecb373995
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
@@ -0,0 +1,305 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
+
+#if defined(MAT_GEOM_MESH)
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh
+ *
+ * Mesh objects attributes are loaded using vertex input attributes.
+ * \{ */
+
+# ifdef OBINFO_LIB
+vec3 attr_load_orco(vec4 orco)
+{
+ /* We know when there is no orco layer when orco.w is 1.0 because it uses the generic vertex
+ * attrib (which is [0,0,0,1]). */
+ if (orco.w == 1.0) {
+ /* If the object does not have any deformation, the orco layer calculation is done on the fly
+ * using the orco_madd factors. */
+ return OrcoTexCoFactors[0].xyz + pos * OrcoTexCoFactors[1].xyz;
+ }
+ return orco.xyz * 0.5 + 0.5;
+}
+# endif
+vec4 attr_load_tangent(vec4 tangent)
+{
+ tangent.xyz = safe_normalize(normal_object_to_world(tangent.xyz));
+ return tangent;
+}
+vec4 attr_load_vec4(vec4 attr)
+{
+ return attr;
+}
+vec3 attr_load_vec3(vec3 attr)
+{
+ return attr;
+}
+vec2 attr_load_vec2(vec2 attr)
+{
+ return attr;
+}
+float attr_load_float(float attr)
+{
+ return attr;
+}
+vec4 attr_load_color(vec4 attr)
+{
+ return attr;
+}
+vec3 attr_load_uv(vec3 attr)
+{
+ return attr;
+}
+
+/** \} */
+
+#elif defined(MAT_GEOM_GPENCIL)
+
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil
+ *
+ * Grease Pencil objects have one uv and one color attribute layer.
+ * \{ */
+
+/* Globals to feed the load functions. */
+vec2 g_uvs;
+vec4 g_color;
+
+# ifdef OBINFO_LIB
+vec3 attr_load_orco(vec4 orco)
+{
+ vec3 lP = point_world_to_object(interp.P);
+ return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
+}
+# endif
+vec4 attr_load_tangent(vec4 tangent)
+{
+ return vec4(0.0, 0.0, 0.0, 1.0);
+}
+vec3 attr_load_uv(vec3 dummy)
+{
+ return vec3(g_uvs, 0.0);
+}
+vec4 attr_load_color(vec4 dummy)
+{
+ return g_color;
+}
+vec4 attr_load_vec4(vec4 attr)
+{
+ return vec4(0.0);
+}
+vec3 attr_load_vec3(vec3 attr)
+{
+ return vec3(0.0);
+}
+vec2 attr_load_vec2(vec2 attr)
+{
+ return vec2(0.0);
+}
+float attr_load_float(float attr)
+{
+ return 0.0;
+}
+
+/** \} */
+
+#elif defined(MAT_GEOM_CURVES)
+
+/* -------------------------------------------------------------------- */
+/** \name Curve
+ *
+ * Curve objects loads attributes from buffers through sampler buffers.
+ * \{ */
+
+# ifdef OBINFO_LIB
+vec3 attr_load_orco(vec4 orco)
+{
+ vec3 P = hair_get_strand_pos();
+ vec3 lP = transform_point(ModelMatrixInverse, P);
+ return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
+}
+# endif
+vec4 attr_load_tangent(samplerBuffer cd_buf)
+{
+ /* Not supported for the moment. */
+ return vec4(0.0, 0.0, 0.0, 1.0);
+}
+vec3 attr_load_uv(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, interp.curves_strand_id).rgb;
+}
+vec4 attr_load_color(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, interp.curves_strand_id).rgba;
+}
+vec4 attr_load_vec4(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, interp.curves_strand_id).rgba;
+}
+vec3 attr_load_vec3(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, interp.curves_strand_id).rgb;
+}
+vec2 attr_load_vec2(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, interp.curves_strand_id).rg;
+}
+float attr_load_float(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, interp.curves_strand_id).r;
+}
+
+/** \} */
+
+#elif defined(MAT_GEOM_VOLUME)
+
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ *
+ * Volume objects loads attributes from "grids" in the form of 3D textures.
+ * Per grid transform order is following loading order.
+ * \{ */
+
+# ifndef OBINFO_LIB
+# error "draw_object_infos is mandatory for volume objects"
+# endif
+
+vec3 g_orco;
+int g_attr_id = 0;
+
+vec3 grid_coordinates()
+{
+ vec3 co = g_orco;
+ /* Optional per-grid transform. */
+ if (drw_volume.grids_xform[g_attr_id][3][3] != 0.0) {
+ co = (drw_volume.grids_xform[g_attr_id] * vec4(objectPosition, 1.0)).xyz;
+ }
+ g_attr_id += 1;
+ return co;
+}
+
+vec3 attr_load_orco(sampler3D tex)
+{
+ g_attr_id += 1;
+ return g_orco;
+}
+vec4 attr_load_tangent(sampler3D tex)
+{
+ attr_id += 1;
+ return vec4(0);
+}
+vec4 attr_load_vec4(sampler3D tex)
+{
+ return texture(tex, grid_coordinates());
+}
+vec3 attr_load_vec3(sampler3D tex)
+{
+ return texture(tex, grid_coordinates()).rgb;
+}
+vec2 attr_load_vec2(sampler3D tex)
+{
+ return texture(tex, grid_coordinates()).rg;
+}
+float attr_load_float(sampler3D tex)
+{
+ return texture(tex, grid_coordinates()).r;
+}
+vec4 attr_load_color(sampler3D tex)
+{
+ return texture(tex, grid_coordinates());
+}
+vec3 attr_load_uv(sampler3D attr)
+{
+ attr_id += 1;
+ return vec3(0);
+}
+
+/** \} */
+
+#elif defined(MAT_GEOM_WORLD)
+
+/* -------------------------------------------------------------------- */
+/** \name World
+ *
+ * World has no attributes other than orco.
+ * \{ */
+
+vec3 attr_load_orco(vec4 orco)
+{
+ return -g_data.N;
+}
+vec4 attr_load_tangent(vec4 tangent)
+{
+ return vec4(0);
+}
+vec4 attr_load_vec4(vec4 attr)
+{
+ return vec4(0);
+}
+vec3 attr_load_vec3(vec3 attr)
+{
+ return vec3(0);
+}
+vec2 attr_load_vec2(vec2 attr)
+{
+ return vec2(0);
+}
+float attr_load_float(float attr)
+{
+ return 0.0;
+}
+vec4 attr_load_color(vec4 attr)
+{
+ return vec4(0);
+}
+vec3 attr_load_uv(vec3 attr)
+{
+ return vec3(0);
+}
+
+/** \} */
+
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Volume Attribute post
+ *
+ * TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
+ * the engine side. But as of now, the engines are reponsible for loading the attributes.
+ *
+ * \{ */
+
+#if defined(MAT_GEOM_VOLUME)
+
+float attr_load_temperature_post(float attr)
+{
+ /* Bring the into standard range without having to modify the grid values */
+ attr = (attr > 0.01) ? (attr * drw_volume.temperature_mul + drw_volume.temperature_bias) : 0.0;
+ return attr;
+}
+vec4 attr_load_color_post(vec4 attr)
+{
+ /* Density is premultiplied for interpolation, divide it out here. */
+ attr.rgb *= safe_rcp(attr.a);
+ attr.rgb *= drw_volume.color_mul.rgb;
+ attr.a = 1.0;
+ return attr;
+}
+
+#else /* Noop for any other surface. */
+
+float attr_load_temperature_post(float attr)
+{
+ return attr;
+}
+vec4 attr_load_color_post(vec4 attr)
+{
+ return attr;
+}
+
+#endif
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
new file mode 100644
index 00000000000..edf9e39e005
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
@@ -0,0 +1,37 @@
+
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl) /* TODO rename to curve. */
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+
+void main(void)
+{
+ init_interface();
+
+ vec3 T;
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ hair_get_pos_tan_binor_time(is_persp,
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz,
+ ViewMatrixInverse[2].xyz,
+ interp.P,
+ T,
+ interp.curves_binormal,
+ interp.curves_time,
+ interp.curves_thickness,
+ interp.curves_time_width);
+
+ interp.N = cross(T, interp.curves_binormal);
+ interp.curves_strand_id = hair_get_strand_id();
+ interp.barycentric_coords = hair_get_barycentric();
+
+ init_globals();
+ attrib_load();
+
+ interp.P += nodetree_displacement();
+
+ gl_Position = point_world_to_ndc(interp.P);
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
new file mode 100644
index 00000000000..bb1f93b4453
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
@@ -0,0 +1,46 @@
+
+#pragma BLENDER_REQUIRE(common_gpencil_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+
+void main(void)
+{
+ init_interface();
+
+ /* TODO(fclem): Expose through a node? */
+ vec4 sspos;
+ vec2 aspect;
+ float strength;
+ float hardness;
+ vec2 thickness;
+
+ gl_Position = gpencil_vertex(ma,
+ ma1,
+ ma2,
+ ma3,
+ pos,
+ pos1,
+ pos2,
+ pos3,
+ uv1,
+ uv2,
+ col1,
+ col2,
+ fcol1,
+ vec4(drw_view.viewport_size, drw_view.viewport_size_inverse),
+ interp.P,
+ interp.N,
+ g_color,
+ strength,
+ g_uvs,
+ sspos,
+ aspect,
+ thickness,
+ hardness);
+
+ init_globals();
+ attrib_load();
+
+ interp.P += nodetree_displacement();
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
new file mode 100644
index 00000000000..24d5a2c60b0
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
@@ -0,0 +1,20 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+
+void main(void)
+{
+ init_interface();
+
+ interp.P = point_object_to_world(pos);
+ interp.N = normal_object_to_world(nor);
+
+ init_globals();
+ attrib_load();
+
+ interp.P += nodetree_displacement();
+
+ gl_Position = point_world_to_ndc(interp.P);
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_world_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_world_vert.glsl
new file mode 100644
index 00000000000..6ce98f26c7e
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_world_vert.glsl
@@ -0,0 +1,21 @@
+
+/**
+ * Custom fullscreen triangle with placeholders varyings.
+ **/
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+
+void main(void)
+{
+ /* Fullscreen triangle. */
+ int v = gl_VertexID % 3;
+ float x = float((v & 1) << 2) - 1.0;
+ float y = float((v & 2) << 1) - 1.0;
+ gl_Position = vec4(x, y, 1.0, 1.0);
+
+ /* Pass view position to keep accuracy. */
+ interp.P = project_point(ProjectionMatrixInverse, gl_Position.xyz);
+ interp.N = vec3(1);
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
new file mode 100644
index 00000000000..06191a5c007
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
@@ -0,0 +1,360 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
+
+vec3 g_emission;
+vec3 g_transmittance;
+float g_holdout;
+
+/* The Closure type is never used. Use float as dummy type. */
+#define Closure float
+
+/* Sampled closure parameters. */
+ClosureDiffuse g_diffuse_data;
+ClosureReflection g_reflection_data;
+ClosureRefraction g_refraction_data;
+/* Random number per sampled closure type. */
+float g_diffuse_rand;
+float g_reflection_rand;
+float g_refraction_rand;
+
+/**
+ * Returns true if the closure is to be selected based on the input weight.
+ */
+bool closure_select(float weight, inout float total_weight, inout float r)
+{
+ total_weight += weight;
+ float x = weight / total_weight;
+ bool chosen = (r < x);
+ /* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within
+ * that interval, so you remaping to [0,1] again to explore this space of probability. */
+ r = (chosen) ? (r / x) : ((r - x) / (1.0 - x));
+ return chosen;
+}
+
+#define SELECT_CLOSURE(destination, random, candidate) \
+ if (closure_select(candidate.weight, destination.weight, random)) { \
+ destination = candidate; \
+ }
+
+void closure_weights_reset()
+{
+ g_diffuse_data.weight = 0.0;
+ g_diffuse_data.color = vec3(0.0);
+ g_diffuse_data.N = vec3(0.0);
+ g_diffuse_data.sss_radius = vec3(0.0);
+ g_diffuse_data.sss_id = uint(0);
+
+ g_reflection_data.weight = 0.0;
+ g_reflection_data.color = vec3(0.0);
+ g_reflection_data.N = vec3(0.0);
+ g_reflection_data.roughness = 0.0;
+
+ g_refraction_data.weight = 0.0;
+ g_refraction_data.color = vec3(0.0);
+ g_refraction_data.N = vec3(0.0);
+ g_refraction_data.roughness = 0.0;
+ g_refraction_data.ior = 0.0;
+
+ /* TEMP */
+#define P(x) ((x + 0.5) / 16.0)
+ const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)),
+ vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
+ vec4(P(3.0), P(11.0), P(1.0), P(9.0)),
+ vec4(P(15.0), P(7.0), P(13.0), P(5.0)));
+#undef P
+#if defined(GPU_FRAGMENT_SHADER)
+ ivec2 pix = ivec2(gl_FragCoord.xy) % ivec2(4);
+ g_diffuse_rand = dither_mat4x4[pix.x][pix.y];
+ g_reflection_rand = dither_mat4x4[pix.x][pix.y];
+ g_refraction_rand = dither_mat4x4[pix.x][pix.y];
+#else
+ g_diffuse_rand = 0.0;
+ g_reflection_rand = 0.0;
+ g_refraction_rand = 0.0;
+#endif
+
+ g_emission = vec3(0.0);
+ g_transmittance = vec3(0.0);
+ g_holdout = 0.0;
+}
+
+/* Single BSDFs. */
+Closure closure_eval(ClosureDiffuse diffuse)
+{
+ SELECT_CLOSURE(g_diffuse_data, g_diffuse_rand, diffuse);
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureTranslucent translucent)
+{
+ /* TODO */
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureReflection reflection)
+{
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection);
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureRefraction refraction)
+{
+ SELECT_CLOSURE(g_refraction_data, g_refraction_rand, refraction);
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureEmission emission)
+{
+ g_emission += emission.emission * emission.weight;
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureTransparency transparency)
+{
+ g_transmittance += transparency.transmittance * transparency.weight;
+ g_holdout += transparency.holdout * transparency.weight;
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureVolumeScatter volume_scatter)
+{
+ /* TODO */
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureVolumeAbsorption volume_absorption)
+{
+ /* TODO */
+ return Closure(0);
+}
+
+Closure closure_eval(ClosureHair hair)
+{
+ /* TODO */
+ return Closure(0);
+}
+
+/* Glass BSDF. */
+Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction)
+{
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection);
+ SELECT_CLOSURE(g_refraction_data, g_refraction_rand, refraction);
+ return Closure(0);
+}
+
+/* Dielectric BSDF. */
+Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
+{
+ SELECT_CLOSURE(g_diffuse_data, g_diffuse_rand, diffuse);
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection);
+ return Closure(0);
+}
+
+/* ClearCoat BSDF. */
+Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat)
+{
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection);
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, clearcoat);
+ return Closure(0);
+}
+
+/* Volume BSDF. */
+Closure closure_eval(ClosureVolumeScatter volume_scatter,
+ ClosureVolumeAbsorption volume_absorption,
+ ClosureEmission emission)
+{
+ /* TODO */
+ return Closure(0);
+}
+
+/* Specular BSDF. */
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat)
+{
+ SELECT_CLOSURE(g_diffuse_data, g_diffuse_rand, diffuse);
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection);
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, clearcoat);
+ return Closure(0);
+}
+
+/* Principled BSDF. */
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat,
+ ClosureRefraction refraction)
+{
+ SELECT_CLOSURE(g_diffuse_data, g_diffuse_rand, diffuse);
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection);
+ SELECT_CLOSURE(g_reflection_data, g_reflection_rand, clearcoat);
+ SELECT_CLOSURE(g_refraction_data, g_refraction_rand, refraction);
+ return Closure(0);
+}
+
+/* Noop since we are sampling closures. */
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ return Closure(0);
+}
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ return Closure(0);
+}
+
+float ambient_occlusion_eval(vec3 normal,
+ float distance,
+ const float inverted,
+ const float sample_count)
+{
+ /* TODO */
+ return 1.0;
+}
+
+#ifndef GPU_METAL
+void attrib_load();
+Closure nodetree_surface();
+Closure nodetree_volume();
+vec3 nodetree_displacement();
+float nodetree_thickness();
+vec4 closure_to_rgba(Closure cl);
+#endif
+
+/* Stubs. */
+vec2 btdf_lut(float a, float b, float c)
+{
+ return vec2(1, 0);
+}
+vec2 brdf_lut(float a, float b)
+{
+ return vec2(1, 0);
+}
+vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c)
+{
+ return a;
+}
+vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c)
+{
+ return a;
+}
+float F_eta(float a, float b)
+{
+ return a;
+}
+void output_aov(vec4 color, float value, uint hash)
+{
+}
+
+#ifdef EEVEE_MATERIAL_STUBS
+# define attrib_load()
+# define nodetree_displacement() vec3(0.0)
+# define nodetree_surface() Closure(0)
+# define nodetree_volume() Closure(0)
+# define nodetree_thickness() 0.1
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Fragment Displacement
+ *
+ * Displacement happening in the fragment shader.
+ * Can be used in conjunction with a per vertex displacement.
+ *
+ * \{ */
+
+#ifdef MAT_DISPLACEMENT_BUMP
+/* Return new shading normal. */
+vec3 displacement_bump()
+{
+# ifdef GPU_FRAGMENT_SHADER
+ vec2 dHd;
+ dF_branch(dot(nodetree_displacement(), g_data.N + dF_impl(g_data.N)), dHd);
+
+ vec3 dPdx = dFdx(g_data.P);
+ vec3 dPdy = dFdy(g_data.P);
+
+ /* Get surface tangents from normal. */
+ vec3 Rx = cross(dPdy, g_data.N);
+ vec3 Ry = cross(g_data.N, dPdx);
+
+ /* Compute surface gradient and determinant. */
+ float det = dot(dPdx, Rx);
+
+ vec3 surfgrad = dHd.x * Rx + dHd.y * Ry;
+
+ float facing = FrontFacing ? 1.0 : -1.0;
+ return normalize(abs(det) * g_data.N - facing * sign(det) * surfgrad);
+# else
+ return g_data.N;
+# endif
+}
+#endif
+
+void fragment_displacement()
+{
+#ifdef MAT_DISPLACEMENT_BUMP
+ g_data.N = displacement_bump();
+#endif
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Coordinate implementations
+ *
+ * Callbacks for the texture coordinate node.
+ *
+ * \{ */
+
+vec3 coordinate_camera(vec3 P)
+{
+ vec3 vP;
+ if (false /* probe */) {
+ /* Unsupported. It would make the probe camera-dependent. */
+ vP = P;
+ }
+ else {
+#ifdef MAT_WORLD
+ vP = transform_direction(ViewMatrix, P);
+#else
+ vP = transform_point(ViewMatrix, P);
+#endif
+ }
+ vP.z = -vP.z;
+ return vP;
+}
+
+vec3 coordinate_screen(vec3 P)
+{
+ vec3 window = vec3(0.0);
+ if (false /* probe */) {
+ /* Unsupported. It would make the probe camera-dependent. */
+ window.xy = vec2(0.5);
+ }
+ else {
+ /* TODO(fclem): Actual camera tranform. */
+ window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
+ window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
+ }
+ return window;
+}
+
+vec3 coordinate_reflect(vec3 P, vec3 N)
+{
+#ifdef MAT_WORLD
+ return N;
+#else
+ return -reflect(cameraVec(P), N);
+#endif
+}
+
+vec3 coordinate_incoming(vec3 P)
+{
+#ifdef MAT_WORLD
+ return -P;
+#else
+ return cameraVec(P);
+#endif
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl
new file mode 100644
index 00000000000..5500131c3e7
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl
@@ -0,0 +1,19 @@
+
+/**
+ * Deferred lighting evaluation: Lighting is evaluated in a separate pass.
+ *
+ * Outputs shading parameter per pixel using a randomized set of BSDFs.
+ **/
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+
+void main(void)
+{
+ init_globals();
+
+ nodetree_surface();
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
new file mode 100644
index 00000000000..a635cf72e45
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
@@ -0,0 +1,72 @@
+
+/**
+ * Depth shader that can stochastically discard transparent pixel.
+ */
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+
+/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire. */
+float hash(vec2 a)
+{
+ return fract(1e4 * sin(17.0 * a.x + 0.1 * a.y) * (0.1 + abs(sin(13.0 * a.y + a.x))));
+}
+
+float hash3d(vec3 a)
+{
+ return hash(vec2(hash(a.xy), a.z));
+}
+
+float hashed_alpha_threshold(float hash_scale, float hash_offset, vec3 P)
+{
+ /* Find the discretized derivatives of our coordinates. */
+ float max_deriv = max(length(dFdx(P)), length(dFdy(P)));
+ float pix_scale = 1.0 / (hash_scale * max_deriv);
+ /* Find two nearest log-discretized noise scales. */
+ float pix_scale_log = log2(pix_scale);
+ vec2 pix_scales;
+ pix_scales.x = exp2(floor(pix_scale_log));
+ pix_scales.y = exp2(ceil(pix_scale_log));
+ /* Compute alpha thresholds at our two noise scales. */
+ vec2 alpha;
+ alpha.x = hash3d(floor(pix_scales.x * P));
+ alpha.y = hash3d(floor(pix_scales.y * P));
+ /* Factor to interpolate lerp with. */
+ float fac = fract(log2(pix_scale));
+ /* Interpolate alpha threshold from noise at two scales. */
+ float x = mix(alpha.x, alpha.y, fac);
+ /* Pass into CDF to compute uniformly distrib threshold. */
+ float a = min(fac, 1.0 - fac);
+ float one_a = 1.0 - a;
+ float denom = 1.0 / (2 * a * one_a);
+ float one_x = (1 - x);
+ vec3 cases = vec3((x * x) * denom, (x - 0.5 * a) / one_a, 1.0 - (one_x * one_x * denom));
+ /* Find our final, uniformly distributed alpha threshold. */
+ float threshold = (x < one_a) ? ((x < a) ? cases.x : cases.y) : cases.z;
+ /* Jitter the threshold for TAA accumulation. */
+ threshold = fract(threshold + hash_offset);
+ /* Avoids threshold == 0. */
+ threshold = clamp(threshold, 1.0e-6, 1.0);
+ return threshold;
+}
+
+void main(void)
+{
+#ifdef MAT_TRANSPARENT
+ init_globals();
+
+ nodetree_surface();
+
+ // float noise_offset = sampling_rng_1D_get(sampling_buf, SAMPLING_TRANSPARENCY);
+ float noise_offset = 0.5;
+ float random_threshold = hashed_alpha_threshold(1.0, noise_offset, g_data.P);
+
+ float transparency = avg(g_transmittance);
+ if (transparency > random_threshold) {
+ discard;
+ }
+#endif
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
new file mode 100644
index 00000000000..b3fbdb937f9
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
@@ -0,0 +1,73 @@
+
+/**
+ * Forward lighting evaluation: Lighting is evaluated during the geometry rasterization.
+ *
+ * This is used by alpha blended materials and materials using Shader to RGB nodes.
+ **/
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+
+float spec_light(ClosureReflection ref)
+{
+ float gloss = saturate(1.0 - ref.roughness);
+ float shininess = exp2(10.0 * gloss + 1.0);
+ vec3 N = ref.N;
+ vec3 L = vec3(0.0, 0.0, 1.0);
+ vec3 H = normalize(L + cameraVec(g_data.P));
+ float spec_angle = saturate(dot(N, H));
+ float normalization_factor = shininess * 0.125 + 1.0;
+ float spec_light = pow(spec_angle, shininess) * saturate(dot(N, L)) * normalization_factor;
+ return spec_light;
+}
+
+vec4 closure_to_rgba(Closure cl)
+{
+ vec4 out_color;
+ out_color.rgb = g_emission;
+ out_color.rgb += g_diffuse_data.color * g_diffuse_data.weight *
+ saturate(g_diffuse_data.N.z * 0.5 + 0.5);
+ out_color.rgb += g_reflection_data.color * g_reflection_data.weight *
+ spec_light(g_reflection_data);
+ out_color.rgb += g_refraction_data.color * g_refraction_data.weight *
+ saturate(g_refraction_data.N.z * 0.5 + 0.5);
+
+ out_color.a = saturate(1.0 - avg(g_transmittance));
+
+ /* Reset for the next closure tree. */
+ closure_weights_reset();
+
+ return out_color;
+}
+
+void main(void)
+{
+ init_globals();
+
+ fragment_displacement();
+
+ nodetree_surface();
+
+ g_holdout = saturate(g_holdout);
+
+ out_radiance.rgb = g_emission;
+ out_radiance.rgb += g_diffuse_data.color * g_diffuse_data.weight *
+ saturate(g_diffuse_data.N.z * 0.5 + 0.5);
+ out_radiance.rgb += g_reflection_data.color * g_reflection_data.weight *
+ spec_light(g_reflection_data);
+ out_radiance.rgb += g_refraction_data.color * g_refraction_data.weight *
+ saturate(g_refraction_data.N.z * 0.5 + 0.5);
+ out_radiance.a = 0.0;
+
+ out_radiance.rgb *= 1.0 - g_holdout;
+
+ out_transmittance.rgb = g_transmittance;
+ out_transmittance.a = saturate(avg(g_transmittance));
+
+ /* Test */
+ out_transmittance.a = 1.0 - out_transmittance.a;
+ out_radiance.a = 1.0 - out_radiance.a;
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
new file mode 100644
index 00000000000..01a90bcb81b
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl
@@ -0,0 +1,104 @@
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+
+#if defined(USE_BARYCENTRICS) && defined(GPU_FRAGMENT_SHADER) && defined(MAT_GEOM_MESH)
+vec3 barycentric_distances_get()
+{
+ /* NOTE: No need to undo perspective divide since it has not been applied. */
+ vec3 pos0 = (ProjectionMatrixInverse * gpu_position_at_vertex(0)).xyz;
+ vec3 pos1 = (ProjectionMatrixInverse * gpu_position_at_vertex(1)).xyz;
+ vec3 pos2 = (ProjectionMatrixInverse * gpu_position_at_vertex(2)).xyz;
+ vec3 edge21 = pos2 - pos1;
+ vec3 edge10 = pos1 - pos0;
+ vec3 edge02 = pos0 - pos2;
+ vec3 d21 = safe_normalize(edge21);
+ vec3 d10 = safe_normalize(edge10);
+ vec3 d02 = safe_normalize(edge02);
+ vec3 dists;
+ float d = dot(d21, edge02);
+ dists.x = sqrt(dot(edge02, edge02) - d * d);
+ d = dot(d02, edge10);
+ dists.y = sqrt(dot(edge10, edge10) - d * d);
+ d = dot(d10, edge21);
+ dists.z = sqrt(dot(edge21, edge21) - d * d);
+ return dists.xyz;
+}
+#endif
+
+void init_globals_mesh(void)
+{
+#if defined(USE_BARYCENTRICS) && defined(GPU_FRAGMENT_SHADER) && defined(MAT_GEOM_MESH)
+ g_data.barycentric_coords = gpu_BaryCoord.xy;
+ g_data.barycentric_dists = barycentric_distances_get();
+#endif
+}
+
+void init_globals_curves(void)
+{
+ /* Shade as a cylinder. */
+ float cos_theta = interp.curves_time_width / interp.curves_thickness;
+ float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
+ g_data.N = normalize(interp.N * sin_theta + interp.curves_binormal * cos_theta);
+
+ g_data.is_strand = true;
+ g_data.hair_time = interp.curves_time;
+ g_data.hair_thickness = interp.curves_thickness;
+ g_data.hair_strand_id = interp.curves_strand_id;
+#if defined(USE_BARYCENTRICS) && defined(GPU_FRAGMENT_SHADER) && defined(MAT_GEOM_CURVES)
+ g_data.barycentric_coords = hair_resolve_barycentric(interp.barycentric_coords);
+#endif
+}
+
+void init_globals_gpencil(void)
+{
+ /* Undo backface flip as the gpencil normal is already pointing towards the camera. */
+ g_data.N = interp.N;
+}
+
+void init_globals(void)
+{
+ /* Default values. */
+ g_data.P = interp.P;
+ g_data.N = safe_normalize(interp.N);
+ g_data.Ng = g_data.N;
+ g_data.is_strand = false;
+ g_data.hair_time = 0.0;
+ g_data.hair_thickness = 0.0;
+ g_data.hair_strand_id = 0;
+ g_data.ray_type = RAY_TYPE_CAMERA; /* TODO */
+ g_data.ray_depth = 0.0;
+ g_data.ray_length = distance(g_data.P, cameraPos);
+ g_data.barycentric_coords = vec2(0.0);
+ g_data.barycentric_dists = vec3(0.0);
+
+#ifdef GPU_FRAGMENT_SHADER
+ g_data.N = (FrontFacing) ? g_data.N : -g_data.N;
+ g_data.Ng = safe_normalize(cross(dFdx(g_data.P), dFdy(g_data.P)));
+#endif
+
+#if defined(MAT_GEOM_MESH)
+ init_globals_mesh();
+#elif defined(MAT_GEOM_CURVES)
+ init_globals_curves();
+#elif defined(MAT_GEOM_GPENCIL)
+ init_globals_gpencil();
+#endif
+}
+
+/* Avoid some compiler issue with non set interface parameters. */
+void init_interface()
+{
+#ifdef GPU_VERTEX_SHADER
+ interp.P = vec3(0.0);
+ interp.N = vec3(0.0);
+ interp.barycentric_coords = vec2(0.0);
+ interp.curves_binormal = vec3(0.0);
+ interp.curves_time = 0.0;
+ interp.curves_time_width = 0.0;
+ interp.curves_thickness = 0.0;
+ interp.curves_strand_id = 0;
+ drw_ResourceID_iface.resource_index = resource_id;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl
new file mode 100644
index 00000000000..9901596623d
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl
@@ -0,0 +1,29 @@
+
+/**
+ * Background used to shade the world.
+ *
+ * Outputs shading parameter per pixel using a set of randomized BSDFs.
+ **/
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
+
+void main(void)
+{
+ init_globals();
+ /* View position is passed to keep accuracy. */
+ g_data.N = normal_view_to_world(viewCameraVec(interp.P));
+ g_data.Ng = g_data.N;
+ g_data.P = -g_data.N + cameraPos;
+ attrib_load();
+
+ nodetree_surface();
+
+ g_holdout = saturate(g_holdout);
+
+ out_background.rgb = safe_color(g_emission) * (1.0 - g_holdout);
+ out_background.a = saturate(avg(g_transmittance)) * g_holdout;
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
new file mode 100644
index 00000000000..13269d833e8
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
@@ -0,0 +1,176 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Common
+ * \{ */
+
+/* TODO(@fclem): This is a bit out of place at the moment. */
+GPU_SHADER_CREATE_INFO(eevee_shared)
+ .typedef_source("eevee_defines.hh")
+ .typedef_source("eevee_shader_shared.hh");
+
+GPU_SHADER_CREATE_INFO(eevee_sampling_data)
+ .additional_info("eevee_shared")
+ .uniform_buf(14, "SamplingData", "sampling_buf");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Surface Mesh Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
+ .define("MAT_GEOM_MESH")
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC3, "nor")
+ .vertex_source("eevee_geom_mesh_vert.glsl")
+ .additional_info("draw_mesh", "draw_resource_id_varying", "draw_resource_handle");
+
+GPU_SHADER_CREATE_INFO(eevee_geom_gpencil)
+ .define("MAT_GEOM_GPENCIL")
+ .vertex_source("eevee_geom_gpencil_vert.glsl")
+ .additional_info("draw_gpencil", "draw_resource_id_varying", "draw_resource_handle");
+
+GPU_SHADER_CREATE_INFO(eevee_geom_curves)
+ .define("MAT_GEOM_CURVES")
+ .vertex_source("eevee_geom_curves_vert.glsl")
+ .additional_info("draw_hair", "draw_resource_id_varying", "draw_resource_handle");
+
+GPU_SHADER_CREATE_INFO(eevee_geom_world)
+ .define("MAT_GEOM_WORLD")
+ .builtins(BuiltinBits::VERTEX_ID)
+ .vertex_source("eevee_geom_world_vert.glsl")
+ .additional_info("draw_modelmat", "draw_resource_id_varying", "draw_resource_handle");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Surface
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp")
+ .smooth(Type::VEC3, "P")
+ .smooth(Type::VEC3, "N")
+ .smooth(Type::VEC2, "barycentric_coords")
+ .smooth(Type::VEC3, "curves_binormal")
+ .smooth(Type::FLOAT, "curves_time")
+ .smooth(Type::FLOAT, "curves_time_width")
+ .smooth(Type::FLOAT, "curves_thickness")
+ .flat(Type::INT, "curves_strand_id");
+
+#define image_out(slot, qualifier, format, name) \
+ image(slot, format, qualifier, ImageType::FLOAT_2D, name, Frequency::PASS)
+
+GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
+ .vertex_out(eevee_surf_iface)
+ /* Note: This removes the possibility of using gl_FragDepth. */
+ // .early_fragment_test(true)
+ /* Direct output. */
+ .fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
+ .fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
+ /* Gbuffer. */
+ // .image_out(0, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_transmit_color")
+ // .image_out(1, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_transmit_data")
+ // .image_out(2, Qualifier::WRITE, GPU_RGBA16F, "gbuff_transmit_normal")
+ // .image_out(3, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_reflection_color")
+ // .image_out(4, Qualifier::WRITE, GPU_RGBA16F, "gbuff_reflection_normal")
+ // .image_out(5, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_emission")
+ /* Renderpasses. */
+ // .image_out(6, Qualifier::READ_WRITE, GPU_RGBA16F, "rpass_volume_light")
+ /* TODO: AOVs maybe? */
+ .fragment_source("eevee_surf_deferred_frag.glsl")
+ // .additional_info("eevee_sampling_data", "eevee_utility_texture")
+ ;
+
+#undef image_out
+
+GPU_SHADER_CREATE_INFO(eevee_surf_forward)
+ .auto_resource_location(true)
+ .vertex_out(eevee_surf_iface)
+ .fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
+ .fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
+ .fragment_source("eevee_surf_forward_frag.glsl")
+ // .additional_info("eevee_sampling_data",
+ // "eevee_lightprobe_data",
+ /* Optionnally added depending on the material. */
+ // "eevee_raytrace_data",
+ // "eevee_transmittance_data",
+ // "eevee_utility_texture",
+ // "eevee_light_data",
+ // "eevee_shadow_data"
+ // )
+ ;
+
+GPU_SHADER_CREATE_INFO(eevee_surf_depth)
+ .vertex_out(eevee_surf_iface)
+ .fragment_source("eevee_surf_depth_frag.glsl")
+ // .additional_info("eevee_sampling_data", "eevee_utility_texture")
+ ;
+
+GPU_SHADER_CREATE_INFO(eevee_surf_world)
+ .vertex_out(eevee_surf_iface)
+ .fragment_out(0, Type::VEC4, "out_background")
+ .fragment_source("eevee_surf_world_frag.glsl")
+ // .additional_info("eevee_utility_texture")
+ ;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ * \{ */
+
+#if 0 /* TODO */
+GPU_SHADER_INTERFACE_INFO(eevee_volume_iface, "interp")
+ .smooth(Type::VEC3, "P_start")
+ .smooth(Type::VEC3, "P_end");
+
+GPU_SHADER_CREATE_INFO(eevee_volume_deferred)
+ .sampler(0, ImageType::DEPTH_2D, "depth_max_tx")
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(eevee_volume_iface)
+ .fragment_out(0, Type::UVEC4, "out_volume_data")
+ .fragment_out(1, Type::VEC4, "out_transparency_data")
+ .additional_info("eevee_shared")
+ .vertex_source("eevee_volume_vert.glsl")
+ .fragment_source("eevee_volume_deferred_frag.glsl")
+ .additional_info("draw_fullscreen");
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Test shaders
+ *
+ * Variations that are only there to test shaders at compile time.
+ * \{ */
+
+#ifdef DEBUG
+
+/* Stub functions defined by the material evaluation. */
+GPU_SHADER_CREATE_INFO(eevee_material_stub).define("EEVEE_MATERIAL_STUBS");
+
+# define EEVEE_MAT_FINAL_VARIATION(name, ...) \
+ GPU_SHADER_CREATE_INFO(name) \
+ .additional_info(__VA_ARGS__) \
+ .auto_resource_location(true) \
+ .do_static_compilation(true);
+
+# define EEVEE_MAT_GEOM_VARIATIONS(prefix, ...) \
+ EEVEE_MAT_FINAL_VARIATION(prefix##_world, "eevee_geom_world", __VA_ARGS__) \
+ EEVEE_MAT_FINAL_VARIATION(prefix##_gpencil, "eevee_geom_gpencil", __VA_ARGS__) \
+ EEVEE_MAT_FINAL_VARIATION(prefix##_hair, "eevee_geom_curves", __VA_ARGS__) \
+ EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__)
+
+# define EEVEE_MAT_PIPE_VARIATIONS(name, ...) \
+ EEVEE_MAT_GEOM_VARIATIONS(name##_world, "eevee_surf_world", __VA_ARGS__) \
+ EEVEE_MAT_GEOM_VARIATIONS(name##_depth, "eevee_surf_depth", __VA_ARGS__) \
+ EEVEE_MAT_GEOM_VARIATIONS(name##_deferred, "eevee_surf_deferred", __VA_ARGS__) \
+ EEVEE_MAT_GEOM_VARIATIONS(name##_forward, "eevee_surf_forward", __VA_ARGS__)
+
+EEVEE_MAT_PIPE_VARIATIONS(eevee_surface, "eevee_material_stub")
+
+#endif
+
+/** \} */