Compare commits
12 Commits
temp-geome
...
eevee-clos
Author | SHA1 | Date | |
---|---|---|---|
42d5896841 | |||
251ad8bf60 | |||
7ca2427ce2 | |||
744427b729 | |||
6eaeb6272e | |||
1d56589f14 | |||
f6cc14f86e | |||
1df2f7a713 | |||
bb05f6d335 | |||
36b066ee98 | |||
60b2e410a7 | |||
fe00859202 |
@@ -11,6 +11,8 @@
|
||||
<array>
|
||||
<string>blend</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>blender file icon.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Blender File</string>
|
||||
<key>CFBundleTypeOSTypes</key>
|
||||
@@ -21,12 +23,6 @@
|
||||
<string>Editor</string>
|
||||
<key>LSIsAppleDefaultForType</key>
|
||||
<true/>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>org.blenderfoundation.blender.file</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconSystemGenerated</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
@@ -53,30 +49,5 @@
|
||||
<string>NSApplication</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>org.blenderfoundation.blender.file</string>
|
||||
<key>UTTypeIcons</key>
|
||||
<dict>
|
||||
<key>UTTypeIconName</key>
|
||||
<string>Blender File</string>
|
||||
<key>UTTypeIconText</key>
|
||||
<string>blend</string>
|
||||
</dict>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>blend</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
Binary file not shown.
@@ -502,7 +502,6 @@ geometry_node_categories = [
|
||||
]),
|
||||
GeometryNodeCategory("GEO_INPUT", "Input", items=[
|
||||
NodeItem("GeometryNodeObjectInfo"),
|
||||
NodeItem("GeometryNodeCollectionInfo"),
|
||||
NodeItem("FunctionNodeRandomFloat"),
|
||||
NodeItem("ShaderNodeValue"),
|
||||
NodeItem("FunctionNodeInputVector"),
|
||||
|
@@ -476,9 +476,3 @@ class VolumeComponent : public GeometryComponent {
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GeometryComponentType::Volume;
|
||||
};
|
||||
|
||||
using ForeachGeometryCallbackConst = std::function<void(
|
||||
const GeometryComponent &component, blender::Span<blender::float4x4> transforms)>;
|
||||
|
||||
void BKE_foreach_geometry_component_recursive(const GeometrySet &geometry_set,
|
||||
const ForeachGeometryCallbackConst &callback);
|
@@ -1364,7 +1364,6 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
||||
#define GEO_NODE_POINT_SCALE 1020
|
||||
#define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021
|
||||
#define GEO_NODE_POINTS_TO_VOLUME 1022
|
||||
#define GEO_NODE_COLLECTION_INFO 1023
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@@ -14,24 +14,19 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "BLI_listbase_wrapper.hh" /* TODO: Couldn't figure this out yet. */
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using blender::float3;
|
||||
using blender::float4x4;
|
||||
using blender::ListBaseWrapper;
|
||||
using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
using blender::StringRef;
|
||||
@@ -571,180 +566,6 @@ bool InstancesComponent::is_empty() const
|
||||
return transforms_.size() == 0;
|
||||
}
|
||||
|
||||
static GeometrySet object_get_geometry_set_for_read(const Object &object)
|
||||
{
|
||||
/* Objects evaluated with a nodes modifier will have a geometry set already. */
|
||||
if (object.runtime.geometry_set_eval != nullptr) {
|
||||
return *object.runtime.geometry_set_eval;
|
||||
}
|
||||
|
||||
/* Otherwise, construct a new geometry set with the component based on the object type. */
|
||||
GeometrySet new_geometry_set;
|
||||
|
||||
if (object.type == OB_MESH) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(
|
||||
&const_cast<Object &>(object), false);
|
||||
|
||||
if (mesh != nullptr) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
|
||||
MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
||||
mesh_component.copy_vertex_group_names_from_object(object);
|
||||
}
|
||||
}
|
||||
// else if (object.type == OB_VOLUME) {
|
||||
// Volume *volume = BKE_modifier_get_volume...
|
||||
// }
|
||||
|
||||
/* Return by value since there is no existing geometry set owned elsewhere to use. */
|
||||
return new_geometry_set;
|
||||
}
|
||||
|
||||
static void foreach_geometry_component_recursive(const GeometrySet &geometry_set,
|
||||
const ForeachGeometryCallbackConst &callback,
|
||||
const float4x4 &transform);
|
||||
|
||||
static void foreach_collection_geometry_set_recursive(const Collection &collection,
|
||||
const ForeachGeometryCallbackConst &callback,
|
||||
const float4x4 &transform)
|
||||
{
|
||||
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
|
||||
BLI_assert(collection_object->ob != nullptr);
|
||||
const Object &object = *collection_object->ob;
|
||||
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
||||
|
||||
/* TODO: This seems to work-- validate this. */
|
||||
const float4x4 instance_transform = transform * object.obmat;
|
||||
foreach_geometry_component_recursive(instance_geometry_set, callback, instance_transform);
|
||||
}
|
||||
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
|
||||
BLI_assert(collection_child->collection != nullptr);
|
||||
const Collection &collection = *collection_child->collection;
|
||||
foreach_collection_geometry_set_recursive(collection, callback, transform);
|
||||
}
|
||||
}
|
||||
|
||||
static void foreach_geometry_component_recursive(const GeometrySet &geometry_set,
|
||||
const ForeachGeometryCallbackConst &callback,
|
||||
const float4x4 &transform)
|
||||
{
|
||||
if (geometry_set.has_mesh()) {
|
||||
callback(*geometry_set.get_component_for_read<MeshComponent>(), {transform});
|
||||
}
|
||||
if (geometry_set.has_pointcloud()) {
|
||||
callback(*geometry_set.get_component_for_read<PointCloudComponent>(), {transform});
|
||||
}
|
||||
if (geometry_set.has_volume()) {
|
||||
callback(*geometry_set.get_component_for_read<VolumeComponent>(), {transform});
|
||||
}
|
||||
|
||||
if (geometry_set.has_instances()) {
|
||||
const InstancesComponent &instances_component =
|
||||
*geometry_set.get_component_for_read<InstancesComponent>();
|
||||
|
||||
Span<float4x4> transforms = instances_component.transforms();
|
||||
Span<InstancedData> instances = instances_component.instanced_data();
|
||||
for (const int i : instances.index_range()) {
|
||||
const InstancedData &data = instances[i];
|
||||
const float4x4 &transform = transforms[i];
|
||||
|
||||
if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
|
||||
BLI_assert(data.data.object != nullptr);
|
||||
const Object &object = *data.data.object;
|
||||
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
||||
foreach_geometry_component_recursive(instance_geometry_set, callback, transform);
|
||||
}
|
||||
else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
|
||||
BLI_assert(data.data.collection != nullptr);
|
||||
const Collection &collection = *data.data.collection;
|
||||
foreach_collection_geometry_set_recursive(collection, callback, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_foreach_geometry_component_recursive(const GeometrySet &geometry_set,
|
||||
const ForeachGeometryCallbackConst &callback)
|
||||
{
|
||||
float4x4 unit_transform;
|
||||
unit_m4(unit_transform.values);
|
||||
|
||||
foreach_geometry_component_recursive(geometry_set, callback, unit_transform);
|
||||
}
|
||||
|
||||
/* ============= API 2 =============== */
|
||||
|
||||
using GeometrySetGroup = std::pair<GeometrySet, Vector<float4x4>>;
|
||||
|
||||
static void collect_geometry_set_recursive(
|
||||
const GeometrySet &geometry_set,
|
||||
const float4x4 &transform,
|
||||
Vector<std::pair<GeometrySet, Vector<float4x4>>> &r_sets);
|
||||
|
||||
static void collect_collection_geometry_set_recursive(const Collection &collection,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometrySetGroup> &r_sets)
|
||||
{
|
||||
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
|
||||
BLI_assert(collection_object->ob != nullptr);
|
||||
const Object &object = *collection_object->ob;
|
||||
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
||||
|
||||
/* TODO: This seems to work-- validate this. */
|
||||
const float4x4 instance_transform = transform * object.obmat;
|
||||
collect_geometry_set_recursive(instance_geometry_set, instance_transform, r_sets);
|
||||
}
|
||||
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
|
||||
BLI_assert(collection_child->collection != nullptr);
|
||||
const Collection &collection = *collection_child->collection;
|
||||
collect_collection_geometry_set_recursive(collection, transform, r_sets);
|
||||
}
|
||||
}
|
||||
|
||||
static void collect_geometry_set_recursive(const GeometrySet &geometry_set,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometrySetGroup> &r_sets)
|
||||
{
|
||||
r_sets.append({geometry_set, {transform}});
|
||||
|
||||
if (geometry_set.has_instances()) {
|
||||
const InstancesComponent &instances_component =
|
||||
*geometry_set.get_component_for_read<InstancesComponent>();
|
||||
|
||||
Span<float4x4> transforms = instances_component.transforms();
|
||||
Span<InstancedData> instances = instances_component.instanced_data();
|
||||
for (const int i : instances.index_range()) {
|
||||
const InstancedData &data = instances[i];
|
||||
const float4x4 &transform = transforms[i];
|
||||
|
||||
if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
|
||||
BLI_assert(data.data.object != nullptr);
|
||||
const Object &object = *data.data.object;
|
||||
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
||||
collect_geometry_set_recursive(instance_geometry_set, transform, r_sets);
|
||||
}
|
||||
else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
|
||||
BLI_assert(data.data.collection != nullptr);
|
||||
const Collection &collection = *data.data.collection;
|
||||
collect_collection_geometry_set_recursive(collection, transform, r_sets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<GeometrySetGroup> BKE_geometry_set_gather_instanced(const GeometrySet &geometry_set)
|
||||
{
|
||||
Vector<GeometrySetGroup> result_vector;
|
||||
|
||||
float4x4 unit_transform;
|
||||
unit_m4(unit_transform.values);
|
||||
|
||||
collect_geometry_set_recursive(geometry_set, unit_transform, result_vector);
|
||||
|
||||
return result_vector;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -3549,9 +3549,6 @@ void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available)
|
||||
int nodeSocketLinkLimit(const bNodeSocket *sock)
|
||||
{
|
||||
bNodeSocketType *stype = sock->typeinfo;
|
||||
if (sock->flag & SOCK_MULTI_INPUT) {
|
||||
return 4095;
|
||||
}
|
||||
if (stype != nullptr && stype->use_link_limits_of_type) {
|
||||
int limit = (sock->in_out == SOCK_IN) ? stype->input_link_limit : stype->output_link_limit;
|
||||
return limit;
|
||||
@@ -4773,7 +4770,6 @@ static void registerGeometryNodes()
|
||||
register_node_type_geo_align_rotation_to_vector();
|
||||
register_node_type_geo_sample_texture();
|
||||
register_node_type_geo_points_to_volume();
|
||||
register_node_type_geo_collection_info();
|
||||
}
|
||||
|
||||
static void registerFunctionNodes()
|
||||
|
@@ -197,7 +197,6 @@ set(LIB
|
||||
|
||||
data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/common_utiltex_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lights_lib.glsl SRC)
|
||||
@@ -215,7 +214,12 @@ data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lookdev_world_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_lit_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_diffuse_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_glossy_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_refraction_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_translucent_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_type_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_dof_vert.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
|
||||
|
@@ -191,6 +191,12 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
|
||||
DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
|
||||
@@ -198,7 +204,6 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
|
||||
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
|
||||
DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
|
||||
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
|
||||
}
|
||||
|
||||
|
@@ -142,7 +142,6 @@ static struct {
|
||||
struct GPUShader *volumetric_accum_sh;
|
||||
|
||||
/* Shader strings */
|
||||
char *closure_lit_lib;
|
||||
char *surface_lit_frag;
|
||||
char *surface_prepass_frag;
|
||||
char *surface_geom_barycentric;
|
||||
@@ -184,7 +183,7 @@ extern char datatoc_bsdf_common_lib_glsl[];
|
||||
extern char datatoc_bsdf_lut_frag_glsl[];
|
||||
extern char datatoc_bsdf_sampling_lib_glsl[];
|
||||
extern char datatoc_btdf_lut_frag_glsl[];
|
||||
extern char datatoc_closure_lib_glsl[];
|
||||
extern char datatoc_closure_type_lib_glsl[];
|
||||
extern char datatoc_common_uniforms_lib_glsl[];
|
||||
extern char datatoc_common_utiltex_lib_glsl[];
|
||||
extern char datatoc_cryptomatte_frag_glsl[];
|
||||
@@ -224,7 +223,11 @@ extern char datatoc_lightprobe_planar_downsample_geom_glsl[];
|
||||
extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
|
||||
extern char datatoc_lightprobe_vert_glsl[];
|
||||
extern char datatoc_lights_lib_glsl[];
|
||||
extern char datatoc_closure_lit_lib_glsl[];
|
||||
extern char datatoc_closure_eval_lib_glsl[];
|
||||
extern char datatoc_closure_eval_diffuse_lib_glsl[];
|
||||
extern char datatoc_closure_eval_glossy_lib_glsl[];
|
||||
extern char datatoc_closure_eval_refraction_lib_glsl[];
|
||||
extern char datatoc_closure_eval_translucent_lib_glsl[];
|
||||
extern char datatoc_ltc_lib_glsl[];
|
||||
extern char datatoc_object_motion_frag_glsl[];
|
||||
extern char datatoc_object_motion_vert_glsl[];
|
||||
@@ -279,23 +282,13 @@ static void eevee_shader_library_ensure(void)
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, lights_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, surface_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, volumetric_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
|
||||
|
||||
/* Add one for each Closure */
|
||||
e_data.closure_lit_lib = BLI_string_joinN(datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl);
|
||||
|
||||
DRW_shader_library_add_file(e_data.lib, e_data.closure_lit_lib, "closure_lit_lib.glsl");
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_type_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_diffuse_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_glossy_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_translucent_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib);
|
||||
|
||||
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
|
||||
datatoc_surface_frag_glsl);
|
||||
@@ -1403,7 +1396,6 @@ struct GPUMaterial *EEVEE_material_get(
|
||||
|
||||
void EEVEE_shaders_free(void)
|
||||
{
|
||||
MEM_SAFE_FREE(e_data.closure_lit_lib);
|
||||
MEM_SAFE_FREE(e_data.surface_prepass_frag);
|
||||
MEM_SAFE_FREE(e_data.surface_lit_frag);
|
||||
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
|
||||
|
@@ -191,15 +191,15 @@ void gtao_deferred(
|
||||
dirs.xy = get_ao_dir(noise.x * 0.5);
|
||||
dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
|
||||
|
||||
bent_normal = normal * 1e-8;
|
||||
visibility = 1e-8;
|
||||
bent_normal = vec3(0.0);
|
||||
visibility = 0.0;
|
||||
|
||||
horizons = unpack_horizons(horizons);
|
||||
|
||||
integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal);
|
||||
integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal);
|
||||
|
||||
bent_normal = normalize(bent_normal / visibility);
|
||||
bent_normal = safe_normalize(bent_normal);
|
||||
|
||||
visibility *= 0.5; /* We integrated 2 slices. */
|
||||
}
|
||||
@@ -240,13 +240,24 @@ float gtao_multibounce(float visibility, vec3 albedo)
|
||||
return max(x, ((x * a + b) * x + c) * x);
|
||||
}
|
||||
|
||||
float diffuse_occlusion(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos, vec3 albedo)
|
||||
{
|
||||
if ((int(aoSettings) & USE_AO) == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
/* If the shading normal is orthogonal to the geometric normal, it should be half lit. */
|
||||
float horizon_fac = saturate(dot(N, vis_cone_dir) * 0.5 + 0.5);
|
||||
float ao = vis_cone_aperture_cos * horizon_fac;
|
||||
return gtao_multibounce(ao, albedo);
|
||||
}
|
||||
|
||||
float specular_occlusion(float NV, float AO, float roughness)
|
||||
{
|
||||
return saturate(pow(NV + AO, roughness) - 1.0 + AO);
|
||||
}
|
||||
|
||||
/* Use the right occlusion */
|
||||
float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal)
|
||||
float occlusion_compute(vec3 N, vec3 vpos, vec4 rand, out vec3 bent_normal)
|
||||
{
|
||||
#ifndef USE_REFRACTION
|
||||
if ((int(aoSettings) & USE_AO) != 0) {
|
||||
@@ -263,10 +274,6 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out
|
||||
visibility = max(1e-3, visibility);
|
||||
|
||||
if ((int(aoSettings) & USE_BENT_NORMAL) != 0) {
|
||||
/* The bent normal will show the facet look of the mesh. Try to minimize this. */
|
||||
float mix_fac = visibility * visibility * visibility;
|
||||
bent_normal = normalize(mix(bent_normal, vnor, mix_fac));
|
||||
|
||||
bent_normal = transform_direction(ViewMatrixInverse, bent_normal);
|
||||
}
|
||||
else {
|
||||
@@ -276,10 +283,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out
|
||||
/* Scale by user factor */
|
||||
visibility = pow(visibility, aoFactor);
|
||||
|
||||
return min(visibility, user_occlusion);
|
||||
return visibility;
|
||||
}
|
||||
#endif
|
||||
|
||||
bent_normal = N;
|
||||
return user_occlusion;
|
||||
return 1.0;
|
||||
}
|
||||
|
@@ -1,6 +1,15 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
|
||||
vec3 diffuse_dominant_dir(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos)
|
||||
{
|
||||
/* TODO(fclem) revisit this. bent too much towards vis_cone_dir. */
|
||||
vis_cone_aperture_cos *= sqr(vis_cone_aperture_cos);
|
||||
|
||||
N = mix(vis_cone_dir, N, vis_cone_aperture_cos);
|
||||
return normalize(N);
|
||||
}
|
||||
|
||||
vec3 specular_dominant_dir(vec3 N, vec3 V, float roughness)
|
||||
{
|
||||
vec3 R = -reflect(V, N);
|
||||
@@ -79,7 +88,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
{
|
||||
/* Unreal specular matching : if specular color is below 2% intensity,
|
||||
* treat as shadowning */
|
||||
return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * abs(f90) + lut.x * f0;
|
||||
return lut.y * f90 + lut.x * f0;
|
||||
}
|
||||
|
||||
/* Multi-scattering brdf approximation from :
|
||||
@@ -87,11 +96,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
* by Carmelo J. Fdez-Agüera. */
|
||||
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
{
|
||||
vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
|
||||
/* Hack to avoid many more shader variations. */
|
||||
if (f90.g < 0.0) {
|
||||
return FssEss;
|
||||
}
|
||||
vec3 FssEss = lut.y * f90 + lut.x * f0;
|
||||
|
||||
float Ess = lut.x + lut.y;
|
||||
float Ems = 1.0 - Ess;
|
||||
@@ -102,8 +107,6 @@ vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
return FssEss + Fms * Ems;
|
||||
}
|
||||
|
||||
#define F_brdf(f0, f90, lut) F_brdf_multi_scatter(f0, f90, lut)
|
||||
|
||||
/* GGX */
|
||||
float D_ggx_opti(float NH, float a2)
|
||||
{
|
||||
|
@@ -0,0 +1,85 @@
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
|
||||
struct ClosureInputDiffuse {
|
||||
vec3 N; /** Shading normal. */
|
||||
vec3 albedo; /** Used for multibounce GTAO approximation. Not applied to final radiance. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Diffuse_DEFAULT ClosureInputDiffuse(vec3(0.0), vec3(0.0))
|
||||
|
||||
struct ClosureEvalDiffuse {
|
||||
vec3 probe_sampling_dir; /** Direction to sample probes from. */
|
||||
float ambient_occlusion; /** Final occlusion for distant lighting. */
|
||||
};
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureOutputDiffuse ClosureOutput
|
||||
#define closure_Diffuse_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Diffuse_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
ClosureEvalDiffuse closure_Diffuse_eval_init(inout ClosureInputDiffuse cl_in,
|
||||
ClosureEvalCommon cl_common,
|
||||
out ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
|
||||
ClosureEvalDiffuse cl_eval;
|
||||
cl_eval.ambient_occlusion = diffuse_occlusion(
|
||||
cl_in.N, cl_common.bent_normal, cl_common.occlusion, cl_in.albedo);
|
||||
cl_eval.probe_sampling_dir = diffuse_dominant_dir(
|
||||
cl_in.N, cl_common.bent_normal, cl_common.occlusion);
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
void closure_Diffuse_light_eval(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L);
|
||||
/* TODO(fclem) We could try to shadow lights that are shadowless with the ambient_occlusion
|
||||
* factor here. */
|
||||
cl_out.radiance += light.data.l_color * (light.vis * light.contact_shadow * radiance);
|
||||
}
|
||||
|
||||
void closure_Diffuse_grid_eval(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureGridData grid,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_grid(
|
||||
grid.data, cl_common.P, cl_eval.probe_sampling_dir, grid.local_pos);
|
||||
cl_out.radiance += grid.attenuation * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Diffuse_indirect_end(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (cl_common.diffuse_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_diff(cl_eval.probe_sampling_dir);
|
||||
cl_out.radiance += cl_common.diffuse_accum * probe_radiance;
|
||||
}
|
||||
/* Apply occlusion on radiance before the light loop. */
|
||||
cl_out.radiance *= cl_eval.ambient_occlusion;
|
||||
}
|
||||
|
||||
void closure_Diffuse_eval_end(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
|
||||
struct ClosureInputGlossy {
|
||||
vec3 N; /** Shading normal. */
|
||||
float roughness; /** Input roughness, not squared. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Glossy_DEFAULT ClosureInputGlossy(vec3(0.0), 0.0)
|
||||
|
||||
struct ClosureEvalGlossy {
|
||||
vec4 ltc_mat; /** LTC matrix values. */
|
||||
float ltc_brdf_scale; /** LTC BRDF scaling. */
|
||||
vec3 probe_sampling_dir; /** Direction to sample probes from. */
|
||||
float spec_occlusion; /** Specular Occlusion. */
|
||||
vec3 raytrace_radiance; /** Raytrace reflection to be accumulated after occlusion. */
|
||||
};
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureOutputGlossy ClosureOutput
|
||||
#define closure_Glossy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
#ifdef STEP_RESOLVE /* SSR */
|
||||
/* Prototype. */
|
||||
void raytrace_resolve(ClosureInputGlossy cl_in,
|
||||
inout ClosureEvalGlossy cl_eval,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out);
|
||||
#endif
|
||||
|
||||
ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
out ClosureOutputGlossy cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
|
||||
float NV = dot(cl_in.N, cl_common.V);
|
||||
vec2 lut_uv = lut_coords_ltc(NV, cl_in.roughness);
|
||||
|
||||
ClosureEvalGlossy cl_eval;
|
||||
cl_eval.ltc_mat = texture(utilTex, vec3(lut_uv, LTC_MAT_LAYER));
|
||||
cl_eval.probe_sampling_dir = specular_dominant_dir(cl_in.N, cl_common.V, sqr(cl_in.roughness));
|
||||
cl_eval.spec_occlusion = specular_occlusion(NV, cl_common.occlusion, cl_in.roughness);
|
||||
cl_eval.raytrace_radiance = vec3(0.0);
|
||||
|
||||
#ifdef STEP_RESOLVE /* SSR */
|
||||
raytrace_resolve(cl_in, cl_eval, cl_common, cl_out);
|
||||
#endif
|
||||
|
||||
/* The brdf split sum LUT is applied after the radiance accumulation.
|
||||
* Correct the LTC so that its energy is constant. */
|
||||
/* TODO(fclem) Optimize this so that only one scale factor is stored. */
|
||||
vec4 ltc_brdf = texture(utilTex, vec3(lut_uv, LTC_BRDF_LAYER)).barg;
|
||||
vec2 split_sum_brdf = ltc_brdf.zw;
|
||||
cl_eval.ltc_brdf_scale = (ltc_brdf.x + ltc_brdf.y) / (split_sum_brdf.x + split_sum_brdf.y);
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
void closure_Glossy_light_eval(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
float radiance = light_specular(light.data, cl_eval.ltc_mat, cl_in.N, cl_common.V, light.L);
|
||||
radiance *= cl_eval.ltc_brdf_scale;
|
||||
cl_out.radiance += light.data.l_color *
|
||||
(light.data.l_spec * light.vis * light.contact_shadow * radiance);
|
||||
}
|
||||
|
||||
void closure_Glossy_planar_eval(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
ClosurePlanarData planar,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
#ifndef STEP_RESOLVE /* SSR already evaluates planar reflections. */
|
||||
vec3 probe_radiance = probe_evaluate_planar(
|
||||
planar.id, planar.data, cl_common.P, cl_in.N, cl_common.V, cl_in.roughness);
|
||||
cl_out.radiance += planar.attenuation * probe_radiance;
|
||||
#else
|
||||
/* HACK: Fix an issue with planar reflections still being counted inside the specular
|
||||
* accumulator. This only works because we only use one Glossy closure in the resolve pass. */
|
||||
cl_common.specular_accum += planar.attenuation;
|
||||
#endif
|
||||
}
|
||||
|
||||
void closure_Glossy_cubemap_eval(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureCubemapData cube,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_cube(
|
||||
cube.id, cl_common.P, cl_eval.probe_sampling_dir, cl_in.roughness);
|
||||
cl_out.radiance += cube.attenuation * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Glossy_indirect_end(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (specToggle && cl_common.specular_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir, cl_in.roughness);
|
||||
cl_out.radiance += cl_common.specular_accum * probe_radiance;
|
||||
}
|
||||
|
||||
/* Apply occlusion on distant lighting. */
|
||||
cl_out.radiance *= cl_eval.spec_occlusion;
|
||||
/* Apply Raytrace reflections after occlusion since they are direct, local reflections. */
|
||||
cl_out.radiance += cl_eval.raytrace_radiance;
|
||||
}
|
||||
|
||||
void closure_Glossy_eval_end(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!specToggle) {
|
||||
cl_out.radiance = vec3(0.0);
|
||||
}
|
||||
}
|
316
source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
Normal file
316
source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
Normal file
@@ -0,0 +1,316 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
|
||||
/**
|
||||
* Extensive use of Macros to be able to change the maximum amount of evaluated closure easily.
|
||||
* NOTE: GLSL does not support variadic macros.
|
||||
*
|
||||
* Example
|
||||
* // Declare the cl_eval function
|
||||
* CLOSURE_EVAL_FUNCTION_DECLARE_3(name, Diffuse, Glossy, Refraction);
|
||||
* // Declare the inputs & outputs
|
||||
* CLOSURE_VARS_DECLARE(Diffuse, Glossy, Refraction);
|
||||
* // Specify inputs
|
||||
* in_Diffuse_0.N = N;
|
||||
* ...
|
||||
* // Call the cl_eval function
|
||||
* CLOSURE_EVAL_FUNCTION_3(name, Diffuse, Glossy, Refraction);
|
||||
* // Get the cl_out
|
||||
* closure.radiance = out_Diffuse_0.radiance + out_Glossy_1.radiance + out_Refraction_2.radiance;
|
||||
**/
|
||||
|
||||
#define CLOSURE_VARS_DECLARE(t0, t1, t2, t3) \
|
||||
ClosureInputCommon in_common = CLOSURE_INPUT_COMMON_DEFAULT; \
|
||||
ClosureInput##t0 in_##t0##_0 = CLOSURE_INPUT_##t0##_DEFAULT; \
|
||||
ClosureInput##t1 in_##t1##_1 = CLOSURE_INPUT_##t1##_DEFAULT; \
|
||||
ClosureInput##t2 in_##t2##_2 = CLOSURE_INPUT_##t2##_DEFAULT; \
|
||||
ClosureInput##t3 in_##t3##_3 = CLOSURE_INPUT_##t3##_DEFAULT; \
|
||||
ClosureOutput##t0 out_##t0##_0; \
|
||||
ClosureOutput##t1 out_##t1##_1; \
|
||||
ClosureOutput##t2 out_##t2##_2; \
|
||||
ClosureOutput##t3 out_##t3##_3;
|
||||
|
||||
#define CLOSURE_EVAL_DECLARE(t0, t1, t2, t3) \
|
||||
ClosureEvalCommon cl_common = closure_Common_eval_init(in_common); \
|
||||
ClosureEval##t0 eval_##t0##_0 = closure_##t0##_eval_init(in_##t0##_0, cl_common, out_##t0##_0); \
|
||||
ClosureEval##t1 eval_##t1##_1 = closure_##t1##_eval_init(in_##t1##_1, cl_common, out_##t1##_1); \
|
||||
ClosureEval##t2 eval_##t2##_2 = closure_##t2##_eval_init(in_##t2##_2, cl_common, out_##t2##_2); \
|
||||
ClosureEval##t3 eval_##t3##_3 = closure_##t3##_eval_init(in_##t3##_3, cl_common, out_##t3##_3);
|
||||
|
||||
#define CLOSURE_META_SUBROUTINE(subroutine, t0, t1, t2, t3) \
|
||||
closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, out_##t0##_0); \
|
||||
closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, out_##t1##_1); \
|
||||
closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, out_##t2##_2); \
|
||||
closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, out_##t3##_3);
|
||||
|
||||
#define CLOSURE_META_SUBROUTINE_DATA(subroutine, sub_data, t0, t1, t2, t3) \
|
||||
closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, sub_data, out_##t0##_0); \
|
||||
closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, sub_data, out_##t1##_1); \
|
||||
closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, sub_data, out_##t2##_2); \
|
||||
closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, sub_data, out_##t3##_3);
|
||||
|
||||
/* Inputs are inout so that callers can get the final inputs used for evaluation. */
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
|
||||
void closure_##name##_eval(ClosureInputCommon in_common, \
|
||||
inout ClosureInput##t0 in_##t0##_0, \
|
||||
inout ClosureInput##t1 in_##t1##_1, \
|
||||
inout ClosureInput##t2 in_##t2##_2, \
|
||||
inout ClosureInput##t3 in_##t3##_3, \
|
||||
out ClosureOutput##t0 out_##t0##_0, \
|
||||
out ClosureOutput##t1 out_##t1##_1, \
|
||||
out ClosureOutput##t2 out_##t2##_2, \
|
||||
out ClosureOutput##t3 out_##t3##_3) \
|
||||
{ \
|
||||
CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
|
||||
\
|
||||
for (int i = 0; cl_common.specular_accum > 0.0 && i < prbNumPlanar && i < MAX_PLANAR; i++) { \
|
||||
ClosurePlanarData planar = closure_planar_eval_init(i, cl_common); \
|
||||
if (planar.attenuation > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Starts at 1 because 0 is world cubemap. */ \
|
||||
for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \
|
||||
i++) { \
|
||||
ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \
|
||||
if (cube.attenuation > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Starts at 1 because 0 is world irradiance. */ \
|
||||
for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; i++) { \
|
||||
ClosureGridData grid = closure_grid_eval_init(i, cl_common); \
|
||||
if (grid.attenuation > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \
|
||||
\
|
||||
for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \
|
||||
ClosureLightData light = closure_light_eval_init(cl_common, i); \
|
||||
if (light.vis > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \
|
||||
}
|
||||
|
||||
#define CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) \
|
||||
closure_##name##_eval(in_common, \
|
||||
in_##t0##_0, \
|
||||
in_##t1##_1, \
|
||||
in_##t2##_2, \
|
||||
in_##t3##_3, \
|
||||
out_##t0##_0, \
|
||||
out_##t1##_1, \
|
||||
out_##t2##_2, \
|
||||
out_##t3##_3)
|
||||
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_1(name, t0) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, Dummy, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_2(name, t0, t1) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_3(name, t0, t1, t2) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_4(name, t0, t1, t2, t3) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3)
|
||||
|
||||
#define CLOSURE_VARS_DECLARE_1(t0) CLOSURE_VARS_DECLARE(t0, Dummy, Dummy, Dummy)
|
||||
#define CLOSURE_VARS_DECLARE_2(t0, t1) CLOSURE_VARS_DECLARE(t0, t1, Dummy, Dummy)
|
||||
#define CLOSURE_VARS_DECLARE_3(t0, t1, t2) CLOSURE_VARS_DECLARE(t0, t1, t2, Dummy)
|
||||
#define CLOSURE_VARS_DECLARE_4(t0, t1, t2, t3) CLOSURE_VARS_DECLARE(t0, t1, t2, t3)
|
||||
|
||||
#define CLOSURE_EVAL_FUNCTION_1(name, t0) CLOSURE_EVAL_FUNCTION(name, t0, Dummy, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_2(name, t0, t1) CLOSURE_EVAL_FUNCTION(name, t0, t1, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_3(name, t0, t1, t2) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_4(name, t0, t1, t2, t3) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Dummy Closure
|
||||
*
|
||||
* Dummy closure type that will be optimized out by the compiler.
|
||||
* \{ */
|
||||
|
||||
#define ClosureInputDummy ClosureOutput
|
||||
#define ClosureOutputDummy ClosureOutput
|
||||
#define ClosureEvalDummy ClosureOutput
|
||||
#define CLOSURE_EVAL_DUMMY ClosureOutput(vec3(0))
|
||||
#define CLOSURE_INPUT_Dummy_DEFAULT CLOSURE_EVAL_DUMMY
|
||||
#define closure_Dummy_eval_init(cl_in, cl_common, cl_out) CLOSURE_EVAL_DUMMY
|
||||
#define closure_Dummy_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_indirect_end(cl_in, cl_eval, cl_common, cl_out)
|
||||
#define closure_Dummy_light_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_eval_end(cl_in, cl_eval, cl_common, cl_out)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Common cl_eval data
|
||||
*
|
||||
* Eval data not dependant on input parameters. All might not be used but unused ones
|
||||
* will be optimized out.
|
||||
* \{ */
|
||||
|
||||
struct ClosureInputCommon {
|
||||
/** Custom occlusion value set by the user. */
|
||||
float occlusion;
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_COMMON_DEFAULT ClosureInputCommon(1.0)
|
||||
|
||||
struct ClosureEvalCommon {
|
||||
/** View vector. */
|
||||
vec3 V;
|
||||
/** Surface position. */
|
||||
vec3 P;
|
||||
/** Normal vector, always facing camera. */
|
||||
vec3 N;
|
||||
/** Normal vector, always facing camera. (viewspace) */
|
||||
vec3 vN;
|
||||
/** Surface position. (viewspace) */
|
||||
vec3 vP;
|
||||
/** Geometric normal, always facing camera. (viewspace) */
|
||||
vec3 vNg;
|
||||
/** Random numbers. 3 random sequences. zw is a random point on a circle. */
|
||||
vec4 rand;
|
||||
/** Final occlusion factor. Mix of the user occlusion and SSAO. */
|
||||
float occlusion;
|
||||
/** Least occluded direction in the hemisphere. */
|
||||
vec3 bent_normal;
|
||||
|
||||
/** Specular probe accumulator. Shared between planar and cubemap probe. */
|
||||
float specular_accum;
|
||||
/** Diffuse probe accumulator. */
|
||||
float diffuse_accum;
|
||||
/** Viewspace depth to start raytracing from. */
|
||||
float tracing_depth;
|
||||
};
|
||||
|
||||
/* Common cl_out struct used by most closures. */
|
||||
struct ClosureOutput {
|
||||
vec3 radiance;
|
||||
};
|
||||
|
||||
ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in)
|
||||
{
|
||||
ClosureEvalCommon cl_eval;
|
||||
cl_eval.rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
cl_eval.V = cameraVec;
|
||||
cl_eval.P = worldPosition;
|
||||
cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal);
|
||||
cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal);
|
||||
cl_eval.vP = viewPosition;
|
||||
cl_eval.vNg = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
/* TODO(fclem) See if we can avoid this complicated setup. */
|
||||
cl_eval.tracing_depth = gl_FragCoord.z;
|
||||
/* Constant bias (due to depth buffer precision) */
|
||||
/* Magic numbers for 24bits of precision.
|
||||
* From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
|
||||
cl_eval.tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
|
||||
/* Convert to view Z. */
|
||||
cl_eval.tracing_depth = get_view_z_from_depth(cl_eval.tracing_depth);
|
||||
|
||||
/* TODO(fclem) Do occlusion evaluation per Closure using shading normal. */
|
||||
cl_eval.occlusion = min(
|
||||
cl_in.occlusion,
|
||||
occlusion_compute(cl_eval.N, cl_eval.vP, cl_eval.rand, cl_eval.bent_normal));
|
||||
|
||||
cl_eval.specular_accum = 1.0;
|
||||
cl_eval.diffuse_accum = 1.0;
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Loop data
|
||||
*
|
||||
* Loop datas are conveniently packed into struct to make it future proof.
|
||||
* \{ */
|
||||
|
||||
struct ClosureLightData {
|
||||
LightData data; /** Light Data. */
|
||||
vec4 L; /** Non-Normalized Light Vector (surface to light) with length in W component. */
|
||||
float vis; /** Light visibility. */
|
||||
float contact_shadow; /** Result of contact shadow tracing. */
|
||||
};
|
||||
|
||||
ClosureLightData closure_light_eval_init(ClosureEvalCommon cl_common, int light_id)
|
||||
{
|
||||
ClosureLightData light;
|
||||
light.data = lights_data[light_id];
|
||||
|
||||
light.L.xyz = light.data.l_position - cl_common.P;
|
||||
light.L.w = length(light.L.xyz);
|
||||
|
||||
light.vis = light_visibility(light.data, cl_common.P, light.L);
|
||||
light.contact_shadow = light_contact_shadows(light.data,
|
||||
cl_common.P,
|
||||
cl_common.vP,
|
||||
cl_common.tracing_depth,
|
||||
cl_common.vNg,
|
||||
cl_common.rand.x,
|
||||
light.vis);
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
struct ClosureCubemapData {
|
||||
int id; /** Probe id. */
|
||||
float attenuation; /** Attenuation. */
|
||||
};
|
||||
|
||||
ClosureCubemapData closure_cubemap_eval_init(int cube_id, inout ClosureEvalCommon cl_common)
|
||||
{
|
||||
ClosureCubemapData cube;
|
||||
cube.id = cube_id;
|
||||
cube.attenuation = probe_attenuation_cube(cube_id, cl_common.P);
|
||||
cube.attenuation = min(cube.attenuation, cl_common.specular_accum);
|
||||
cl_common.specular_accum -= cube.attenuation;
|
||||
return cube;
|
||||
}
|
||||
|
||||
struct ClosurePlanarData {
|
||||
int id; /** Probe id. */
|
||||
PlanarData data; /** planars_data[id]. */
|
||||
float attenuation; /** Attenuation. */
|
||||
};
|
||||
|
||||
ClosurePlanarData closure_planar_eval_init(int planar_id, inout ClosureEvalCommon cl_common)
|
||||
{
|
||||
ClosurePlanarData planar;
|
||||
planar.id = planar_id;
|
||||
planar.data = planars_data[planar_id];
|
||||
planar.attenuation = probe_attenuation_planar(planar.data, cl_common.P, cl_common.N, 0.0);
|
||||
planar.attenuation = min(planar.attenuation, cl_common.specular_accum);
|
||||
cl_common.specular_accum -= planar.attenuation;
|
||||
return planar;
|
||||
}
|
||||
|
||||
struct ClosureGridData {
|
||||
int id; /** Grid id. */
|
||||
GridData data; /** grids_data[id] */
|
||||
float attenuation; /** Attenuation. */
|
||||
vec3 local_pos; /** Local position inside the grid. */
|
||||
};
|
||||
|
||||
ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common)
|
||||
{
|
||||
ClosureGridData grid;
|
||||
grid.id = id;
|
||||
grid.data = grids_data[id];
|
||||
grid.attenuation = probe_attenuation_grid(grid.data, cl_common.P, grid.local_pos);
|
||||
grid.attenuation = min(grid.attenuation, cl_common.diffuse_accum);
|
||||
cl_common.diffuse_accum -= grid.attenuation;
|
||||
return grid;
|
||||
}
|
||||
|
||||
/** \} */
|
@@ -0,0 +1,128 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
||||
|
||||
struct ClosureInputRefraction {
|
||||
vec3 N; /** Shading normal. */
|
||||
float roughness; /** Input roughness, not squared. */
|
||||
float ior; /** Index of refraction ratio. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Refraction_DEFAULT ClosureInputRefraction(vec3(0.0), 0.0, 0.0)
|
||||
|
||||
struct ClosureEvalRefraction {
|
||||
vec3 P; /** LTC matrix values. */
|
||||
vec3 ltc_brdf; /** LTC BRDF values. */
|
||||
vec3 probe_sampling_dir; /** Direction to sample probes from. */
|
||||
float probes_weight; /** Factor to apply to probe radiance. */
|
||||
};
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureOutputRefraction ClosureOutput
|
||||
#define closure_Refraction_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
ClosureEvalRefraction closure_Refraction_eval_init(inout ClosureInputRefraction cl_in,
|
||||
ClosureEvalCommon cl_common,
|
||||
out ClosureOutputRefraction cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
|
||||
cl_in.ior = max(cl_in.ior, 1e-5);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
|
||||
ClosureEvalRefraction cl_eval;
|
||||
vec3 cl_V;
|
||||
float eval_ior;
|
||||
/* Refract the view vector using the depth heuristic.
|
||||
* Then later Refract a second time the already refracted
|
||||
* ray using the inverse ior. */
|
||||
if (refractionDepth > 0.0) {
|
||||
eval_ior = 1.0 / cl_in.ior;
|
||||
cl_V = -refract(-cl_common.V, cl_in.N, eval_ior);
|
||||
vec3 plane_pos = cl_common.P - cl_in.N * refractionDepth;
|
||||
cl_eval.P = line_plane_intersect(cl_common.P, cl_V, plane_pos, cl_in.N);
|
||||
}
|
||||
else {
|
||||
eval_ior = cl_in.ior;
|
||||
cl_V = cl_common.V;
|
||||
cl_eval.P = cl_common.P;
|
||||
}
|
||||
|
||||
cl_eval.probe_sampling_dir = refraction_dominant_dir(cl_in.N, cl_V, cl_in.roughness, eval_ior);
|
||||
cl_eval.probes_weight = 1.0;
|
||||
|
||||
#ifdef USE_REFRACTION
|
||||
if (ssrefractToggle && cl_in.roughness < ssrMaxRoughness + 0.2) {
|
||||
/* Find approximated position of the 2nd refraction event. */
|
||||
vec3 vP = (refractionDepth > 0.0) ? transform_point(ViewMatrix, cl_eval.P) : cl_common.vP;
|
||||
vec4 ssr_output = screen_space_refraction(
|
||||
vP, cl_in.N, cl_V, eval_ior, sqr(cl_in.roughness), cl_common.rand);
|
||||
ssr_output.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, cl_in.roughness);
|
||||
cl_out.radiance += ssr_output.rgb * ssr_output.a;
|
||||
cl_eval.probes_weight -= ssr_output.a;
|
||||
}
|
||||
#endif
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
void closure_Refraction_light_eval(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
/* Not implemented yet. */
|
||||
}
|
||||
|
||||
void closure_Refraction_planar_eval(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosurePlanarData planar,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
/* Not implemented yet. */
|
||||
}
|
||||
|
||||
void closure_Refraction_cubemap_eval(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureCubemapData cube,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_cube(
|
||||
cube.id, cl_eval.P, cl_eval.probe_sampling_dir, sqr(cl_in.roughness));
|
||||
cl_out.radiance += (cube.attenuation * cl_eval.probes_weight) * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Refraction_indirect_end(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (specToggle && cl_common.specular_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir,
|
||||
sqr(cl_in.roughness));
|
||||
cl_out.radiance += (cl_common.specular_accum * cl_eval.probes_weight) * probe_radiance;
|
||||
}
|
||||
}
|
||||
|
||||
void closure_Refraction_eval_end(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!specToggle) {
|
||||
cl_out.radiance = vec3(0.0);
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
|
||||
struct ClosureInputTranslucent {
|
||||
vec3 N; /** Shading normal. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Translucent_DEFAULT ClosureInputTranslucent(vec3(0.0))
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureEvalTranslucent ClosureEvalDummy
|
||||
#define ClosureOutputTranslucent ClosureOutput
|
||||
#define closure_Translucent_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Translucent_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
ClosureEvalTranslucent closure_Translucent_eval_init(inout ClosureInputTranslucent cl_in,
|
||||
ClosureEvalCommon cl_common,
|
||||
out ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return CLOSURE_EVAL_DUMMY;
|
||||
}
|
||||
|
||||
void closure_Translucent_light_eval(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L);
|
||||
cl_out.radiance += light.data.l_color * (light.vis * radiance);
|
||||
}
|
||||
|
||||
void closure_Translucent_grid_eval(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureGridData grid,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_grid(grid.data, cl_common.P, cl_in.N, grid.local_pos);
|
||||
cl_out.radiance += grid.attenuation * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Translucent_indirect_end(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (cl_common.diffuse_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_diff(cl_in.N);
|
||||
cl_out.radiance += cl_common.diffuse_accum * probe_radiance;
|
||||
}
|
||||
}
|
||||
|
||||
void closure_Translucent_eval_end(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
}
|
@@ -1,545 +0,0 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
||||
|
||||
/**
|
||||
* AUTO CONFIG
|
||||
* We include the file multiple times each time with a different configuration.
|
||||
* This leads to a lot of deadcode. Better idea would be to only generate the one needed.
|
||||
*/
|
||||
#if !defined(SURFACE_DEFAULT)
|
||||
# define SURFACE_DEFAULT
|
||||
# define CLOSURE_NAME eevee_closure_default
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_GLOSSY
|
||||
#endif /* SURFACE_DEFAULT */
|
||||
|
||||
#if !defined(SURFACE_DEFAULT_CLEARCOAT) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_DEFAULT_CLEARCOAT
|
||||
# define CLOSURE_NAME eevee_closure_default_clearcoat
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_CLEARCOAT
|
||||
#endif /* SURFACE_DEFAULT_CLEARCOAT */
|
||||
|
||||
#if !defined(SURFACE_PRINCIPLED) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_PRINCIPLED
|
||||
# define CLOSURE_NAME eevee_closure_principled
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_CLEARCOAT
|
||||
# define CLOSURE_REFRACTION
|
||||
# define CLOSURE_SUBSURFACE
|
||||
#endif /* SURFACE_PRINCIPLED */
|
||||
|
||||
#if !defined(SURFACE_CLEARCOAT) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_CLEARCOAT
|
||||
# define CLOSURE_NAME eevee_closure_clearcoat
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_CLEARCOAT
|
||||
#endif /* SURFACE_CLEARCOAT */
|
||||
|
||||
#if !defined(SURFACE_DIFFUSE) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_DIFFUSE
|
||||
# define CLOSURE_NAME eevee_closure_diffuse
|
||||
# define CLOSURE_DIFFUSE
|
||||
#endif /* SURFACE_DIFFUSE */
|
||||
|
||||
#if !defined(SURFACE_SUBSURFACE) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_SUBSURFACE
|
||||
# define CLOSURE_NAME eevee_closure_subsurface
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_SUBSURFACE
|
||||
#endif /* SURFACE_SUBSURFACE */
|
||||
|
||||
#if !defined(SURFACE_SKIN) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_SKIN
|
||||
# define CLOSURE_NAME eevee_closure_skin
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_SUBSURFACE
|
||||
# define CLOSURE_GLOSSY
|
||||
#endif /* SURFACE_SKIN */
|
||||
|
||||
#if !defined(SURFACE_GLOSSY) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_GLOSSY
|
||||
# define CLOSURE_NAME eevee_closure_glossy
|
||||
# define CLOSURE_GLOSSY
|
||||
#endif /* SURFACE_GLOSSY */
|
||||
|
||||
#if !defined(SURFACE_REFRACT) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_REFRACT
|
||||
# define CLOSURE_NAME eevee_closure_refraction
|
||||
# define CLOSURE_REFRACTION
|
||||
#endif /* SURFACE_REFRACT */
|
||||
|
||||
#if !defined(SURFACE_GLASS) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_GLASS
|
||||
# define CLOSURE_NAME eevee_closure_glass
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_REFRACTION
|
||||
#endif /* SURFACE_GLASS */
|
||||
|
||||
/* Safety : CLOSURE_CLEARCOAT implies CLOSURE_GLOSSY */
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
# ifndef CLOSURE_GLOSSY
|
||||
# define CLOSURE_GLOSSY
|
||||
# endif
|
||||
#endif /* CLOSURE_CLEARCOAT */
|
||||
|
||||
void CLOSURE_NAME(vec3 N
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
,
|
||||
vec3 albedo
|
||||
#endif
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
,
|
||||
vec3 f0,
|
||||
vec3 f90,
|
||||
int ssr_id
|
||||
#endif
|
||||
#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
|
||||
,
|
||||
float roughness
|
||||
#endif
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
,
|
||||
vec3 C_N,
|
||||
float C_intensity,
|
||||
float C_roughness
|
||||
#endif
|
||||
#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
|
||||
,
|
||||
float ao
|
||||
#endif
|
||||
#ifdef CLOSURE_SUBSURFACE
|
||||
,
|
||||
float sss_scale
|
||||
#endif
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
,
|
||||
float ior
|
||||
#endif
|
||||
,
|
||||
const bool use_contact_shadows
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
,
|
||||
out vec3 out_diff
|
||||
#endif
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
,
|
||||
out vec3 out_spec
|
||||
#endif
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
,
|
||||
out vec3 out_refr
|
||||
#endif
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
,
|
||||
out vec3 ssr_spec
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
out_diff = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
out_spec = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
out_refr = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
return;
|
||||
#else
|
||||
|
||||
/* Zero length vectors cause issues, see: T51979. */
|
||||
float len = length(N);
|
||||
if (isnan(len)) {
|
||||
return;
|
||||
}
|
||||
N /= len;
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
len = length(C_N);
|
||||
if (isnan(len)) {
|
||||
return;
|
||||
}
|
||||
C_N /= len;
|
||||
# endif
|
||||
|
||||
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
|
||||
roughness = clamp(roughness, 1e-8, 0.9999);
|
||||
float roughnessSquared = roughness * roughness;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
C_roughness = clamp(C_roughness, 1e-8, 0.9999);
|
||||
float C_roughnessSquared = C_roughness * C_roughness;
|
||||
# endif
|
||||
|
||||
vec3 V = cameraVec;
|
||||
|
||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* -------------------- SCENE LIGHTS LIGHTING --------------------- */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec2 lut_uv = lut_coords_ltc(dot(N, V), roughness);
|
||||
vec4 ltc_mat = texture(utilTex, vec3(lut_uv, 0.0)).rgba;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec2 lut_uv_clear = lut_coords_ltc(dot(C_N, V), C_roughness);
|
||||
vec4 ltc_mat_clear = texture(utilTex, vec3(lut_uv_clear, 0.0)).rgba;
|
||||
vec3 out_spec_clear = vec3(0.0);
|
||||
# endif
|
||||
|
||||
float tracing_depth = gl_FragCoord.z;
|
||||
/* Constant bias (due to depth buffer precision) */
|
||||
/* Magic numbers for 24bits of precision.
|
||||
* From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
|
||||
tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
|
||||
/* Convert to view Z. */
|
||||
tracing_depth = get_view_z_from_depth(tracing_depth);
|
||||
|
||||
vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
|
||||
for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
|
||||
LightData ld = lights_data[i];
|
||||
|
||||
vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
|
||||
l_vector.xyz = ld.l_position - worldPosition;
|
||||
l_vector.w = length(l_vector.xyz);
|
||||
|
||||
float l_vis = light_visibility(ld,
|
||||
worldPosition,
|
||||
viewPosition,
|
||||
tracing_depth,
|
||||
true_normal,
|
||||
rand.x,
|
||||
use_contact_shadows,
|
||||
l_vector);
|
||||
|
||||
if (l_vis < 1e-8) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec3 l_color_vis = ld.l_color * l_vis;
|
||||
|
||||
# ifdef CLOSURE_DIFFUSE
|
||||
out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
out_spec_clear += l_color_vis * light_specular(ld, ltc_mat_clear, C_N, V, l_vector) *
|
||||
ld.l_spec;
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba;
|
||||
out_spec *= F_brdf(f0, f90, brdf_lut_lights.xy);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec2 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).ba;
|
||||
out_spec_clear *= F_brdf(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy);
|
||||
out_spec += out_spec_clear * C_intensity;
|
||||
# endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Accumulate incoming light from all sources until accumulator is full. Then apply Occlusion and
|
||||
* BRDF. */
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec4 spec_accum = vec4(0.0);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec4 C_spec_accum = vec4(0.0);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
vec4 refr_accum = vec4(0.0);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
/* ---------------------------- */
|
||||
/* Planar Reflections */
|
||||
/* ---------------------------- */
|
||||
|
||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; i++) {
|
||||
PlanarData pd = planars_data[i];
|
||||
|
||||
/* Fade on geometric normal. */
|
||||
float fade = probe_attenuation_planar(
|
||||
pd, worldPosition, (gl_FrontFacing) ? worldNormal : -worldNormal, roughness);
|
||||
|
||||
if (fade > 0.0) {
|
||||
if (!(ssrToggle && ssr_id == outputSsrId)) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, C_roughness, fade);
|
||||
accumulate_light(C_spec, fade, C_spec_accum);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec3 spec_dir = specular_dominant_dir(N, V, roughnessSquared);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec_dir = specular_dominant_dir(C_N, V, C_roughnessSquared);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
/* Refract the view vector using the depth heuristic.
|
||||
* Then later Refract a second time the already refracted
|
||||
* ray using the inverse ior. */
|
||||
float final_ior = (refractionDepth > 0.0) ? 1.0 / ior : ior;
|
||||
vec3 refr_V = (refractionDepth > 0.0) ? -refract(-V, N, final_ior) : V;
|
||||
vec3 refr_pos = (refractionDepth > 0.0) ?
|
||||
line_plane_intersect(
|
||||
worldPosition, refr_V, worldPosition - N * refractionDepth, N) :
|
||||
worldPosition;
|
||||
vec3 refr_dir = refraction_dominant_dir(N, refr_V, roughness, final_ior);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
/* ---------------------------- */
|
||||
/* Screen Space Refraction */
|
||||
/* ---------------------------- */
|
||||
# ifdef USE_REFRACTION
|
||||
if (ssrefractToggle && roughness < ssrMaxRoughness + 0.2) {
|
||||
/* Find approximated position of the 2nd refraction event. */
|
||||
vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) :
|
||||
viewPosition;
|
||||
vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand);
|
||||
trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
||||
accumulate_light(trans.rgb, trans.a, refr_accum);
|
||||
}
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Specular probes */
|
||||
/* ---------------------------- */
|
||||
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
|
||||
|
||||
# if defined(CLOSURE_GLOSSY) && defined(CLOSURE_REFRACTION)
|
||||
# define GLASS_ACCUM 1
|
||||
# define ACCUM min(refr_accum.a, spec_accum.a)
|
||||
# elif defined(CLOSURE_REFRACTION)
|
||||
# define GLASS_ACCUM 0
|
||||
# define ACCUM refr_accum.a
|
||||
# else
|
||||
# define GLASS_ACCUM 0
|
||||
# define ACCUM spec_accum.a
|
||||
# endif
|
||||
|
||||
/* Starts at 1 because 0 is world probe */
|
||||
for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; i++) {
|
||||
float fade = probe_attenuation_cube(i, worldPosition);
|
||||
|
||||
if (fade > 0.0) {
|
||||
|
||||
# if GLASS_ACCUM
|
||||
if (spec_accum.a < 0.999) {
|
||||
# endif
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
if (!(ssrToggle && ssr_id == outputSsrId)) {
|
||||
vec3 spec = probe_evaluate_cube(i, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec = probe_evaluate_cube(i, worldPosition, C_spec_dir, C_roughness);
|
||||
accumulate_light(C_spec, fade, C_spec_accum);
|
||||
# endif
|
||||
# if GLASS_ACCUM
|
||||
}
|
||||
# endif
|
||||
|
||||
# if GLASS_ACCUM
|
||||
if (refr_accum.a < 0.999) {
|
||||
# endif
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
vec3 trans = probe_evaluate_cube(i, refr_pos, refr_dir, roughnessSquared);
|
||||
accumulate_light(trans, fade, refr_accum);
|
||||
# endif
|
||||
# if GLASS_ACCUM
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
# undef GLASS_ACCUM
|
||||
# undef ACCUM
|
||||
|
||||
/* ---------------------------- */
|
||||
/* World Probe */
|
||||
/* ---------------------------- */
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
if (spec_accum.a < 0.999) {
|
||||
if (!(ssrToggle && ssr_id == outputSsrId)) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
}
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness);
|
||||
accumulate_light(C_spec, 1.0, C_spec_accum);
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
if (refr_accum.a < 0.999) {
|
||||
vec3 trans = probe_evaluate_world_spec(refr_dir, roughnessSquared);
|
||||
accumulate_light(trans, 1.0, refr_accum);
|
||||
}
|
||||
# endif
|
||||
# endif /* Specular probes */
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Ambient Occlusion */
|
||||
/* ---------------------------- */
|
||||
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
|
||||
if (!use_contact_shadows) {
|
||||
/* HACK: Fix for translucent BSDF. (see T65631) */
|
||||
N = -N;
|
||||
}
|
||||
vec3 bent_normal;
|
||||
float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal);
|
||||
if (!use_contact_shadows) {
|
||||
N = -N;
|
||||
/* Bypass bent normal. */
|
||||
bent_normal = N;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Specular Output */
|
||||
/* ---------------------------- */
|
||||
float NV = dot(N, V);
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec2 uv = lut_coords(NV, roughness);
|
||||
vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
|
||||
|
||||
/* This factor is outputted to be used by SSR in order
|
||||
* to match the intensity of the regular reflections. */
|
||||
ssr_spec = F_brdf(f0, f90, brdf_lut);
|
||||
float spec_occlu = specular_occlusion(NV, final_ao, roughness);
|
||||
|
||||
/* The SSR pass recompute the occlusion to not apply it to the SSR */
|
||||
if (ssrToggle && ssr_id == outputSsrId) {
|
||||
spec_occlu = 1.0;
|
||||
}
|
||||
|
||||
out_spec += spec_accum.rgb * ssr_spec * spec_occlu;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
float btdf = get_btdf_lut(NV, roughness, ior);
|
||||
|
||||
out_refr += refr_accum.rgb * btdf;
|
||||
|
||||
/* Global toggle for lightprobe baking. */
|
||||
out_refr *= float(specToggle);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
NV = dot(C_N, V);
|
||||
vec2 C_uv = lut_coords(NV, C_roughness);
|
||||
vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg;
|
||||
vec3 C_fresnel = F_brdf(vec3(0.04), vec3(1.0), C_brdf_lut) *
|
||||
specular_occlusion(NV, final_ao, C_roughness);
|
||||
|
||||
out_spec += C_spec_accum.rgb * C_fresnel * C_intensity;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
/* Global toggle for lightprobe baking. */
|
||||
out_spec *= float(specToggle);
|
||||
# endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* ---------------- DIFFUSE ENVIRONMENT LIGHTING ------------------ */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
|
||||
# ifdef CLOSURE_DIFFUSE
|
||||
vec4 diff_accum = vec4(0.0);
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Irradiance Grids */
|
||||
/* ---------------------------- */
|
||||
/* Start at 1 because 0 is world irradiance */
|
||||
for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; i++) {
|
||||
GridData gd = grids_data[i];
|
||||
|
||||
vec3 localpos;
|
||||
float fade = probe_attenuation_grid(gd, grids_data[i].localmat, worldPosition, localpos);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 diff = probe_evaluate_grid(gd, worldPosition, bent_normal, localpos);
|
||||
accumulate_light(diff, fade, diff_accum);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------- */
|
||||
/* World Diffuse */
|
||||
/* ---------------------------- */
|
||||
if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) {
|
||||
vec3 diff = probe_evaluate_world_diff(bent_normal);
|
||||
accumulate_light(diff, 1.0, diff_accum);
|
||||
}
|
||||
|
||||
out_diff += diff_accum.rgb * gtao_multibounce(final_ao, albedo);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Cleanup for next configuration */
|
||||
#undef CLOSURE_NAME
|
||||
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
# undef CLOSURE_DIFFUSE
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
# undef CLOSURE_GLOSSY
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
# undef CLOSURE_CLEARCOAT
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
# undef CLOSURE_REFRACTION
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_SUBSURFACE
|
||||
# undef CLOSURE_SUBSURFACE
|
||||
#endif
|
@@ -147,17 +147,27 @@ Closure closure_emission(vec3 rgb)
|
||||
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
/* Let radiance passthrough or replace it to get the BRDF and color
|
||||
* to applied to the SSR result. */
|
||||
vec3 closure_mask_ssr_radiance(vec3 radiance, float ssr_id)
|
||||
{
|
||||
return (ssrToggle && int(ssr_id) == outputSsrId) ? vec3(1.0) : radiance;
|
||||
}
|
||||
|
||||
void closure_load_ssr_data(
|
||||
vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
|
||||
vec3 ssr_radiance, float roughness, vec3 N, float ssr_id, inout Closure cl)
|
||||
{
|
||||
/* Still encode to avoid artifacts in the SSR pass. */
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
||||
cl.ssr_normal = normal_encode(vN, viewVec);
|
||||
cl.ssr_normal = normal_encode(vN, viewCameraVec);
|
||||
|
||||
if (ssr_id == outputSsrId) {
|
||||
cl.ssr_data = vec4(ssr_spec, roughness);
|
||||
if (ssrToggle && int(ssr_id) == outputSsrId) {
|
||||
cl.ssr_data = vec4(ssr_radiance, roughness);
|
||||
cl.flag |= CLOSURE_SSR_FLAG;
|
||||
}
|
||||
else {
|
||||
cl.radiance += ssr_radiance;
|
||||
}
|
||||
}
|
||||
|
||||
void closure_load_sss_data(
|
||||
@@ -169,13 +179,11 @@ void closure_load_sss_data(
|
||||
cl.sss_radius = radius;
|
||||
cl.sss_albedo = sss_albedo;
|
||||
cl.flag |= CLOSURE_SSS_FLAG;
|
||||
cl.radiance += render_pass_diffuse_mask(sss_albedo, vec3(0));
|
||||
/* Irradiance will be convolved by SSSS pass. Do not add to radiance. */
|
||||
sss_irradiance = vec3(0);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo);
|
||||
}
|
||||
cl.radiance += render_pass_diffuse_mask(vec3(1), sss_irradiance) * sss_albedo;
|
||||
}
|
||||
|
||||
#endif
|
@@ -12,11 +12,20 @@ uniform sampler2DArray utilTex;
|
||||
|
||||
#define LUT_SIZE 64
|
||||
|
||||
#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
|
||||
#define LTC_MAT_LAYER 0
|
||||
#define LTC_BRDF_LAYER 1
|
||||
#define BRDF_LUT_LAYER 1
|
||||
#define NOISE_LAYER 2
|
||||
#define LTC_DISK_LAYER 3 /* UNUSED */
|
||||
/* Layers 4 to 20 are for BTDF Lut. */
|
||||
|
||||
#define texelfetch_noise_tex(coord) \
|
||||
texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, NOISE_LAYER), 0)
|
||||
|
||||
/* Return texture coordinates to sample Surface LUT */
|
||||
vec2 lut_coords(float cosTheta, float roughness)
|
||||
{
|
||||
/* TODO(fclem) Ugly Acos here. Get rid ot this. Should use same mapping as lut_coords_ltc. */
|
||||
float theta = acos(cosTheta);
|
||||
vec2 coords = vec2(roughness, theta / M_PI_2);
|
||||
|
||||
@@ -32,6 +41,11 @@ vec2 lut_coords_ltc(float cosTheta, float roughness)
|
||||
return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
|
||||
}
|
||||
|
||||
vec2 brdf_lut(float cosTheta, float roughness)
|
||||
{
|
||||
return textureLod(utilTex, vec3(lut_coords(cosTheta, roughness), BRDF_LUT_LAYER), 0.0).rg;
|
||||
}
|
||||
|
||||
float get_btdf_lut(float NV, float roughness, float ior)
|
||||
{
|
||||
const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE;
|
||||
|
@@ -2,6 +2,8 @@
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
||||
@@ -170,7 +172,7 @@ void main()
|
||||
/* Importance sampling bias */
|
||||
rand.x = mix(rand.x, 0.0, ssrBrdfBias);
|
||||
|
||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
vec3 W = transform_point(ViewMatrixInverse, viewPosition);
|
||||
vec3 wN = transform_direction(ViewMatrixInverse, N);
|
||||
|
||||
vec3 T, B;
|
||||
@@ -180,12 +182,12 @@ void main()
|
||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
||||
PlanarData pd = planars_data[i];
|
||||
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0);
|
||||
float fade = probe_attenuation_planar(pd, W, wN, 0.0);
|
||||
|
||||
if (fade > 0.5) {
|
||||
/* Find view vector / reflection plane intersection. */
|
||||
/* TODO optimize, use view space for all. */
|
||||
vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq);
|
||||
vec3 tracePosition = line_plane_intersect(W, cameraVec, pd.pl_plane_eq);
|
||||
tracePosition = transform_point(ViewMatrix, tracePosition);
|
||||
vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
|
||||
|
||||
@@ -213,6 +215,8 @@ uniform sampler2D pdfBuffer;
|
||||
|
||||
uniform int neighborOffset;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0),
|
||||
ivec2(1, 1),
|
||||
ivec2(-2, 0),
|
||||
@@ -298,7 +302,7 @@ float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index)
|
||||
|
||||
vec3 get_hit_vector(vec3 hit_pos,
|
||||
PlanarData pd,
|
||||
vec3 worldPosition,
|
||||
vec3 P,
|
||||
vec3 N,
|
||||
vec3 V,
|
||||
bool is_planar,
|
||||
@@ -309,7 +313,7 @@ vec3 get_hit_vector(vec3 hit_pos,
|
||||
|
||||
if (is_planar) {
|
||||
/* Reflect back the hit position to have it in non-reflected world space */
|
||||
vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq);
|
||||
vec3 trace_pos = line_plane_intersect(P, V, pd.pl_plane_eq);
|
||||
hit_vec = hit_pos - trace_pos;
|
||||
hit_vec = reflect(hit_vec, pd.pl_normal);
|
||||
/* Modify here so mip texel alignment is correct. */
|
||||
@@ -317,8 +321,8 @@ vec3 get_hit_vector(vec3 hit_pos,
|
||||
}
|
||||
else {
|
||||
/* Find hit position in previous frame. */
|
||||
hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
|
||||
hit_vec = hit_pos - worldPosition;
|
||||
hit_co = get_reprojected_reflection(hit_pos, P, N);
|
||||
hit_vec = hit_pos - P;
|
||||
}
|
||||
|
||||
mask = screen_border_mask(hit_co);
|
||||
@@ -339,7 +343,7 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
||||
ivec4 hit_data[2],
|
||||
PlanarData pd,
|
||||
float planar_index,
|
||||
vec3 worldPosition,
|
||||
vec3 P,
|
||||
vec3 N,
|
||||
vec3 V,
|
||||
float roughnessSquared,
|
||||
@@ -379,14 +383,10 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
||||
|
||||
/* Get actual hit vector and hit coordinate (from last frame). */
|
||||
vec4 mask = vec4(1.0);
|
||||
hit_pos[0] = get_hit_vector(
|
||||
hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x);
|
||||
hit_pos[1] = get_hit_vector(
|
||||
hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y);
|
||||
hit_pos[2] = get_hit_vector(
|
||||
hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z);
|
||||
hit_pos[3] = get_hit_vector(
|
||||
hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w);
|
||||
hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x);
|
||||
hit_pos[1] = get_hit_vector(hit_pos[1], pd, P, N, V, is_planar.y, hit_co[0].zw, mask.y);
|
||||
hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z);
|
||||
hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w);
|
||||
|
||||
vec4 hit_dist;
|
||||
hit_dist.x = length(hit_pos[0]);
|
||||
@@ -476,47 +476,30 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
||||
return accum;
|
||||
}
|
||||
|
||||
void main()
|
||||
void raytrace_resolve(ClosureInputGlossy cl_in,
|
||||
inout ClosureEvalGlossy cl_eval,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
|
||||
# ifdef FULLRES
|
||||
ivec2 halfres_texel = fullres_texel;
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
# else
|
||||
ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy / 2.0);
|
||||
# endif
|
||||
vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
|
||||
|
||||
float depth = textureLod(depthBuffer, uvs, 0.0).r;
|
||||
|
||||
/* Early out */
|
||||
if (depth == 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
/* Using world space */
|
||||
vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */
|
||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
vec3 V = cameraVec;
|
||||
vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
|
||||
vec3 N = transform_direction(ViewMatrixInverse, vN);
|
||||
vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
|
||||
vec3 V = cl_common.V;
|
||||
vec3 N = cl_in.N;
|
||||
vec3 P = cl_common.P;
|
||||
|
||||
/* Early out */
|
||||
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float roughness = speccol_roughness.a;
|
||||
float roughnessSquared = max(1e-3, roughness * roughness);
|
||||
|
||||
vec4 spec_accum = vec4(0.0);
|
||||
float roughness = cl_in.roughness;
|
||||
float roughnessSquared = max(1e-3, sqr(roughness));
|
||||
|
||||
/* Resolve SSR */
|
||||
float cone_cos = cone_cosine(roughnessSquared);
|
||||
float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
|
||||
cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */
|
||||
|
||||
vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
|
||||
vec2 source_uvs = project_point(pastViewProjectionMatrix, P).xy * 0.5 + 0.5;
|
||||
|
||||
vec4 ssr_accum = vec4(0.0);
|
||||
float weight_acc = 0.0;
|
||||
@@ -525,16 +508,16 @@ void main()
|
||||
/* TODO optimize with textureGather */
|
||||
/* Doing these fetches early to hide latency. */
|
||||
vec4 hit_pdf;
|
||||
hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r;
|
||||
hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r;
|
||||
hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r;
|
||||
hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r;
|
||||
hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r;
|
||||
hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r;
|
||||
hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r;
|
||||
hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r;
|
||||
|
||||
ivec4 hit_data[2];
|
||||
hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg;
|
||||
hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg;
|
||||
hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg;
|
||||
hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg;
|
||||
hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg;
|
||||
hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg;
|
||||
hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg;
|
||||
hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg;
|
||||
|
||||
/* Find Planar Reflections affecting this pixel */
|
||||
PlanarData pd;
|
||||
@@ -542,7 +525,7 @@ void main()
|
||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
||||
pd = planars_data[i];
|
||||
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
|
||||
float fade = probe_attenuation_planar(pd, P, N, 0.0);
|
||||
|
||||
if (fade > 0.5) {
|
||||
planar_index = float(i);
|
||||
@@ -554,7 +537,7 @@ void main()
|
||||
hit_data,
|
||||
pd,
|
||||
planar_index,
|
||||
worldPosition,
|
||||
P,
|
||||
N,
|
||||
V,
|
||||
roughnessSquared,
|
||||
@@ -564,19 +547,51 @@ void main()
|
||||
}
|
||||
|
||||
/* Compute SSR contribution */
|
||||
if (weight_acc > 0.0) {
|
||||
ssr_accum /= weight_acc;
|
||||
/* fade between 0.5 and 1.0 roughness */
|
||||
ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
||||
accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
|
||||
ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc);
|
||||
/* fade between 0.5 and 1.0 roughness */
|
||||
ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
||||
|
||||
cl_eval.raytrace_radiance = ssr_accum.rgb * ssr_accum.a;
|
||||
cl_common.specular_accum -= ssr_accum.a;
|
||||
}
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy)
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
float depth = texelFetch(depthBuffer, texel, 0).r;
|
||||
|
||||
if (depth == 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
/* If SSR contribution is not 1.0, blend with cubemaps */
|
||||
if (spec_accum.a < 1.0) {
|
||||
fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
|
||||
vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba;
|
||||
vec3 brdf = speccol_roughness.rgb;
|
||||
float roughness = speccol_roughness.a;
|
||||
|
||||
if (max_v3(brdf) <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
|
||||
viewPosition = get_view_space_from_depth(uvcoordsvar.xy, depth);
|
||||
worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
|
||||
vec2 normal_encoded = texelFetch(normalBuffer, texel, 0).rg;
|
||||
viewNormal = normal_decode(normal_encoded, viewCameraVec);
|
||||
worldNormal = transform_direction(ViewMatrixInverse, viewNormal);
|
||||
|
||||
CLOSURE_VARS_DECLARE_1(Glossy);
|
||||
|
||||
in_Glossy_0.N = worldNormal;
|
||||
in_Glossy_0.roughness = roughness;
|
||||
|
||||
/* Do a full deferred evaluation of the glossy BSDF. The only difference is that we inject the
|
||||
* SSR resolve before the cubemap iter. BRDF term is already computed during main pass and is
|
||||
* passed as specular color. */
|
||||
CLOSURE_EVAL_FUNCTION_1(ssr_resolve, Glossy);
|
||||
|
||||
fragColor = vec4(out_Glossy_0.radiance * brdf, 1.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -137,9 +137,9 @@ float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N, float roughness)
|
||||
return fac;
|
||||
}
|
||||
|
||||
float probe_attenuation_grid(GridData gd, mat4 localmat, vec3 W, out vec3 localpos)
|
||||
float probe_attenuation_grid(GridData gd, vec3 W, out vec3 localpos)
|
||||
{
|
||||
localpos = transform_point(localmat, W);
|
||||
localpos = transform_point(gd.localmat, W);
|
||||
vec3 pos_to_edge = max(vec3(0.0), abs(localpos) - 1.0);
|
||||
float fade = length(pos_to_edge);
|
||||
return saturate(-fade * gd.g_atten_scale + gd.g_atten_bias);
|
||||
@@ -183,8 +183,7 @@ vec3 probe_evaluate_world_spec(vec3 R, float roughness)
|
||||
return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb;
|
||||
}
|
||||
|
||||
vec3 probe_evaluate_planar(
|
||||
float id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness, inout float fade)
|
||||
vec3 probe_evaluate_planar(int id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness)
|
||||
{
|
||||
/* Find view vector / reflection plane intersection. */
|
||||
vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq);
|
||||
@@ -226,7 +225,7 @@ void fallback_cubemap(vec3 N,
|
||||
#ifdef SSR_AO
|
||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
vec3 bent_normal;
|
||||
float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal);
|
||||
float final_ao = occlusion_compute(N, viewPosition, rand, bent_normal);
|
||||
final_ao = specular_occlusion(dot(N, V), final_ao, roughness);
|
||||
#else
|
||||
const float final_ao = 1.0;
|
||||
|
@@ -252,32 +252,29 @@ float light_attenuation(LightData ld, vec4 l_vector)
|
||||
return vis;
|
||||
}
|
||||
|
||||
float light_shadowing(LightData ld,
|
||||
vec3 W,
|
||||
#ifndef VOLUMETRICS
|
||||
vec3 viewPosition,
|
||||
float tracing_depth,
|
||||
vec3 true_normal,
|
||||
float rand_x,
|
||||
const bool use_contact_shadows,
|
||||
#endif
|
||||
float vis)
|
||||
float light_shadowing(LightData ld, vec3 W, float vis)
|
||||
{
|
||||
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
|
||||
/* shadowing */
|
||||
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
|
||||
|
||||
if (ld.l_type == SUN) {
|
||||
vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
|
||||
}
|
||||
else {
|
||||
vis *= sample_cube_shadow(int(ld.l_shadowid), W);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return vis;
|
||||
}
|
||||
|
||||
# ifndef VOLUMETRICS
|
||||
#ifndef VOLUMETRICS
|
||||
float light_contact_shadows(
|
||||
LightData ld, vec3 P, vec3 vP, float tracing_depth, vec3 vNg, float rand_x, float vis)
|
||||
{
|
||||
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
|
||||
ShadowData sd = shadows_data[int(ld.l_shadowid)];
|
||||
/* Only compute if not already in shadow. */
|
||||
if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) {
|
||||
if (sd.sh_contact_dist > 0.0) {
|
||||
/* Contact Shadows. */
|
||||
vec3 ray_ori, ray_dir;
|
||||
float trace_distance;
|
||||
@@ -287,54 +284,34 @@ float light_shadowing(LightData ld,
|
||||
ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
|
||||
}
|
||||
else {
|
||||
ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W;
|
||||
ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P;
|
||||
float len = length(ray_dir);
|
||||
trace_distance = min(sd.sh_contact_dist, len);
|
||||
ray_dir *= trace_distance / len;
|
||||
}
|
||||
|
||||
ray_dir = transform_direction(ViewMatrix, ray_dir);
|
||||
ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset;
|
||||
ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset;
|
||||
|
||||
vec3 hit_pos = raycast(
|
||||
-1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
|
||||
|
||||
if (hit_pos.z > 0.0) {
|
||||
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
|
||||
float hit_dist = distance(viewPosition, hit_pos);
|
||||
float hit_dist = distance(vP, hit_pos);
|
||||
float dist_ratio = hit_dist / trace_distance;
|
||||
return vis * saturate(dist_ratio * 3.0 - 2.0);
|
||||
return saturate(dist_ratio * 3.0 - 2.0);
|
||||
}
|
||||
}
|
||||
# endif /* VOLUMETRICS */
|
||||
}
|
||||
#endif
|
||||
|
||||
return vis;
|
||||
return 1.0;
|
||||
}
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
float light_visibility(LightData ld,
|
||||
vec3 W,
|
||||
#ifndef VOLUMETRICS
|
||||
vec3 viewPosition,
|
||||
float tracing_depth,
|
||||
vec3 true_normal,
|
||||
float rand_x,
|
||||
const bool use_contact_shadows,
|
||||
#endif
|
||||
vec4 l_vector)
|
||||
float light_visibility(LightData ld, vec3 W, vec4 l_vector)
|
||||
{
|
||||
float l_atten = light_attenuation(ld, l_vector);
|
||||
return light_shadowing(ld,
|
||||
W,
|
||||
#ifndef VOLUMETRICS
|
||||
viewPosition,
|
||||
tracing_depth,
|
||||
true_normal,
|
||||
rand_x,
|
||||
use_contact_shadows,
|
||||
#endif
|
||||
l_atten);
|
||||
return light_shadowing(ld, W, l_atten);
|
||||
}
|
||||
|
||||
float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
|
||||
|
@@ -5,8 +5,12 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(surface_lib.glsl)
|
||||
|
||||
#ifdef USE_ALPHA_HASH
|
||||
|
@@ -39,7 +39,7 @@ void main()
|
||||
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
|
||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
|
||||
vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
vec3 true_normal = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
|
||||
for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
|
||||
LightData ld = lights_data[i];
|
||||
@@ -48,8 +48,10 @@ void main()
|
||||
l_vector.xyz = ld.l_position - worldPosition;
|
||||
l_vector.w = length(l_vector.xyz);
|
||||
|
||||
float l_vis = light_shadowing(
|
||||
ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, true, 1.0);
|
||||
float l_vis = light_shadowing(ld, worldPosition, 1.0);
|
||||
|
||||
l_vis *= light_contact_shadows(
|
||||
ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, 1.0);
|
||||
|
||||
accum_light += l_vis;
|
||||
}
|
||||
|
@@ -3,8 +3,13 @@
|
||||
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
|
||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
|
||||
|
||||
#pragma BLENDER_REQUIRE(surface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
||||
|
||||
|
@@ -13,7 +13,15 @@ uniform float refractionDepth;
|
||||
vec3 worldNormal; \
|
||||
vec3 viewNormal;
|
||||
|
||||
#ifdef GPU_GEOMETRY_SHADER
|
||||
#if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE)
|
||||
/* SSR will set these global variables itself.
|
||||
* Also make false positive compiler warnings disapear by setting values. */
|
||||
vec3 worldPosition = vec3(0);
|
||||
vec3 viewPosition = vec3(0);
|
||||
vec3 worldNormal = vec3(0);
|
||||
vec3 viewNormal = vec3(0);
|
||||
|
||||
#elif defined(GPU_GEOMETRY_SHADER)
|
||||
in ShaderStageInterface{SURFACE_INTERFACE} dataIn[];
|
||||
|
||||
out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
|
||||
@@ -24,7 +32,7 @@ out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
|
||||
dataOut.worldNormal = dataIn[vert].worldNormal; \
|
||||
dataOut.viewNormal = dataIn[vert].viewNormal;
|
||||
|
||||
#else
|
||||
#else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/
|
||||
|
||||
IN_OUT ShaderStageInterface{SURFACE_INTERFACE};
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||
|
||||
/* Based on Frosbite Unified Volumetric.
|
||||
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
|
||||
|
@@ -72,6 +72,9 @@ float sum(vec4 v) { return dot(vec4(1.0), v); }
|
||||
float avg(vec2 v) { return dot(vec2(1.0 / 2.0), v); }
|
||||
float avg(vec3 v) { return dot(vec3(1.0 / 3.0), v); }
|
||||
float avg(vec4 v) { return dot(vec4(1.0 / 4.0), v); }
|
||||
|
||||
float sqr(float v) { return v * v; }
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define saturate(a) clamp(a, 0.0, 1.0)
|
||||
@@ -93,6 +96,15 @@ float len_squared(vec3 a)
|
||||
return dot(a, a);
|
||||
}
|
||||
|
||||
vec3 safe_normalize(vec3 v)
|
||||
{
|
||||
float len = length(v);
|
||||
if (isnan(len) || len == 0.0) {
|
||||
return vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
return v / len;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@@ -3374,13 +3374,6 @@ static void node_geometry_buts_points_to_volume(uiLayout *layout,
|
||||
uiItemR(layout, ptr, "input_type_radius", DEFAULT_FLAGS, IFACE_("Radius"), ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_geometry_buts_collection_info(uiLayout *layout,
|
||||
bContext *UNUSED(C),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_geometry_set_butfunc(bNodeType *ntype)
|
||||
{
|
||||
switch (ntype->type) {
|
||||
@@ -3441,9 +3434,6 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
|
||||
case GEO_NODE_POINTS_TO_VOLUME:
|
||||
ntype->draw_buttons = node_geometry_buts_points_to_volume;
|
||||
break;
|
||||
case GEO_NODE_COLLECTION_INFO:
|
||||
ntype->draw_buttons = node_geometry_buts_collection_info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -51,7 +51,6 @@ typedef struct bNodeLinkDrag {
|
||||
* This way the links can be added to the node tree while being stored in this list.
|
||||
*/
|
||||
ListBase links;
|
||||
bool from_multi_input_socket;
|
||||
int in_out;
|
||||
} bNodeLinkDrag;
|
||||
|
||||
|
@@ -836,38 +836,31 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
|
||||
nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
|
||||
|
||||
const int num_links = nodeCountSocketLinks(snode->edittree, sock);
|
||||
if (num_links > 0) {
|
||||
int link_limit = nodeSocketLinkLimit(sock);
|
||||
if (num_links > 0 && (num_links >= link_limit || detach)) {
|
||||
/* dragged links are fixed on output side */
|
||||
nldrag->in_out = SOCK_OUT;
|
||||
/* detach current links and store them in the operator data */
|
||||
bNodeLink *link_to_pick;
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
|
||||
if (link->tosock == sock) {
|
||||
if (sock->flag & SOCK_MULTI_INPUT) {
|
||||
nldrag->from_multi_input_socket = true;
|
||||
LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
|
||||
bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
|
||||
linkdata->data = oplink;
|
||||
*oplink = *link;
|
||||
oplink->next = oplink->prev = NULL;
|
||||
oplink->flag |= NODE_LINK_VALID;
|
||||
oplink->flag &= ~NODE_LINK_TEST;
|
||||
if (node_connected_to_output(bmain, snode->edittree, link->tonode)) {
|
||||
oplink->flag |= NODE_LINK_TEST;
|
||||
}
|
||||
link_to_pick = link;
|
||||
}
|
||||
}
|
||||
|
||||
if (link_to_pick != NULL && !nldrag->from_multi_input_socket) {
|
||||
LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
|
||||
bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
|
||||
linkdata->data = oplink;
|
||||
*oplink = *link_to_pick;
|
||||
oplink->next = oplink->prev = NULL;
|
||||
oplink->flag |= NODE_LINK_VALID;
|
||||
oplink->flag &= ~NODE_LINK_TEST;
|
||||
if (node_connected_to_output(bmain, snode->edittree, link_to_pick->tonode)) {
|
||||
oplink->flag |= NODE_LINK_TEST;
|
||||
}
|
||||
BLI_addtail(&nldrag->links, linkdata);
|
||||
nodeRemLink(snode->edittree, link);
|
||||
|
||||
BLI_addtail(&nldrag->links, linkdata);
|
||||
nodeRemLink(snode->edittree, link_to_pick);
|
||||
|
||||
/* send changed event to original link->tonode */
|
||||
if (node) {
|
||||
snode_update(snode, node);
|
||||
/* send changed event to original link->tonode */
|
||||
if (node) {
|
||||
snode_update(snode, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -903,8 +896,6 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
|
||||
float cursor[2];
|
||||
UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
|
||||
RNA_float_set_array(op->ptr, "drag_start", cursor);
|
||||
RNA_boolean_set(op->ptr, "has_link_picked", false);
|
||||
|
||||
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
|
||||
|
||||
@@ -950,28 +941,7 @@ void NODE_OT_link(wmOperatorType *ot)
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_boolean(ot->srna, "detach", false, "Detach", "Detach and redirect existing links");
|
||||
prop = RNA_def_boolean(
|
||||
ot->srna,
|
||||
"has_link_picked",
|
||||
false,
|
||||
"Has Link Picked",
|
||||
"The operation has placed a link. Only used for multi-input sockets, where the "
|
||||
"link is picked later");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
RNA_def_float_array(ot->srna,
|
||||
"drag_start",
|
||||
2,
|
||||
0,
|
||||
-UI_PRECISION_FLOAT_MAX,
|
||||
UI_PRECISION_FLOAT_MAX,
|
||||
"Drag Start",
|
||||
"The position of the mouse cursor at the start of the operation.",
|
||||
-UI_PRECISION_FLOAT_MAX,
|
||||
UI_PRECISION_FLOAT_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
/* ********************** Make Link operator ***************** */
|
||||
|
@@ -755,6 +755,10 @@ static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
|
||||
|
||||
/* get parameters */
|
||||
while (*code && *code != ')') {
|
||||
if (BLI_str_startswith(code, "const ")) {
|
||||
code = gpu_str_skip_token(code, NULL, 0);
|
||||
}
|
||||
|
||||
/* test if it's an input or output */
|
||||
qual = FUNCTION_QUAL_IN;
|
||||
if (BLI_str_startswith(code, "out ")) {
|
||||
|
@@ -4,7 +4,7 @@ void node_ambient_occlusion(
|
||||
{
|
||||
vec3 bent_normal;
|
||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
|
||||
result_ao = occlusion_compute(normalize(normal), viewPosition, rand, bent_normal);
|
||||
result_color = result_ao * color;
|
||||
}
|
||||
#else
|
||||
|
@@ -1,12 +1,27 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse)
|
||||
|
||||
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
CLOSURE_VARS_DECLARE_1(Diffuse);
|
||||
|
||||
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = color.rgb;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_diffuse, Diffuse);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance);
|
||||
result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb);
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
||||
|
||||
out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance);
|
||||
out_Diffuse_0.radiance *= color.rgb;
|
||||
|
||||
result.radiance = out_Diffuse_0.radiance;
|
||||
|
||||
/* TODO(fclem) Try to not use this. */
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub diffuse because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT)
|
||||
|
@@ -1,4 +1,7 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy)
|
||||
|
||||
void node_eevee_specular(vec4 diffuse,
|
||||
vec4 specular,
|
||||
float roughness,
|
||||
@@ -12,34 +15,63 @@ void node_eevee_specular(vec4 diffuse,
|
||||
float ssr_id,
|
||||
out Closure result)
|
||||
{
|
||||
normal = normalize(normal);
|
||||
CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
|
||||
|
||||
vec3 out_diff, out_spec, ssr_spec;
|
||||
eevee_closure_default_clearcoat(normal,
|
||||
diffuse.rgb,
|
||||
specular.rgb,
|
||||
vec3(1.0),
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
clearcoat_normal,
|
||||
clearcoat * 0.25,
|
||||
clearcoat_roughness,
|
||||
occlusion,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
in_common.occlusion = occlusion;
|
||||
|
||||
in_Diffuse_0.N = normal; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = diffuse.rgb;
|
||||
|
||||
in_Glossy_1.N = normal; /* Normalized during eval. */
|
||||
in_Glossy_1.roughness = roughness;
|
||||
|
||||
in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */
|
||||
in_Glossy_2.roughness = clearcoat_roughness;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy);
|
||||
|
||||
float alpha = 1.0 - transp;
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_diffuse_mask(diffuse.rgb, out_diff * diffuse.rgb);
|
||||
result.radiance += render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_emission_mask(emissive.rgb);
|
||||
result.radiance *= alpha;
|
||||
result.transmittance = vec3(transp);
|
||||
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
|
||||
{
|
||||
/* Diffuse. */
|
||||
out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1), out_Diffuse_0.radiance);
|
||||
out_Diffuse_0.radiance *= in_Diffuse_0.albedo;
|
||||
result += out_Diffuse_0.radiance;
|
||||
}
|
||||
{
|
||||
/* Glossy. */
|
||||
float NV = dot(in_Glossy_1.N, cameraVec);
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_1.roughness);
|
||||
vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum);
|
||||
|
||||
out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
|
||||
out_Glossy_1.radiance *= brdf;
|
||||
out_Glossy_1.radiance = render_pass_glossy_mask(spec_color, out_Glossy_1.radiance);
|
||||
closure_load_ssr_data(
|
||||
out_Glossy_1.radiance, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
|
||||
}
|
||||
{
|
||||
/* Clearcoat. */
|
||||
float NV = dot(in_Glossy_2.N, cameraVec);
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
|
||||
vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
|
||||
|
||||
out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
|
||||
out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
|
||||
result.radiance += out_Glossy_2.radiance;
|
||||
}
|
||||
{
|
||||
/* Emission. */
|
||||
vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
|
||||
result.radiance += out_emission_radiance;
|
||||
}
|
||||
|
||||
float trans = 1.0 - trans;
|
||||
result.transmittance = vec3(trans);
|
||||
result.radiance *= alpha;
|
||||
result.ssr_data.rgb *= alpha;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub specular because it is not compatible with volumetrics. */
|
||||
# define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT)
|
||||
|
@@ -1,4 +1,7 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction)
|
||||
|
||||
void node_bsdf_glass(vec4 color,
|
||||
float roughness,
|
||||
float ior,
|
||||
@@ -7,32 +10,38 @@ void node_bsdf_glass(vec4 color,
|
||||
float ssr_id,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_spec, out_refr, ssr_spec;
|
||||
vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
|
||||
color.rgb; /* Simulate 2 transmission event */
|
||||
eevee_closure_glass(N,
|
||||
vec3(1.0),
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? vec3(1.0) : -vec3(1.0),
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
ior,
|
||||
true,
|
||||
out_spec,
|
||||
out_refr,
|
||||
ssr_spec);
|
||||
float fresnel = F_eta(ior, dot(N, cameraVec));
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color) * (1.0 - fresnel);
|
||||
result.radiance += render_pass_glossy_mask(color.rgb, out_spec * color.rgb) * fresnel;
|
||||
CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
|
||||
|
||||
in_Glossy_0.N = N; /* Normalized during eval. */
|
||||
in_Glossy_0.roughness = roughness;
|
||||
|
||||
in_Refraction_1.N = N; /* Normalized during eval. */
|
||||
in_Refraction_1.roughness = roughness;
|
||||
in_Refraction_1.ior = ior;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
|
||||
float fresnel = F_eta(in_Refraction_1.ior, dot(in_Glossy_0.N, cameraVec));
|
||||
|
||||
vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec), in_Glossy_0.roughness);
|
||||
vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
|
||||
F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
|
||||
out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
|
||||
out_Glossy_0.radiance *= brdf;
|
||||
out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
|
||||
out_Glossy_0.radiance *= color.rgb * fresnel;
|
||||
closure_load_ssr_data(
|
||||
ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
|
||||
|
||||
out_Refraction_1.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_1.radiance);
|
||||
out_Refraction_1.radiance *= color.rgb * (1.0 - fresnel);
|
||||
/* Simulate 2nd absorption event. */
|
||||
out_Refraction_1.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
|
||||
result.radiance += out_Refraction_1.radiance;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub glass because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT)
|
||||
|
@@ -1,23 +1,32 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy)
|
||||
|
||||
void node_bsdf_glossy(
|
||||
vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_spec, ssr_spec;
|
||||
eevee_closure_glossy(N,
|
||||
vec3(1.0),
|
||||
use_multiscatter != 0.0 ? vec3(1.0) : vec3(-1.0), /* HACK */
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId);
|
||||
|
||||
CLOSURE_VARS_DECLARE_1(Glossy);
|
||||
|
||||
in_Glossy_0.N = N; /* Normalized during eval. */
|
||||
in_Glossy_0.roughness = roughness;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) * color.rgb;
|
||||
closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec), in_Glossy_0.roughness);
|
||||
vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
|
||||
F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
|
||||
out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
|
||||
out_Glossy_0.radiance *= brdf;
|
||||
out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
|
||||
out_Glossy_0.radiance *= color.rgb;
|
||||
closure_load_ssr_data(
|
||||
out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub glossy because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
|
||||
|
@@ -1,41 +1,20 @@
|
||||
#ifndef VOLUMETRICS
|
||||
vec3 tint_from_color(vec3 color)
|
||||
{
|
||||
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
|
||||
return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
|
||||
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
|
||||
return (lum > 0.0) ? color / lum : vec3(0.0); /* normalize lum. to isolate hue+sat */
|
||||
}
|
||||
|
||||
void convert_metallic_to_specular_tinted(vec3 basecol,
|
||||
vec3 basecol_tint,
|
||||
float metallic,
|
||||
float specular_fac,
|
||||
float specular_tint,
|
||||
out vec3 diffuse,
|
||||
out vec3 f0)
|
||||
{
|
||||
vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
|
||||
f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
|
||||
diffuse = basecol * (1.0 - metallic);
|
||||
}
|
||||
|
||||
/* Output sheen is to be multiplied by sheen_color. */
|
||||
void principled_sheen(float NV,
|
||||
vec3 basecol_tint,
|
||||
float sheen,
|
||||
float sheen_tint,
|
||||
out float out_sheen,
|
||||
out vec3 sheen_color)
|
||||
float principled_sheen(float NV)
|
||||
{
|
||||
float f = 1.0 - NV;
|
||||
/* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps,
|
||||
* therefore we need to clamp value. */
|
||||
f = clamp(f, 0.0, 1.0);
|
||||
/* Empirical approximation (manual curve fitting). Can be refined. */
|
||||
out_sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
|
||||
|
||||
sheen_color = sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
|
||||
float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
|
||||
return sheen;
|
||||
}
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction)
|
||||
|
||||
void node_bsdf_principled(vec4 base_color,
|
||||
float subsurface,
|
||||
vec3 subsurface_radius,
|
||||
@@ -59,434 +38,163 @@ void node_bsdf_principled(vec4 base_color,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
const float do_diffuse,
|
||||
const float do_clearcoat,
|
||||
const float do_refraction,
|
||||
const float do_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
ior = max(ior, 1e-5);
|
||||
/* Match cycles. */
|
||||
metallic = saturate(metallic);
|
||||
transmission = saturate(transmission);
|
||||
float m_transmission = 1.0 - transmission;
|
||||
float diffuse_weight = (1.0 - transmission) * (1.0 - metallic);
|
||||
transmission *= (1.0 - metallic);
|
||||
float specular_weight = (1.0 - transmission);
|
||||
clearcoat = max(clearcoat, 0.0);
|
||||
transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness);
|
||||
|
||||
float dielectric = 1.0 - metallic;
|
||||
transmission *= dielectric;
|
||||
sheen *= dielectric;
|
||||
subsurface_color *= dielectric;
|
||||
CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
|
||||
|
||||
vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec, sheen_color;
|
||||
float out_sheen;
|
||||
vec3 ctint = tint_from_color(base_color.rgb);
|
||||
convert_metallic_to_specular_tinted(
|
||||
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
|
||||
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface);
|
||||
|
||||
float NV = dot(N, cameraVec);
|
||||
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
|
||||
in_Glossy_1.N = N; /* Normalized during eval. */
|
||||
in_Glossy_1.roughness = roughness;
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
|
||||
in_Glossy_2.N = CN; /* Normalized during eval. */
|
||||
in_Glossy_2.roughness = clearcoat_roughness;
|
||||
|
||||
/* Far from being accurate, but 2 glossy evaluation is too expensive.
|
||||
* Most noticeable difference is at grazing angles since the bsdf lut
|
||||
* f0 color interpolation is done on top of this interpolation. */
|
||||
vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
|
||||
float fresnel = F_eta(ior, NV);
|
||||
vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
|
||||
f0 = mix(f0, spec_col, transmission);
|
||||
f90 = mix(f90, spec_col, transmission);
|
||||
in_Refraction_3.N = N; /* Normalized during eval. */
|
||||
in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness;
|
||||
in_Refraction_3.ior = ior;
|
||||
|
||||
|
||||
/* Really poor approximation but needed to workaround issues with renderpasses. */
|
||||
spec_col = mix(vec3(1.0), spec_col, transmission);
|
||||
/* Match cycles. */
|
||||
spec_col += float(clearcoat > 1e-5);
|
||||
|
||||
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
|
||||
|
||||
float sss_scalef = avg(sss_scale) * subsurface;
|
||||
eevee_closure_principled(N,
|
||||
mixed_ss_base_color,
|
||||
f0,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
CN,
|
||||
clearcoat * 0.25,
|
||||
clearcoat_roughness,
|
||||
1.0,
|
||||
sss_scalef,
|
||||
ior,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
out_refr,
|
||||
ssr_spec);
|
||||
|
||||
vec3 refr_color = base_color.rgb;
|
||||
refr_color *= (refractionDepth > 0.0) ? refr_color :
|
||||
vec3(1.0); /* Simulate 2 transmission event */
|
||||
refr_color *= saturate(1.0 - fresnel) * transmission;
|
||||
|
||||
sheen_color *= m_transmission;
|
||||
mixed_ss_base_color *= m_transmission;
|
||||
CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color);
|
||||
result.radiance += render_pass_glossy_mask(spec_col, out_spec);
|
||||
/* Coarse approx. */
|
||||
result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
mixed_ss_base_color *= alpha;
|
||||
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
/* This will tag the whole eval for optimisation. */
|
||||
if (do_diffuse == 0.0) {
|
||||
out_Diffuse_0.radiance = vec3(0);
|
||||
}
|
||||
if (do_clearcoat == 0.0) {
|
||||
out_Glossy_2.radiance = vec3(0);
|
||||
}
|
||||
if (do_refraction == 0.0) {
|
||||
out_Refraction_3.radiance = vec3(0);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_dielectric(vec4 base_color,
|
||||
float subsurface,
|
||||
vec3 subsurface_radius,
|
||||
vec4 subsurface_color,
|
||||
float metallic,
|
||||
float specular,
|
||||
float specular_tint,
|
||||
float roughness,
|
||||
float anisotropic,
|
||||
float anisotropic_rotation,
|
||||
float sheen,
|
||||
float sheen_tint,
|
||||
float clearcoat,
|
||||
float clearcoat_roughness,
|
||||
float ior,
|
||||
float transmission,
|
||||
float transmission_roughness,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
metallic = saturate(metallic);
|
||||
float dielectric = 1.0 - metallic;
|
||||
/* Glossy_1 will always be evaluated. */
|
||||
float NV = dot(in_Glossy_1.N, cameraVec);
|
||||
|
||||
vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color;
|
||||
float out_sheen;
|
||||
vec3 ctint = tint_from_color(base_color.rgb);
|
||||
convert_metallic_to_specular_tinted(
|
||||
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
|
||||
vec3 base_color_tint = tint_from_color(base_color.rgb);
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
|
||||
/* TODO(fclem) This isn't good for rough glass using multiscatter (since the fresnel is applied
|
||||
* on each microfacet in cycles). */
|
||||
float fresnel = F_eta(in_Refraction_3.ior, NV);
|
||||
|
||||
float NV = dot(N, cameraVec);
|
||||
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
|
||||
{
|
||||
/* Glossy reflections.
|
||||
* Separate Glass reflections and main specular reflections to match Cycles renderpasses. */
|
||||
out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
|
||||
|
||||
eevee_closure_default(N,
|
||||
diffuse,
|
||||
f0,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
vec2 split_sum = brdf_lut(NV, roughness);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
|
||||
result.radiance += render_pass_diffuse_mask(diffuse, out_diff * diffuse);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
vec3 glossy_radiance_final = vec3(0.0);
|
||||
if (transmission > 1e-5) {
|
||||
/* Glass Reflection: Reuse radiance from Glossy1. */
|
||||
vec3 out_glass_refl_radiance = out_Glossy_1.radiance;
|
||||
|
||||
/* Poor approximation since we baked the LUT using a fixed IOR. */
|
||||
vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
|
||||
vec3 f90 = vec3(1);
|
||||
|
||||
vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
|
||||
F_brdf_single_scatter(f0, f90, split_sum);
|
||||
|
||||
out_glass_refl_radiance *= brdf;
|
||||
out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance);
|
||||
out_glass_refl_radiance *= fresnel * transmission;
|
||||
glossy_radiance_final += out_glass_refl_radiance;
|
||||
}
|
||||
if (specular_weight > 1e-5) {
|
||||
vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
|
||||
vec3 metallic_f0_color = base_color.rgb;
|
||||
vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
|
||||
/* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
|
||||
* is already baked inside the split sum LUT. We approximate using by modifying the
|
||||
* changing the f90 color directly in a non linear fashion. */
|
||||
vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular));
|
||||
|
||||
vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
|
||||
F_brdf_single_scatter(f0, f90, split_sum);
|
||||
|
||||
out_Glossy_1.radiance *= brdf;
|
||||
out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance);
|
||||
out_Glossy_1.radiance *= specular_weight;
|
||||
glossy_radiance_final += out_Glossy_1.radiance;
|
||||
}
|
||||
|
||||
closure_load_ssr_data(
|
||||
glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
|
||||
}
|
||||
|
||||
if (diffuse_weight > 1e-5) {
|
||||
/* Mask over all diffuse radiance. */
|
||||
out_Diffuse_0.radiance *= diffuse_weight;
|
||||
|
||||
/* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
|
||||
vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint);
|
||||
vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV);
|
||||
out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance);
|
||||
out_sheen_radiance *= sheen * sheen_color;
|
||||
result.radiance += out_sheen_radiance;
|
||||
|
||||
/* Diffuse / Subsurface. */
|
||||
float scale = avg(sss_scale) * subsurface;
|
||||
closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result);
|
||||
}
|
||||
|
||||
if (transmission > 1e-5) {
|
||||
/* TODO(fclem) This could be going to a transmission render pass instead. */
|
||||
out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance);
|
||||
out_Refraction_3.radiance *= base_color.rgb;
|
||||
/* Simulate 2nd transmission event. */
|
||||
out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1);
|
||||
out_Refraction_3.radiance *= (1.0 - fresnel) * transmission;
|
||||
result.radiance += out_Refraction_3.radiance;
|
||||
}
|
||||
|
||||
if (clearcoat > 1e-5) {
|
||||
float NV = dot(in_Glossy_2.N, cameraVec);
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
|
||||
vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
|
||||
|
||||
out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
|
||||
out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
|
||||
result.radiance += out_Glossy_2.radiance;
|
||||
}
|
||||
|
||||
{
|
||||
vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
|
||||
out_emission_radiance *= emission_strength;
|
||||
result.radiance += out_emission_radiance;
|
||||
}
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_metallic(vec4 base_color,
|
||||
float subsurface,
|
||||
vec3 subsurface_radius,
|
||||
vec4 subsurface_color,
|
||||
float metallic,
|
||||
float specular,
|
||||
float specular_tint,
|
||||
float roughness,
|
||||
float anisotropic,
|
||||
float anisotropic_rotation,
|
||||
float sheen,
|
||||
float sheen_tint,
|
||||
float clearcoat,
|
||||
float clearcoat_roughness,
|
||||
float ior,
|
||||
float transmission,
|
||||
float transmission_roughness,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_spec, ssr_spec;
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
|
||||
|
||||
eevee_closure_glossy(N,
|
||||
base_color.rgb,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
result.ssr_data.rgb *= alpha;
|
||||
# ifdef USE_SSS
|
||||
result.sss_irradiance *= alpha;
|
||||
# endif
|
||||
}
|
||||
|
||||
void node_bsdf_principled_clearcoat(vec4 base_color,
|
||||
float subsurface,
|
||||
vec3 subsurface_radius,
|
||||
vec4 subsurface_color,
|
||||
float metallic,
|
||||
float specular,
|
||||
float specular_tint,
|
||||
float roughness,
|
||||
float anisotropic,
|
||||
float anisotropic_rotation,
|
||||
float sheen,
|
||||
float sheen_tint,
|
||||
float clearcoat,
|
||||
float clearcoat_roughness,
|
||||
float ior,
|
||||
float transmission,
|
||||
float transmission_roughness,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
vec3 out_spec, ssr_spec;
|
||||
N = normalize(N);
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
|
||||
|
||||
eevee_closure_clearcoat(N,
|
||||
base_color.rgb,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
CN,
|
||||
clearcoat * 0.25,
|
||||
clearcoat_roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
/* Match cycles. */
|
||||
float spec_col = 1.0 + float(clearcoat > 1e-5);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(spec_col), out_spec);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_subsurface(vec4 base_color,
|
||||
float subsurface,
|
||||
vec3 subsurface_radius,
|
||||
vec4 subsurface_color,
|
||||
float metallic,
|
||||
float specular,
|
||||
float specular_tint,
|
||||
float roughness,
|
||||
float anisotropic,
|
||||
float anisotropic_rotation,
|
||||
float sheen,
|
||||
float sheen_tint,
|
||||
float clearcoat,
|
||||
float clearcoat_roughness,
|
||||
float ior,
|
||||
float transmission,
|
||||
float transmission_roughness,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
metallic = saturate(metallic);
|
||||
N = normalize(N);
|
||||
|
||||
vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color;
|
||||
float out_sheen;
|
||||
vec3 ctint = tint_from_color(base_color.rgb);
|
||||
convert_metallic_to_specular_tinted(
|
||||
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
|
||||
|
||||
subsurface_color = subsurface_color * (1.0 - metallic);
|
||||
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
|
||||
float sss_scalef = avg(sss_scale) * subsurface;
|
||||
|
||||
float NV = dot(N, cameraVec);
|
||||
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
|
||||
|
||||
eevee_closure_skin(N,
|
||||
mixed_ss_base_color,
|
||||
f0,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure variations
|
||||
* or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
sss_scalef,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
mixed_ss_base_color *= alpha;
|
||||
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_glass(vec4 base_color,
|
||||
float subsurface,
|
||||
vec3 subsurface_radius,
|
||||
vec4 subsurface_color,
|
||||
float metallic,
|
||||
float specular,
|
||||
float specular_tint,
|
||||
float roughness,
|
||||
float anisotropic,
|
||||
float anisotropic_rotation,
|
||||
float sheen,
|
||||
float sheen_tint,
|
||||
float clearcoat,
|
||||
float clearcoat_roughness,
|
||||
float ior,
|
||||
float transmission,
|
||||
float transmission_roughness,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
ior = max(ior, 1e-5);
|
||||
N = normalize(N);
|
||||
|
||||
vec3 f0, out_spec, out_refr, ssr_spec;
|
||||
f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
|
||||
|
||||
eevee_closure_glass(N,
|
||||
vec3(1.0),
|
||||
vec3((use_multiscatter != 0.0) ? 1.0 : -1.0),
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
ior,
|
||||
true,
|
||||
out_spec,
|
||||
out_refr,
|
||||
ssr_spec);
|
||||
|
||||
vec3 refr_color = base_color.rgb;
|
||||
refr_color *= (refractionDepth > 0.0) ? refr_color :
|
||||
vec3(1.0); /* Simulate 2 transmission events */
|
||||
|
||||
float fresnel = F_eta(ior, dot(N, cameraVec));
|
||||
vec3 spec_col = F_color_blend(ior, fresnel, f0);
|
||||
spec_col *= fresnel;
|
||||
refr_color *= (1.0 - fresnel);
|
||||
|
||||
ssr_spec *= spec_col;
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color);
|
||||
result.radiance += render_pass_glossy_mask(spec_col, out_spec * spec_col);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
#else
|
||||
/* clang-format off */
|
||||
/* Stub principled because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_dielectric(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_metallic(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_clearcoat(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_subsurface(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_glass(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, result) (result = CLOSURE_DEFAULT)
|
||||
/* clang-format on */
|
||||
#endif
|
||||
|
@@ -1,15 +1,30 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_refraction, Refraction)
|
||||
|
||||
void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_refr;
|
||||
color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
|
||||
eevee_closure_refraction(N, roughness, ior, true, out_refr);
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
CLOSURE_VARS_DECLARE_1(Refraction);
|
||||
|
||||
in_Refraction_0.N = N; /* Normalized during eval. */
|
||||
in_Refraction_0.roughness = roughness;
|
||||
in_Refraction_0.ior = ior;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.ssr_normal = normal_encode(vN, viewCameraVec);
|
||||
result.radiance = render_pass_glossy_mask(color.rgb, out_refr * color.rgb);
|
||||
|
||||
out_Refraction_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_0.radiance);
|
||||
out_Refraction_0.radiance *= color.rgb;
|
||||
/* Simulate 2nd absorption event. */
|
||||
out_Refraction_0.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
|
||||
|
||||
result.radiance = out_Refraction_0.radiance;
|
||||
|
||||
/* TODO(fclem) Try to not use this. */
|
||||
result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N, viewCameraVec);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub refraction because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT)
|
||||
|
@@ -1,4 +1,7 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse)
|
||||
|
||||
void node_subsurface_scattering(vec4 color,
|
||||
float scale,
|
||||
vec3 radius,
|
||||
@@ -8,20 +11,29 @@ void node_subsurface_scattering(vec4 color,
|
||||
float sss_id,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_diff;
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
CLOSURE_VARS_DECLARE_1(Diffuse);
|
||||
|
||||
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = color.rgb;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
||||
|
||||
eevee_closure_subsurface(N, color.rgb, 1.0, scale, true, out_diff);
|
||||
/* Not perfect for texture_blur values between 0.0 and 1.0.
|
||||
* Interpolate between separated color and color applied on irradiance. */
|
||||
float one_minus_texture_blur = 1.0 - texture_blur;
|
||||
vec3 sss_albedo = color.rgb * texture_blur + one_minus_texture_blur;
|
||||
vec3 radiance_tint = color.rgb * one_minus_texture_blur + texture_blur;
|
||||
/* Consider output radiance as irradiance. */
|
||||
out_Diffuse_0.radiance *= radiance_tint;
|
||||
|
||||
/* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
|
||||
vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
|
||||
out_diff *= mix(vec3(1.0), color.rgb, texture_blur);
|
||||
result.radiance = render_pass_sss_mask(sss_albedo);
|
||||
closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result);
|
||||
closure_load_sss_data(scale, out_Diffuse_0.radiance, sss_albedo, int(sss_id), result);
|
||||
|
||||
/* TODO(fclem) Try to not use this. */
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub subsurface scattering because it is not compatible with volumetrics. */
|
||||
# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT)
|
||||
|
@@ -1,12 +1,20 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent)
|
||||
|
||||
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
CLOSURE_VARS_DECLARE_1(Translucent);
|
||||
|
||||
in_Translucent_0.N = -N; /* Normalized during eval. */
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_translucent, Translucent);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance);
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
||||
result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb);
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1.0, result);
|
||||
result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub translucent because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT)
|
||||
|
@@ -200,8 +200,6 @@ typedef enum eNodeSocketFlag {
|
||||
SOCK_NO_INTERNAL_LINK = (1 << 9),
|
||||
/** Draw socket in a more compact form. */
|
||||
SOCK_COMPACT = (1 << 10),
|
||||
/** Make the input socket accept multiple incoming links in the UI. */
|
||||
SOCK_MULTI_INPUT = (1 << 11),
|
||||
} eNodeSocketFlag;
|
||||
|
||||
/* limit data in bNode to what we want to see saved? */
|
||||
@@ -1195,13 +1193,6 @@ typedef struct NodeGeometryPointsToVolume {
|
||||
char _pad[6];
|
||||
} NodeGeometryPointsToVolume;
|
||||
|
||||
typedef struct NodeGeometryCollectionInfo {
|
||||
/* GeometryNodeTransformSpace. */
|
||||
uint8_t transform_space;
|
||||
|
||||
char _pad[7];
|
||||
} NodeGeometryCollectionInfo;
|
||||
|
||||
/* script node mode */
|
||||
#define NODE_SCRIPT_INTERNAL 0
|
||||
#define NODE_SCRIPT_EXTERNAL 1
|
||||
|
@@ -8911,33 +8911,6 @@ static void def_geo_points_to_volume(StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
}
|
||||
|
||||
static void def_geo_collection_info(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem rna_node_geometry_collection_info_transform_space_items[] = {
|
||||
{GEO_NODE_TRANSFORM_SPACE_ORIGINAL,
|
||||
"ORIGINAL",
|
||||
0,
|
||||
"Original",
|
||||
"Output the geometry relative to the collection offset"},
|
||||
{GEO_NODE_TRANSFORM_SPACE_RELATIVE,
|
||||
"RELATIVE",
|
||||
0,
|
||||
"Relative",
|
||||
"Bring the input collection geometry into the modified object, maintaining the relative "
|
||||
"position between the objects in the scene."},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometryCollectionInfo", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "transform_space", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_node_geometry_collection_info_transform_space_items);
|
||||
RNA_def_property_ui_text(prop, "Transform Space", "The transformation of the geometry output");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void rna_def_shader_node(BlenderRNA *brna)
|
||||
|
@@ -215,7 +215,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
|
||||
class GeometryNodesEvaluator {
|
||||
private:
|
||||
blender::LinearAllocator<> allocator_;
|
||||
Map<std::pair<const DInputSocket *, const DOutputSocket *>, GMutablePointer> value_by_input_;
|
||||
Map<const DInputSocket *, GMutablePointer> value_by_input_;
|
||||
Vector<const DInputSocket *> group_outputs_;
|
||||
blender::nodes::MultiFunctionByNode &mf_by_node_;
|
||||
const blender::nodes::DataTypeConversions &conversions_;
|
||||
@@ -246,8 +246,8 @@ class GeometryNodesEvaluator {
|
||||
{
|
||||
Vector<GMutablePointer> results;
|
||||
for (const DInputSocket *group_output : group_outputs_) {
|
||||
Vector<GMutablePointer> result = this->get_input_values(*group_output);
|
||||
results.append(result[0]);
|
||||
GMutablePointer result = this->get_input_value(*group_output);
|
||||
results.append(result);
|
||||
}
|
||||
for (GMutablePointer value : value_by_input_.values()) {
|
||||
value.destruct();
|
||||
@@ -256,53 +256,32 @@ class GeometryNodesEvaluator {
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<GMutablePointer> get_input_values(const DInputSocket &socket_to_compute)
|
||||
GMutablePointer get_input_value(const DInputSocket &socket_to_compute)
|
||||
{
|
||||
std::optional<GMutablePointer> value = value_by_input_.pop_try(&socket_to_compute);
|
||||
if (value.has_value()) {
|
||||
/* This input has been computed before, return it directly. */
|
||||
return *value;
|
||||
}
|
||||
|
||||
Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
|
||||
Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
|
||||
const int total_inputs = from_sockets.size() + from_group_inputs.size();
|
||||
BLI_assert(total_inputs <= 1);
|
||||
|
||||
if (total_inputs == 0) {
|
||||
/* The input is not connected, use the value from the socket itself. */
|
||||
return {get_unlinked_input_value(socket_to_compute)};
|
||||
return get_unlinked_input_value(socket_to_compute);
|
||||
}
|
||||
|
||||
if (from_group_inputs.size() == 1) {
|
||||
return {get_unlinked_input_value(socket_to_compute)};
|
||||
}
|
||||
|
||||
/* Multi-input sockets contain a vector of inputs. */
|
||||
if (socket_to_compute.is_multi_input_socket()) {
|
||||
Vector<GMutablePointer> values;
|
||||
for (const DOutputSocket *from_socket : from_sockets) {
|
||||
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
|
||||
&socket_to_compute, from_socket);
|
||||
std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
|
||||
if (value.has_value()) {
|
||||
values.append(value.value());
|
||||
}
|
||||
else {
|
||||
this->compute_output_and_forward(*from_socket);
|
||||
GMutablePointer value = value_by_input_.pop(key);
|
||||
values.append(value);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
const DOutputSocket &from_socket = *from_sockets[0];
|
||||
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
|
||||
&socket_to_compute, &from_socket);
|
||||
std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
|
||||
if (value.has_value()) {
|
||||
/* This input has been computed before, return it directly. */
|
||||
return {*value};
|
||||
/* The input gets its value from the input of a group that is not further connected. */
|
||||
return get_unlinked_input_value(socket_to_compute);
|
||||
}
|
||||
|
||||
/* Compute the socket now. */
|
||||
const DOutputSocket &from_socket = *from_sockets[0];
|
||||
this->compute_output_and_forward(from_socket);
|
||||
return {value_by_input_.pop(key)};
|
||||
return value_by_input_.pop(&socket_to_compute);
|
||||
}
|
||||
|
||||
void compute_output_and_forward(const DOutputSocket &socket_to_compute)
|
||||
@@ -323,14 +302,8 @@ class GeometryNodesEvaluator {
|
||||
GValueMap<StringRef> node_inputs_map{allocator_};
|
||||
for (const DInputSocket *input_socket : node.inputs()) {
|
||||
if (input_socket->is_available()) {
|
||||
Vector<GMutablePointer> values = this->get_input_values(*input_socket);
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
/* Values from Multi Input Sockets are stored in input map with the format
|
||||
* <identifier>[<index>]. */
|
||||
blender::StringRefNull key = allocator_.copy_string(
|
||||
input_socket->identifier() + (i > 0 ? ("[" + std::to_string(i)) + "]" : ""));
|
||||
node_inputs_map.add_new_direct(key, std::move(values[i]));
|
||||
}
|
||||
GMutablePointer value = this->get_input_value(*input_socket);
|
||||
node_inputs_map.add_new_direct(input_socket->identifier(), value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,15 +393,13 @@ class GeometryNodesEvaluator {
|
||||
|
||||
void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
|
||||
{
|
||||
/* For all sockets that are linked with the from_socket push the value to their node. */
|
||||
Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets();
|
||||
|
||||
const CPPType &from_type = *value_to_forward.type();
|
||||
|
||||
Vector<const DInputSocket *> to_sockets_same_type;
|
||||
for (const DInputSocket *to_socket : to_sockets_all) {
|
||||
const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo());
|
||||
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
|
||||
to_socket, &from_socket);
|
||||
if (from_type == to_type) {
|
||||
to_sockets_same_type.append(to_socket);
|
||||
}
|
||||
@@ -440,7 +411,7 @@ class GeometryNodesEvaluator {
|
||||
else {
|
||||
to_type.copy_to_uninitialized(to_type.default_value(), buffer);
|
||||
}
|
||||
add_value_to_input_socket(key, GMutablePointer{to_type, buffer});
|
||||
value_by_input_.add_new(to_socket, GMutablePointer{to_type, buffer});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,35 +422,23 @@ class GeometryNodesEvaluator {
|
||||
else if (to_sockets_same_type.size() == 1) {
|
||||
/* This value is only used on one input socket, no need to copy it. */
|
||||
const DInputSocket *to_socket = to_sockets_same_type[0];
|
||||
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
|
||||
to_socket, &from_socket);
|
||||
|
||||
add_value_to_input_socket(key, value_to_forward);
|
||||
value_by_input_.add_new(to_socket, value_to_forward);
|
||||
}
|
||||
else {
|
||||
/* Multiple inputs use the value, make a copy for every input except for one. */
|
||||
const DInputSocket *first_to_socket = to_sockets_same_type[0];
|
||||
Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
|
||||
const CPPType &type = *value_to_forward.type();
|
||||
const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair(
|
||||
first_to_socket, &from_socket);
|
||||
add_value_to_input_socket(first_key, value_to_forward);
|
||||
|
||||
value_by_input_.add_new(first_to_socket, value_to_forward);
|
||||
for (const DInputSocket *to_socket : other_to_sockets) {
|
||||
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
|
||||
to_socket, &from_socket);
|
||||
void *buffer = allocator_.allocate(type.size(), type.alignment());
|
||||
type.copy_to_uninitialized(value_to_forward.get(), buffer);
|
||||
add_value_to_input_socket(key, GMutablePointer{type, buffer});
|
||||
value_by_input_.add_new(to_socket, GMutablePointer{type, buffer});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_value_to_input_socket(const std::pair<const DInputSocket *, const DOutputSocket *> key,
|
||||
GMutablePointer value)
|
||||
{
|
||||
value_by_input_.add_new(key, value);
|
||||
}
|
||||
|
||||
GMutablePointer get_unlinked_input_value(const DInputSocket &socket)
|
||||
{
|
||||
bNodeSocket *bsocket;
|
||||
|
@@ -150,7 +150,6 @@ set(SRC
|
||||
geometry/nodes/node_geo_attribute_randomize.cc
|
||||
geometry/nodes/node_geo_attribute_vector_math.cc
|
||||
geometry/nodes/node_geo_boolean.cc
|
||||
geometry/nodes/node_geo_collection_info.cc
|
||||
geometry/nodes/node_geo_common.cc
|
||||
geometry/nodes/node_geo_edge_split.cc
|
||||
geometry/nodes/node_geo_join_geometry.cc
|
||||
|
@@ -80,7 +80,6 @@ class DInputSocket : public DSocket {
|
||||
private:
|
||||
Vector<DOutputSocket *> linked_sockets_;
|
||||
Vector<DGroupInput *> linked_group_inputs_;
|
||||
bool is_multi_input_socket_;
|
||||
|
||||
friend DerivedNodeTree;
|
||||
|
||||
@@ -91,7 +90,6 @@ class DInputSocket : public DSocket {
|
||||
Span<const DGroupInput *> linked_group_inputs() const;
|
||||
|
||||
bool is_linked() const;
|
||||
bool is_multi_input_socket() const;
|
||||
};
|
||||
|
||||
class DOutputSocket : public DSocket {
|
||||
@@ -364,11 +362,6 @@ inline bool DInputSocket::is_linked() const
|
||||
return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0;
|
||||
}
|
||||
|
||||
inline bool DInputSocket::is_multi_input_socket() const
|
||||
{
|
||||
return is_multi_input_socket_;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* DOutputSocket inline methods.
|
||||
*/
|
||||
|
@@ -49,7 +49,6 @@ void register_node_type_geo_point_rotate(void);
|
||||
void register_node_type_geo_align_rotation_to_vector(void);
|
||||
void register_node_type_geo_sample_texture(void);
|
||||
void register_node_type_geo_points_to_volume(void);
|
||||
void register_node_type_geo_collection_info(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -103,25 +103,6 @@ class GeoNodeExecParams {
|
||||
return input_values_.extract<T>(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get input as vector for multi input socket with the given identifier.
|
||||
*
|
||||
* This method can only be called once for each identifier.
|
||||
*/
|
||||
template<typename T> Vector<T> extract_multi_input(StringRef identifier)
|
||||
{
|
||||
Vector<T> values;
|
||||
values.append(input_values_.extract<T>(identifier));
|
||||
int i = 1;
|
||||
std::string sub_identifier = identifier + "[1]";
|
||||
while (input_values_.contains(sub_identifier)) {
|
||||
values.append(input_values_.extract<T>(sub_identifier));
|
||||
i++;
|
||||
sub_identifier = identifier + "[" + std::to_string(i) + "]";
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input value for the input socket with the given identifier.
|
||||
*
|
||||
|
@@ -291,7 +291,6 @@ DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE",
|
||||
DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "")
|
||||
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
|
||||
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
|
||||
|
||||
/* undefine macros */
|
||||
#undef DefNode
|
||||
|
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
|
||||
static bNodeSocketTemplate geo_node_collection_info_in[] = {
|
||||
{SOCK_COLLECTION, N_("Collection")},
|
||||
{-1, ""},
|
||||
};
|
||||
|
||||
static bNodeSocketTemplate geo_node_collection_info_out[] = {
|
||||
{SOCK_GEOMETRY, N_("Geometry")},
|
||||
{-1, ""},
|
||||
};
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void geo_node_collection_info_exec(GeoNodeExecParams params)
|
||||
{
|
||||
bke::PersistentCollectionHandle collection_handle =
|
||||
params.extract_input<bke::PersistentCollectionHandle>("Collection");
|
||||
Collection *collection = params.handle_map().lookup(collection_handle);
|
||||
|
||||
GeometrySet geometry_set_out;
|
||||
|
||||
if (collection == nullptr) {
|
||||
params.set_output("Geometry", geometry_set_out);
|
||||
return;
|
||||
}
|
||||
|
||||
const bNode &bnode = params.node();
|
||||
NodeGeometryCollectionInfo *node_storage = (NodeGeometryCollectionInfo *)bnode.storage;
|
||||
const bool transform_space_relative = (node_storage->transform_space ==
|
||||
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
|
||||
|
||||
InstancedData instance;
|
||||
instance.type = INSTANCE_DATA_TYPE_COLLECTION;
|
||||
instance.data.collection = collection;
|
||||
|
||||
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
|
||||
|
||||
float transform_mat[4][4];
|
||||
unit_m4(transform_mat);
|
||||
const Object *self_object = params.self_object();
|
||||
|
||||
if (transform_space_relative) {
|
||||
copy_v3_v3(transform_mat[3], collection->instance_offset);
|
||||
|
||||
mul_m4_m4_pre(transform_mat, self_object->imat);
|
||||
|
||||
float3 self_loc;
|
||||
copy_v3_v3(self_loc, self_object->obmat[3]);
|
||||
}
|
||||
instances.add_instance(instance, transform_mat, -1);
|
||||
|
||||
params.set_output("Geometry", geometry_set_out);
|
||||
}
|
||||
|
||||
static void geo_node_collection_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
|
||||
{
|
||||
NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN(
|
||||
sizeof(NodeGeometryCollectionInfo), __func__);
|
||||
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_geo_collection_info()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0);
|
||||
node_type_socket_templates(&ntype, geo_node_collection_info_in, geo_node_collection_info_out);
|
||||
node_type_init(&ntype, blender::nodes::geo_node_collection_info_node_init);
|
||||
node_type_storage(&ntype,
|
||||
"NodeGeometryCollectionInfo",
|
||||
node_free_standard_storage,
|
||||
node_copy_standard_storage);
|
||||
ntype.geometry_node_execute = blender::nodes::geo_node_collection_info_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
@@ -69,15 +69,35 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
|
||||
quat_to_eul(rotation, quaternion);
|
||||
|
||||
if (object != self_object) {
|
||||
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
|
||||
if (object->type == OB_MESH) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object, false);
|
||||
if (mesh != nullptr) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
|
||||
if (transform_space_relative) {
|
||||
instances.add_instance(object, transform);
|
||||
/* Make a copy because the life time of the other mesh might be shorter. */
|
||||
Mesh *copied_mesh = BKE_mesh_copy_for_eval(mesh, false);
|
||||
|
||||
if (transform_space_relative) {
|
||||
/* Transform into the local space of the object that is being modified. */
|
||||
BKE_mesh_transform(copied_mesh, transform, true);
|
||||
}
|
||||
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(copied_mesh);
|
||||
mesh_component.copy_vertex_group_names_from_object(*object);
|
||||
}
|
||||
}
|
||||
else {
|
||||
float unit_transform[4][4];
|
||||
unit_m4(unit_transform);
|
||||
instances.add_instance(object, unit_transform);
|
||||
if (object->type == OB_VOLUME) {
|
||||
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
|
||||
|
||||
if (transform_space_relative) {
|
||||
instances.add_instance(object, transform);
|
||||
}
|
||||
else {
|
||||
float unit_transform[4][4];
|
||||
unit_m4(unit_transform);
|
||||
instances.add_instance(object, unit_transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -79,7 +79,6 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
|
||||
}
|
||||
|
||||
static void sample_mesh_surface(const Mesh &mesh,
|
||||
const float4x4 &transform,
|
||||
const float base_density,
|
||||
const FloatReadAttribute *density_factors,
|
||||
const int seed,
|
||||
@@ -94,10 +93,9 @@ static void sample_mesh_surface(const Mesh &mesh,
|
||||
const int v0_index = mesh.mloop[looptri.tri[0]].v;
|
||||
const int v1_index = mesh.mloop[looptri.tri[1]].v;
|
||||
const int v2_index = mesh.mloop[looptri.tri[2]].v;
|
||||
|
||||
const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co);
|
||||
const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co);
|
||||
const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co);
|
||||
const float3 v0_pos = mesh.mvert[v0_index].co;
|
||||
const float3 v1_pos = mesh.mvert[v1_index].co;
|
||||
const float3 v2_pos = mesh.mvert[v2_index].co;
|
||||
|
||||
float looptri_density_factor = 1.0f;
|
||||
if (density_factors != nullptr) {
|
||||
@@ -196,8 +194,8 @@ BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
|
||||
const float v1_density_factor = std::max(0.0f, density_factors[v1_index]);
|
||||
const float v2_density_factor = std::max(0.0f, density_factors[v2_index]);
|
||||
|
||||
const float probablity = attribute_math::mix3<float>(
|
||||
bary_coord, v0_density_factor, v1_density_factor, v2_density_factor);
|
||||
const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
|
||||
v2_density_factor * bary_coord.z;
|
||||
|
||||
const float hash = BLI_hash_int_01(bary_coord.hash());
|
||||
if (hash > probablity) {
|
||||
@@ -388,174 +386,77 @@ BLI_NOINLINE static void add_remaining_point_attributes(const MeshComponent &mes
|
||||
*mesh_component.get_for_read(), component, bary_coords, looptri_indices);
|
||||
}
|
||||
|
||||
struct AttributeInfo {
|
||||
std::string name;
|
||||
Vector<CustomDataType> data_types;
|
||||
Vector<AttributeDomain> domains;
|
||||
};
|
||||
|
||||
struct ScatterPointsOnMeshOp {
|
||||
/* Input data. */
|
||||
const GeometryNodePointDistributeMethod distribute_method;
|
||||
const std::string &density_attribute_name;
|
||||
const int seed;
|
||||
const float density;
|
||||
|
||||
/* Output data. */
|
||||
Vector<float3> &positions;
|
||||
Vector<float3> &bary_coords;
|
||||
Vector<int> &looptri_indices;
|
||||
Set<AttributeInfo> &attributes;
|
||||
|
||||
void operator()(const GeometryComponent &component, blender::Span<blender::float4x4> transforms)
|
||||
{
|
||||
if (component.type() != GeometryComponentType::Mesh) {
|
||||
return;
|
||||
}
|
||||
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
if (!mesh_component.has_mesh()) {
|
||||
return;
|
||||
}
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
for (const float4x4 &transform : transforms) {
|
||||
switch (distribute_method) {
|
||||
case GEO_NODE_POINT_DISTRIBUTE_RANDOM: {
|
||||
const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>(
|
||||
density_attribute_name, ATTR_DOMAIN_POINT, 1.0f);
|
||||
sample_mesh_surface(mesh,
|
||||
transform,
|
||||
density,
|
||||
&density_factors,
|
||||
seed,
|
||||
positions,
|
||||
bary_coords,
|
||||
looptri_indices);
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_POINT_DISTRIBUTE_POISSON:
|
||||
sample_mesh_surface(
|
||||
mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct PoissonEliminateFromDensityOp {
|
||||
/* Input data. */
|
||||
const std::string &density_attribute_name;
|
||||
const float density;
|
||||
Span<float3> bary_coords;
|
||||
Span<int> looptri_indices;
|
||||
|
||||
/* Output data. */
|
||||
MutableSpan<bool> elimination_mask;
|
||||
|
||||
void operator()(const GeometryComponent &component, blender::Span<blender::float4x4> transforms)
|
||||
{
|
||||
if (component.type() != GeometryComponentType::Mesh) {
|
||||
return;
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
if (!mesh_component.has_mesh()) {
|
||||
return;
|
||||
}
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
for (const float4x4 &transform : transforms) {
|
||||
const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>(
|
||||
density_attribute_name, ATTR_DOMAIN_POINT, 1.0f);
|
||||
update_elimination_mask_based_on_density_factors(
|
||||
mesh, density_factors, bary_coords, looptri_indices, elimination_mask);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct AttributeInterpolateOp {
|
||||
/* Input data. */
|
||||
const std::string &density_attribute_name;
|
||||
const float density;
|
||||
Span<float3> bary_coords;
|
||||
Span<int> looptri_indices;
|
||||
|
||||
int index_offset = 0;
|
||||
|
||||
/* Output data. */
|
||||
MutableSpan<bool> elimination_mask;
|
||||
|
||||
void operator()(const GeometryComponent &component, blender::Span<blender::float4x4> transforms)
|
||||
{
|
||||
if (component.type() != GeometryComponentType::Mesh) {
|
||||
return;
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
if (!mesh_component.has_mesh()) {
|
||||
return;
|
||||
}
|
||||
const Mesh &mesh = *mesh_component.get_for_read();
|
||||
for (const float4x4 &transform : transforms) {
|
||||
|
||||
const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>(
|
||||
density_attribute_name, ATTR_DOMAIN_POINT, 1.0f);
|
||||
update_elimination_mask_based_on_density_factors(
|
||||
mesh, density_factors, bary_coords, looptri_indices, elimination_mask);
|
||||
}
|
||||
}
|
||||
};
|
||||
static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh,
|
||||
const float max_density,
|
||||
const float minimum_distance,
|
||||
const FloatReadAttribute &density_factors,
|
||||
const int seed,
|
||||
Vector<float3> &r_positions,
|
||||
Vector<float3> &r_bary_coords,
|
||||
Vector<int> &r_looptri_indices)
|
||||
{
|
||||
sample_mesh_surface(
|
||||
mesh, max_density, nullptr, seed, r_positions, r_bary_coords, r_looptri_indices);
|
||||
Array<bool> elimination_mask(r_positions.size(), false);
|
||||
update_elimination_mask_for_close_points(r_positions, minimum_distance, elimination_mask);
|
||||
update_elimination_mask_based_on_density_factors(
|
||||
mesh, density_factors, r_bary_coords, r_looptri_indices, elimination_mask);
|
||||
eliminate_points_based_on_mask(elimination_mask, r_positions, r_bary_coords, r_looptri_indices);
|
||||
}
|
||||
|
||||
static void geo_node_point_distribute_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||
GeometrySet geometry_set_out;
|
||||
|
||||
const GeometryNodePointDistributeMethod distribute_method =
|
||||
GeometryNodePointDistributeMethod distribute_method =
|
||||
static_cast<GeometryNodePointDistributeMethod>(params.node().custom1);
|
||||
|
||||
if (!geometry_set.has_mesh() && !geometry_set.has_instances()) {
|
||||
if (!geometry_set.has_mesh()) {
|
||||
params.set_output("Geometry", std::move(geometry_set_out));
|
||||
return;
|
||||
}
|
||||
|
||||
const float density = params.extract_input<float>("Density Max");
|
||||
const std::string density_attribute_name = params.extract_input<std::string>(
|
||||
"Density Attribute");
|
||||
const std::string density_attribute = params.extract_input<std::string>("Density Attribute");
|
||||
|
||||
if (density <= 0.0f) {
|
||||
params.set_output("Geometry", std::move(geometry_set_out));
|
||||
return;
|
||||
}
|
||||
|
||||
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
const Mesh *mesh_in = mesh_component.get_for_read();
|
||||
|
||||
if (mesh_in == nullptr || mesh_in->mpoly == nullptr) {
|
||||
params.set_output("Geometry", std::move(geometry_set_out));
|
||||
return;
|
||||
}
|
||||
|
||||
const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>(
|
||||
density_attribute, ATTR_DOMAIN_POINT, 1.0f);
|
||||
const int seed = params.get_input<int>("Seed");
|
||||
|
||||
Vector<float3> positions;
|
||||
Vector<float3> bary_coords;
|
||||
Vector<int> looptri_indices;
|
||||
Set<AttributeInfo> attributes;
|
||||
|
||||
ScatterPointsOnMeshOp scatter_points_op{distribute_method,
|
||||
density_attribute_name,
|
||||
seed,
|
||||
density,
|
||||
positions,
|
||||
bary_coords,
|
||||
looptri_indices,
|
||||
attributes};
|
||||
BKE_foreach_geometry_component_recursive(geometry_set, scatter_points_op);
|
||||
|
||||
/* Eliminate points based on the minimum distance for the poisson disk case. */
|
||||
if (distribute_method == GEO_NODE_POINT_DISTRIBUTE_POISSON) {
|
||||
Array<bool> elimination_mask(positions.size(), false);
|
||||
const float minimum_distance = params.get_input<float>("Distance Min");
|
||||
|
||||
update_elimination_mask_for_close_points(positions, minimum_distance, elimination_mask);
|
||||
|
||||
PoissonEliminateFromDensityOp eliminate_density_op{
|
||||
density_attribute_name, density, bary_coords, looptri_indices};
|
||||
BKE_foreach_geometry_component_recursive(geometry_set, eliminate_density_op);
|
||||
|
||||
eliminate_points_based_on_mask(elimination_mask, positions, bary_coords, looptri_indices);
|
||||
switch (distribute_method) {
|
||||
case GEO_NODE_POINT_DISTRIBUTE_RANDOM:
|
||||
sample_mesh_surface(
|
||||
*mesh_in, density, &density_factors, seed, positions, bary_coords, looptri_indices);
|
||||
break;
|
||||
case GEO_NODE_POINT_DISTRIBUTE_POISSON:
|
||||
const float minimum_distance = params.extract_input<float>("Distance Min");
|
||||
sample_mesh_surface_with_minimum_distance(*mesh_in,
|
||||
density,
|
||||
minimum_distance,
|
||||
density_factors,
|
||||
seed,
|
||||
positions,
|
||||
bary_coords,
|
||||
looptri_indices);
|
||||
break;
|
||||
}
|
||||
|
||||
const int tot_points = positions.size();
|
||||
|
||||
PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points);
|
||||
@@ -569,7 +470,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
|
||||
geometry_set_out.get_component_for_write<PointCloudComponent>();
|
||||
point_component.replace(pointcloud);
|
||||
|
||||
// add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices);
|
||||
add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices);
|
||||
|
||||
params.set_output("Geometry", std::move(geometry_set_out));
|
||||
}
|
||||
|
@@ -91,7 +91,7 @@ DNode &DerivedNodeTree::create_node(const NodeRef &node_ref,
|
||||
for (int i : node.inputs_.index_range()) {
|
||||
const InputSocketRef &socket_ref = node_ref.input(i);
|
||||
DInputSocket &socket = *node.inputs_[i];
|
||||
socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT;
|
||||
|
||||
socket.id_ = UNINITIALIZED_ID;
|
||||
socket.node_ = &node;
|
||||
socket.socket_ref_ = &socket_ref;
|
||||
|
@@ -281,30 +281,25 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Find an eligible socket for linking. */
|
||||
/* find an eligible socket for linking */
|
||||
static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur)
|
||||
{
|
||||
/* link swapping: try to find a free slot with a matching name */
|
||||
|
||||
bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
|
||||
bNodeSocket *sock;
|
||||
|
||||
/* Iterate over all sockets of the target node, to find one that matches the same socket type.
|
||||
* The idea behind this is: When a user connects an input to a socket that is
|
||||
* already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
|
||||
* the link that we try to overwrite and connect that previous link to the new socket. */
|
||||
sock = cur->next ? cur->next : first; /* Wrap around the list end. */
|
||||
sock = cur->next ? cur->next : first; /* wrap around the list end */
|
||||
while (sock != cur) {
|
||||
if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) {
|
||||
break;
|
||||
int link_count = node_count_links(ntree, sock);
|
||||
/* take +1 into account since we would add a new link */
|
||||
if (link_count + 1 <= nodeSocketLinkLimit(sock)) {
|
||||
return sock; /* found a valid free socket we can swap to */
|
||||
}
|
||||
}
|
||||
sock = sock->next ? sock->next : first; /* Wrap around the list end. */
|
||||
}
|
||||
|
||||
if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) {
|
||||
int link_count = node_count_links(ntree, sock);
|
||||
/* Take +1 into account since we would add a new link. */
|
||||
if (link_count + 1 <= nodeSocketLinkLimit(sock)) {
|
||||
return sock; /* Found a valid free socket we can swap to. */
|
||||
}
|
||||
sock = sock->next ? sock->next : first; /* wrap around the list end */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -314,6 +309,7 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
bNodeSocket *sock = link->tosock;
|
||||
bNodeLink *tlink, *tlink_next;
|
||||
|
||||
/* inputs can have one link only, outputs can have unlimited links */
|
||||
if (node != link->tonode) {
|
||||
return;
|
||||
}
|
||||
|
@@ -134,54 +134,32 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
|
||||
GPU_link(mat, "set_rgb_one", &sss_scale);
|
||||
}
|
||||
|
||||
/* Due to the manual effort done per config, we only optimize the most common permutations. */
|
||||
char *node_name;
|
||||
uint flag = 0;
|
||||
if (!use_subsurf && use_diffuse && !use_refract && !use_clear) {
|
||||
static char name[] = "node_bsdf_principled_dielectric";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
|
||||
uint flag = GPU_MATFLAG_GLOSSY;
|
||||
if (use_diffuse) {
|
||||
flag |= GPU_MATFLAG_DIFFUSE;
|
||||
}
|
||||
else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) {
|
||||
static char name[] = "node_bsdf_principled_metallic";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_GLOSSY;
|
||||
if (use_refract) {
|
||||
flag |= GPU_MATFLAG_REFRACT;
|
||||
}
|
||||
else if (!use_subsurf && !use_diffuse && !use_refract && use_clear) {
|
||||
static char name[] = "node_bsdf_principled_clearcoat";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_GLOSSY;
|
||||
}
|
||||
else if (use_subsurf && use_diffuse && !use_refract && !use_clear) {
|
||||
static char name[] = "node_bsdf_principled_subsurface";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
|
||||
}
|
||||
else if (!use_subsurf && !use_diffuse && use_refract && !use_clear && !socket_not_zero(4)) {
|
||||
static char name[] = "node_bsdf_principled_glass";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
|
||||
}
|
||||
else {
|
||||
static char name[] = "node_bsdf_principled";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
|
||||
}
|
||||
|
||||
if (use_subsurf) {
|
||||
flag |= GPU_MATFLAG_SSS;
|
||||
}
|
||||
|
||||
float f_use_diffuse = use_diffuse ? 1.0f : 0.0f;
|
||||
float f_use_clearcoat = use_clear ? 1.0f : 0.0f;
|
||||
float f_use_refraction = use_refract ? 1.0f : 0.0f;
|
||||
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
|
||||
|
||||
GPU_material_flag_set(mat, flag);
|
||||
|
||||
return GPU_stack_link(mat,
|
||||
node,
|
||||
node_name,
|
||||
"node_bsdf_principled",
|
||||
in,
|
||||
out,
|
||||
GPU_builtin(GPU_VIEW_POSITION),
|
||||
GPU_constant(&f_use_diffuse),
|
||||
GPU_constant(&f_use_clearcoat),
|
||||
GPU_constant(&f_use_refraction),
|
||||
GPU_constant(&use_multi_scatter),
|
||||
GPU_constant(&node->ssr_id),
|
||||
GPU_constant(&node->sss_id),
|
||||
|
Reference in New Issue
Block a user