diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-04-21 11:28:30 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-04-23 00:12:05 +0300 |
commit | a60215f058845e14084132c82ddce3c3b028c80f (patch) | |
tree | 589dc5898e5db74b628d45ee2aad89e987c47d08 /source/blender/draw/engines/eevee_next/shaders | |
parent | 2882cbe685e7eca2a79438998354035c5d665205 (diff) |
EEVEE: Rewrite: Implement nodetree support with every geometry typestmp-eevee-next-merge
Diffstat (limited to 'source/blender/draw/engines/eevee_next/shaders')
12 files changed, 1223 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..d315fe92400 --- /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(samplerBuffer cd_buf) +{ + 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..4c123031c83 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl @@ -0,0 +1,37 @@ + +#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl) +#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_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..8e7201b9bce --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl @@ -0,0 +1,46 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_gpencil_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_attributes_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..0110a2bd930 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -0,0 +1,358 @@ + +#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; +/* Weight accumulation per sampled closure type. */ +float g_diffuse_weight; +float g_reflection_weight; +float g_refraction_weight; +/* 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, weight_total, random, candidate) \ + if (closure_select(candidate.weight, weight_total, random)) { \ + destination = candidate; \ + } + +void closure_weights_reset() +{ + g_diffuse_weight = 0.0; + g_reflection_weight = 0.0; + g_refraction_weight = 0.0; + + 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; + + /* TODO */ + g_diffuse_rand = 0.5; + g_reflection_rand = 0.5; + g_refraction_rand = 0.5; + + 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_weight, 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_weight, g_reflection_rand, reflection); + return Closure(0); +} + +Closure closure_eval(ClosureRefraction refraction) +{ + SELECT_CLOSURE(g_refraction_data, g_refraction_weight, 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_weight, g_reflection_rand, reflection); + SELECT_CLOSURE(g_refraction_data, g_refraction_weight, g_refraction_rand, refraction); + return Closure(0); +} + +/* Dielectric BSDF. */ +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection) +{ + SELECT_CLOSURE(g_diffuse_data, g_diffuse_weight, g_diffuse_rand, diffuse); + SELECT_CLOSURE(g_reflection_data, g_reflection_weight, g_reflection_rand, reflection); + return Closure(0); +} + +/* ClearCoat BSDF. */ +Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat) +{ + SELECT_CLOSURE(g_reflection_data, g_reflection_weight, g_reflection_rand, reflection); + SELECT_CLOSURE(g_reflection_data, g_reflection_weight, 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_weight, g_diffuse_rand, diffuse); + SELECT_CLOSURE(g_reflection_data, g_reflection_weight, g_reflection_rand, reflection); + SELECT_CLOSURE(g_reflection_data, g_reflection_weight, 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_weight, g_diffuse_rand, diffuse); + SELECT_CLOSURE(g_reflection_data, g_reflection_weight, g_reflection_rand, reflection); + SELECT_CLOSURE(g_reflection_data, g_reflection_weight, g_reflection_rand, clearcoat); + SELECT_CLOSURE(g_refraction_data, g_refraction_weight, 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 0.0; +} + +#ifndef GPU_METAL +void attrib_load(); +Closure nodetree_surface(); +Closure nodetree_volume(); +vec3 nodetree_displacement(); +float nodetree_thickness(); +#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; +} +vec4 closure_to_rgba(Closure cl) +{ + return vec4(0.0); +} +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..fbc5be853a0 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -0,0 +1,18 @@ + +/** + * 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(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..a7656d70c1b --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl @@ -0,0 +1,71 @@ + +/** + * 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(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..d83802c73f3 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl @@ -0,0 +1,36 @@ + +/** + * 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(eevee_nodetree_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) + +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 * saturate(g_diffuse_data.N.z); + out_radiance.rgb += g_reflection_data.color * saturate(g_reflection_data.N.z); + 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..5811b935c0d --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl @@ -0,0 +1,106 @@ + +#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) +{ +#if 0 /* TODO */ + /* 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 +#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 + +/** \} */ |