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>
|
<array>
|
||||||
<string>blend</string>
|
<string>blend</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>CFBundleTypeIconFile</key>
|
||||||
|
<string>blender file icon.icns</string>
|
||||||
<key>CFBundleTypeName</key>
|
<key>CFBundleTypeName</key>
|
||||||
<string>Blender File</string>
|
<string>Blender File</string>
|
||||||
<key>CFBundleTypeOSTypes</key>
|
<key>CFBundleTypeOSTypes</key>
|
||||||
@@ -21,12 +23,6 @@
|
|||||||
<string>Editor</string>
|
<string>Editor</string>
|
||||||
<key>LSIsAppleDefaultForType</key>
|
<key>LSIsAppleDefaultForType</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSItemContentTypes</key>
|
|
||||||
<array>
|
|
||||||
<string>org.blenderfoundation.blender.file</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeIconSystemGenerated</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
@@ -53,30 +49,5 @@
|
|||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<true/>
|
<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>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
Binary file not shown.
@@ -502,7 +502,6 @@ geometry_node_categories = [
|
|||||||
]),
|
]),
|
||||||
GeometryNodeCategory("GEO_INPUT", "Input", items=[
|
GeometryNodeCategory("GEO_INPUT", "Input", items=[
|
||||||
NodeItem("GeometryNodeObjectInfo"),
|
NodeItem("GeometryNodeObjectInfo"),
|
||||||
NodeItem("GeometryNodeCollectionInfo"),
|
|
||||||
NodeItem("FunctionNodeRandomFloat"),
|
NodeItem("FunctionNodeRandomFloat"),
|
||||||
NodeItem("ShaderNodeValue"),
|
NodeItem("ShaderNodeValue"),
|
||||||
NodeItem("FunctionNodeInputVector"),
|
NodeItem("FunctionNodeInputVector"),
|
||||||
|
@@ -476,9 +476,3 @@ class VolumeComponent : public GeometryComponent {
|
|||||||
|
|
||||||
static constexpr inline GeometryComponentType static_type = GeometryComponentType::Volume;
|
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_POINT_SCALE 1020
|
||||||
#define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021
|
#define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021
|
||||||
#define GEO_NODE_POINTS_TO_VOLUME 1022
|
#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.
|
* 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_geometry_set.hh"
|
||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
#include "BKE_mesh_wrapper.h"
|
#include "BKE_mesh_wrapper.h"
|
||||||
#include "BKE_modifier.h"
|
|
||||||
#include "BKE_pointcloud.h"
|
#include "BKE_pointcloud.h"
|
||||||
#include "BKE_volume.h"
|
#include "BKE_volume.h"
|
||||||
|
|
||||||
#include "DNA_collection_types.h"
|
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
using blender::float3;
|
using blender::float3;
|
||||||
using blender::float4x4;
|
using blender::float4x4;
|
||||||
using blender::ListBaseWrapper;
|
|
||||||
using blender::MutableSpan;
|
using blender::MutableSpan;
|
||||||
using blender::Span;
|
using blender::Span;
|
||||||
using blender::StringRef;
|
using blender::StringRef;
|
||||||
@@ -571,180 +566,6 @@ bool InstancesComponent::is_empty() const
|
|||||||
return transforms_.size() == 0;
|
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)
|
int nodeSocketLinkLimit(const bNodeSocket *sock)
|
||||||
{
|
{
|
||||||
bNodeSocketType *stype = sock->typeinfo;
|
bNodeSocketType *stype = sock->typeinfo;
|
||||||
if (sock->flag & SOCK_MULTI_INPUT) {
|
|
||||||
return 4095;
|
|
||||||
}
|
|
||||||
if (stype != nullptr && stype->use_link_limits_of_type) {
|
if (stype != nullptr && stype->use_link_limits_of_type) {
|
||||||
int limit = (sock->in_out == SOCK_IN) ? stype->input_link_limit : stype->output_link_limit;
|
int limit = (sock->in_out == SOCK_IN) ? stype->input_link_limit : stype->output_link_limit;
|
||||||
return limit;
|
return limit;
|
||||||
@@ -4773,7 +4770,6 @@ static void registerGeometryNodes()
|
|||||||
register_node_type_geo_align_rotation_to_vector();
|
register_node_type_geo_align_rotation_to_vector();
|
||||||
register_node_type_geo_sample_texture();
|
register_node_type_geo_sample_texture();
|
||||||
register_node_type_geo_points_to_volume();
|
register_node_type_geo_points_to_volume();
|
||||||
register_node_type_geo_collection_info();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerFunctionNodes()
|
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/ambient_occlusion_lib.glsl SRC)
|
||||||
data_to_c_simple(engines/eevee/shaders/background_vert.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_uniforms_lib.glsl SRC)
|
||||||
data_to_c_simple(engines/eevee/shaders/common_utiltex_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)
|
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_frag.glsl SRC)
|
||||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.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/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_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_vert.glsl SRC)
|
||||||
data_to_c_simple(engines/eevee/shaders/effect_dof_frag.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, "hitBuffer", &effects->ssr_hit_output);
|
||||||
DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_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, "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, "grid_block", sldata->grid_ubo);
|
||||||
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
|
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
|
||||||
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_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_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
|
||||||
DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
|
DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
|
||||||
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
|
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);
|
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -142,7 +142,6 @@ static struct {
|
|||||||
struct GPUShader *volumetric_accum_sh;
|
struct GPUShader *volumetric_accum_sh;
|
||||||
|
|
||||||
/* Shader strings */
|
/* Shader strings */
|
||||||
char *closure_lit_lib;
|
|
||||||
char *surface_lit_frag;
|
char *surface_lit_frag;
|
||||||
char *surface_prepass_frag;
|
char *surface_prepass_frag;
|
||||||
char *surface_geom_barycentric;
|
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_lut_frag_glsl[];
|
||||||
extern char datatoc_bsdf_sampling_lib_glsl[];
|
extern char datatoc_bsdf_sampling_lib_glsl[];
|
||||||
extern char datatoc_btdf_lut_frag_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_uniforms_lib_glsl[];
|
||||||
extern char datatoc_common_utiltex_lib_glsl[];
|
extern char datatoc_common_utiltex_lib_glsl[];
|
||||||
extern char datatoc_cryptomatte_frag_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_planar_downsample_vert_glsl[];
|
||||||
extern char datatoc_lightprobe_vert_glsl[];
|
extern char datatoc_lightprobe_vert_glsl[];
|
||||||
extern char datatoc_lights_lib_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_ltc_lib_glsl[];
|
||||||
extern char datatoc_object_motion_frag_glsl[];
|
extern char datatoc_object_motion_frag_glsl[];
|
||||||
extern char datatoc_object_motion_vert_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, lights_lib);
|
||||||
DRW_SHADER_LIB_ADD(e_data.lib, surface_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, volumetric_lib);
|
||||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_lib);
|
|
||||||
DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
|
DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
|
||||||
|
DRW_SHADER_LIB_ADD(e_data.lib, closure_type_lib);
|
||||||
/* Add one for each Closure */
|
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_lib);
|
||||||
e_data.closure_lit_lib = BLI_string_joinN(datatoc_closure_lit_lib_glsl,
|
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_diffuse_lib);
|
||||||
datatoc_closure_lit_lib_glsl,
|
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_glossy_lib);
|
||||||
datatoc_closure_lit_lib_glsl,
|
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_translucent_lib);
|
||||||
datatoc_closure_lit_lib_glsl,
|
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib);
|
||||||
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");
|
|
||||||
|
|
||||||
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
|
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
|
||||||
datatoc_surface_frag_glsl);
|
datatoc_surface_frag_glsl);
|
||||||
@@ -1403,7 +1396,6 @@ struct GPUMaterial *EEVEE_material_get(
|
|||||||
|
|
||||||
void EEVEE_shaders_free(void)
|
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_prepass_frag);
|
||||||
MEM_SAFE_FREE(e_data.surface_lit_frag);
|
MEM_SAFE_FREE(e_data.surface_lit_frag);
|
||||||
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
|
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.xy = get_ao_dir(noise.x * 0.5);
|
||||||
dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
|
dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
|
||||||
|
|
||||||
bent_normal = normal * 1e-8;
|
bent_normal = vec3(0.0);
|
||||||
visibility = 1e-8;
|
visibility = 0.0;
|
||||||
|
|
||||||
horizons = unpack_horizons(horizons);
|
horizons = unpack_horizons(horizons);
|
||||||
|
|
||||||
integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal);
|
integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal);
|
||||||
integrate_slice(normal, dirs.zw, horizons.zw, 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. */
|
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);
|
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)
|
float specular_occlusion(float NV, float AO, float roughness)
|
||||||
{
|
{
|
||||||
return saturate(pow(NV + AO, roughness) - 1.0 + AO);
|
return saturate(pow(NV + AO, roughness) - 1.0 + AO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the right occlusion */
|
/* 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
|
#ifndef USE_REFRACTION
|
||||||
if ((int(aoSettings) & USE_AO) != 0) {
|
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);
|
visibility = max(1e-3, visibility);
|
||||||
|
|
||||||
if ((int(aoSettings) & USE_BENT_NORMAL) != 0) {
|
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);
|
bent_normal = transform_direction(ViewMatrixInverse, bent_normal);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -276,10 +283,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out
|
|||||||
/* Scale by user factor */
|
/* Scale by user factor */
|
||||||
visibility = pow(visibility, aoFactor);
|
visibility = pow(visibility, aoFactor);
|
||||||
|
|
||||||
return min(visibility, user_occlusion);
|
return visibility;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bent_normal = N;
|
bent_normal = N;
|
||||||
return user_occlusion;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,15 @@
|
|||||||
|
|
||||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
#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 specular_dominant_dir(vec3 N, vec3 V, float roughness)
|
||||||
{
|
{
|
||||||
vec3 R = -reflect(V, N);
|
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,
|
/* Unreal specular matching : if specular color is below 2% intensity,
|
||||||
* treat as shadowning */
|
* 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 :
|
/* 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. */
|
* by Carmelo J. Fdez-Agüera. */
|
||||||
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||||
{
|
{
|
||||||
vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
|
vec3 FssEss = lut.y * f90 + lut.x * f0;
|
||||||
/* Hack to avoid many more shader variations. */
|
|
||||||
if (f90.g < 0.0) {
|
|
||||||
return FssEss;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Ess = lut.x + lut.y;
|
float Ess = lut.x + lut.y;
|
||||||
float Ems = 1.0 - Ess;
|
float Ems = 1.0 - Ess;
|
||||||
@@ -102,8 +107,6 @@ vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
|||||||
return FssEss + Fms * Ems;
|
return FssEss + Fms * Ems;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define F_brdf(f0, f90, lut) F_brdf_multi_scatter(f0, f90, lut)
|
|
||||||
|
|
||||||
/* GGX */
|
/* GGX */
|
||||||
float D_ggx_opti(float NH, float a2)
|
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
|
#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(
|
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. */
|
/* Still encode to avoid artifacts in the SSR pass. */
|
||||||
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
||||||
cl.ssr_normal = normal_encode(vN, viewVec);
|
cl.ssr_normal = normal_encode(vN, viewCameraVec);
|
||||||
|
|
||||||
if (ssr_id == outputSsrId) {
|
if (ssrToggle && int(ssr_id) == outputSsrId) {
|
||||||
cl.ssr_data = vec4(ssr_spec, roughness);
|
cl.ssr_data = vec4(ssr_radiance, roughness);
|
||||||
cl.flag |= CLOSURE_SSR_FLAG;
|
cl.flag |= CLOSURE_SSR_FLAG;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
cl.radiance += ssr_radiance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closure_load_sss_data(
|
void closure_load_sss_data(
|
||||||
@@ -169,13 +179,11 @@ void closure_load_sss_data(
|
|||||||
cl.sss_radius = radius;
|
cl.sss_radius = radius;
|
||||||
cl.sss_albedo = sss_albedo;
|
cl.sss_albedo = sss_albedo;
|
||||||
cl.flag |= CLOSURE_SSS_FLAG;
|
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
|
# endif
|
||||||
{
|
cl.radiance += render_pass_diffuse_mask(vec3(1), sss_irradiance) * sss_albedo;
|
||||||
cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@@ -12,11 +12,20 @@ uniform sampler2DArray utilTex;
|
|||||||
|
|
||||||
#define LUT_SIZE 64
|
#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 */
|
/* Return texture coordinates to sample Surface LUT */
|
||||||
vec2 lut_coords(float cosTheta, float roughness)
|
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);
|
float theta = acos(cosTheta);
|
||||||
vec2 coords = vec2(roughness, theta / M_PI_2);
|
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;
|
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)
|
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;
|
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_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(common_utiltex_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(raytrace_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
||||||
@@ -170,7 +172,7 @@ void main()
|
|||||||
/* Importance sampling bias */
|
/* Importance sampling bias */
|
||||||
rand.x = mix(rand.x, 0.0, ssrBrdfBias);
|
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 wN = transform_direction(ViewMatrixInverse, N);
|
||||||
|
|
||||||
vec3 T, B;
|
vec3 T, B;
|
||||||
@@ -180,12 +182,12 @@ void main()
|
|||||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
||||||
PlanarData pd = planars_data[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) {
|
if (fade > 0.5) {
|
||||||
/* Find view vector / reflection plane intersection. */
|
/* Find view vector / reflection plane intersection. */
|
||||||
/* TODO optimize, use view space for all. */
|
/* 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);
|
tracePosition = transform_point(ViewMatrix, tracePosition);
|
||||||
vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
|
vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
|
||||||
|
|
||||||
@@ -213,6 +215,8 @@ uniform sampler2D pdfBuffer;
|
|||||||
|
|
||||||
uniform int neighborOffset;
|
uniform int neighborOffset;
|
||||||
|
|
||||||
|
in vec4 uvcoordsvar;
|
||||||
|
|
||||||
const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0),
|
const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0),
|
||||||
ivec2(1, 1),
|
ivec2(1, 1),
|
||||||
ivec2(-2, 0),
|
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,
|
vec3 get_hit_vector(vec3 hit_pos,
|
||||||
PlanarData pd,
|
PlanarData pd,
|
||||||
vec3 worldPosition,
|
vec3 P,
|
||||||
vec3 N,
|
vec3 N,
|
||||||
vec3 V,
|
vec3 V,
|
||||||
bool is_planar,
|
bool is_planar,
|
||||||
@@ -309,7 +313,7 @@ vec3 get_hit_vector(vec3 hit_pos,
|
|||||||
|
|
||||||
if (is_planar) {
|
if (is_planar) {
|
||||||
/* Reflect back the hit position to have it in non-reflected world space */
|
/* 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 = hit_pos - trace_pos;
|
||||||
hit_vec = reflect(hit_vec, pd.pl_normal);
|
hit_vec = reflect(hit_vec, pd.pl_normal);
|
||||||
/* Modify here so mip texel alignment is correct. */
|
/* Modify here so mip texel alignment is correct. */
|
||||||
@@ -317,8 +321,8 @@ vec3 get_hit_vector(vec3 hit_pos,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Find hit position in previous frame. */
|
/* Find hit position in previous frame. */
|
||||||
hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
|
hit_co = get_reprojected_reflection(hit_pos, P, N);
|
||||||
hit_vec = hit_pos - worldPosition;
|
hit_vec = hit_pos - P;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask = screen_border_mask(hit_co);
|
mask = screen_border_mask(hit_co);
|
||||||
@@ -339,7 +343,7 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
|||||||
ivec4 hit_data[2],
|
ivec4 hit_data[2],
|
||||||
PlanarData pd,
|
PlanarData pd,
|
||||||
float planar_index,
|
float planar_index,
|
||||||
vec3 worldPosition,
|
vec3 P,
|
||||||
vec3 N,
|
vec3 N,
|
||||||
vec3 V,
|
vec3 V,
|
||||||
float roughnessSquared,
|
float roughnessSquared,
|
||||||
@@ -379,14 +383,10 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
|||||||
|
|
||||||
/* Get actual hit vector and hit coordinate (from last frame). */
|
/* Get actual hit vector and hit coordinate (from last frame). */
|
||||||
vec4 mask = vec4(1.0);
|
vec4 mask = vec4(1.0);
|
||||||
hit_pos[0] = get_hit_vector(
|
hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x);
|
||||||
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, P, N, V, is_planar.y, hit_co[0].zw, mask.y);
|
||||||
hit_pos[1] = get_hit_vector(
|
hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z);
|
||||||
hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y);
|
hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w);
|
||||||
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);
|
|
||||||
|
|
||||||
vec4 hit_dist;
|
vec4 hit_dist;
|
||||||
hit_dist.x = length(hit_pos[0]);
|
hit_dist.x = length(hit_pos[0]);
|
||||||
@@ -476,47 +476,30 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
|||||||
return accum;
|
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
|
# ifdef FULLRES
|
||||||
ivec2 halfres_texel = fullres_texel;
|
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||||
# else
|
# else
|
||||||
ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
|
ivec2 texel = ivec2(gl_FragCoord.xy / 2.0);
|
||||||
# endif
|
# 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 */
|
/* Using world space */
|
||||||
vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */
|
vec3 V = cl_common.V;
|
||||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
vec3 N = cl_in.N;
|
||||||
vec3 V = cameraVec;
|
vec3 P = cl_common.P;
|
||||||
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;
|
|
||||||
|
|
||||||
/* Early out */
|
float roughness = cl_in.roughness;
|
||||||
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
|
float roughnessSquared = max(1e-3, sqr(roughness));
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
float roughness = speccol_roughness.a;
|
|
||||||
float roughnessSquared = max(1e-3, roughness * roughness);
|
|
||||||
|
|
||||||
vec4 spec_accum = vec4(0.0);
|
|
||||||
|
|
||||||
/* Resolve SSR */
|
/* Resolve SSR */
|
||||||
float cone_cos = cone_cosine(roughnessSquared);
|
float cone_cos = cone_cosine(roughnessSquared);
|
||||||
float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
|
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 */
|
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);
|
vec4 ssr_accum = vec4(0.0);
|
||||||
float weight_acc = 0.0;
|
float weight_acc = 0.0;
|
||||||
@@ -525,16 +508,16 @@ void main()
|
|||||||
/* TODO optimize with textureGather */
|
/* TODO optimize with textureGather */
|
||||||
/* Doing these fetches early to hide latency. */
|
/* Doing these fetches early to hide latency. */
|
||||||
vec4 hit_pdf;
|
vec4 hit_pdf;
|
||||||
hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r;
|
hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r;
|
||||||
hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r;
|
hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r;
|
||||||
hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r;
|
hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r;
|
||||||
hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r;
|
hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r;
|
||||||
|
|
||||||
ivec4 hit_data[2];
|
ivec4 hit_data[2];
|
||||||
hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg;
|
hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg;
|
||||||
hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg;
|
hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg;
|
||||||
hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg;
|
hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg;
|
||||||
hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg;
|
hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg;
|
||||||
|
|
||||||
/* Find Planar Reflections affecting this pixel */
|
/* Find Planar Reflections affecting this pixel */
|
||||||
PlanarData pd;
|
PlanarData pd;
|
||||||
@@ -542,7 +525,7 @@ void main()
|
|||||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
||||||
pd = planars_data[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) {
|
if (fade > 0.5) {
|
||||||
planar_index = float(i);
|
planar_index = float(i);
|
||||||
@@ -554,7 +537,7 @@ void main()
|
|||||||
hit_data,
|
hit_data,
|
||||||
pd,
|
pd,
|
||||||
planar_index,
|
planar_index,
|
||||||
worldPosition,
|
P,
|
||||||
N,
|
N,
|
||||||
V,
|
V,
|
||||||
roughnessSquared,
|
roughnessSquared,
|
||||||
@@ -564,19 +547,51 @@ void main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compute SSR contribution */
|
/* Compute SSR contribution */
|
||||||
if (weight_acc > 0.0) {
|
ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc);
|
||||||
ssr_accum /= weight_acc;
|
/* fade between 0.5 and 1.0 roughness */
|
||||||
/* fade between 0.5 and 1.0 roughness */
|
ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
||||||
ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
|
||||||
accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
|
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 */
|
vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba;
|
||||||
if (spec_accum.a < 1.0) {
|
vec3 brdf = speccol_roughness.rgb;
|
||||||
fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
|
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
|
#endif
|
||||||
|
@@ -137,9 +137,9 @@ float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N, float roughness)
|
|||||||
return fac;
|
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);
|
vec3 pos_to_edge = max(vec3(0.0), abs(localpos) - 1.0);
|
||||||
float fade = length(pos_to_edge);
|
float fade = length(pos_to_edge);
|
||||||
return saturate(-fade * gd.g_atten_scale + gd.g_atten_bias);
|
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;
|
return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 probe_evaluate_planar(
|
vec3 probe_evaluate_planar(int id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness)
|
||||||
float id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness, inout float fade)
|
|
||||||
{
|
{
|
||||||
/* Find view vector / reflection plane intersection. */
|
/* Find view vector / reflection plane intersection. */
|
||||||
vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq);
|
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
|
#ifdef SSR_AO
|
||||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||||
vec3 bent_normal;
|
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);
|
final_ao = specular_occlusion(dot(N, V), final_ao, roughness);
|
||||||
#else
|
#else
|
||||||
const float final_ao = 1.0;
|
const float final_ao = 1.0;
|
||||||
|
@@ -252,32 +252,29 @@ float light_attenuation(LightData ld, vec4 l_vector)
|
|||||||
return vis;
|
return vis;
|
||||||
}
|
}
|
||||||
|
|
||||||
float light_shadowing(LightData ld,
|
float light_shadowing(LightData ld, vec3 W, float vis)
|
||||||
vec3 W,
|
|
||||||
#ifndef VOLUMETRICS
|
|
||||||
vec3 viewPosition,
|
|
||||||
float tracing_depth,
|
|
||||||
vec3 true_normal,
|
|
||||||
float rand_x,
|
|
||||||
const bool use_contact_shadows,
|
|
||||||
#endif
|
|
||||||
float vis)
|
|
||||||
{
|
{
|
||||||
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
|
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
|
||||||
/* shadowing */
|
|
||||||
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
|
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
|
||||||
|
|
||||||
if (ld.l_type == SUN) {
|
if (ld.l_type == SUN) {
|
||||||
vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
|
vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
vis *= sample_cube_shadow(int(ld.l_shadowid), W);
|
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)];
|
ShadowData sd = shadows_data[int(ld.l_shadowid)];
|
||||||
/* Only compute if not already in shadow. */
|
/* 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. */
|
/* Contact Shadows. */
|
||||||
vec3 ray_ori, ray_dir;
|
vec3 ray_ori, ray_dir;
|
||||||
float trace_distance;
|
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;
|
ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
|
||||||
}
|
}
|
||||||
else {
|
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);
|
float len = length(ray_dir);
|
||||||
trace_distance = min(sd.sh_contact_dist, len);
|
trace_distance = min(sd.sh_contact_dist, len);
|
||||||
ray_dir *= trace_distance / len;
|
ray_dir *= trace_distance / len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ray_dir = transform_direction(ViewMatrix, ray_dir);
|
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(
|
vec3 hit_pos = raycast(
|
||||||
-1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
|
-1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
|
||||||
|
|
||||||
if (hit_pos.z > 0.0) {
|
if (hit_pos.z > 0.0) {
|
||||||
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
|
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;
|
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 1.0;
|
||||||
|
|
||||||
return vis;
|
|
||||||
}
|
}
|
||||||
|
#endif /* VOLUMETRICS */
|
||||||
|
|
||||||
float light_visibility(LightData ld,
|
float light_visibility(LightData ld, vec3 W, vec4 l_vector)
|
||||||
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 l_atten = light_attenuation(ld, l_vector);
|
float l_atten = light_attenuation(ld, l_vector);
|
||||||
return light_shadowing(ld,
|
return light_shadowing(ld, W, l_atten);
|
||||||
W,
|
|
||||||
#ifndef VOLUMETRICS
|
|
||||||
viewPosition,
|
|
||||||
tracing_depth,
|
|
||||||
true_normal,
|
|
||||||
rand_x,
|
|
||||||
use_contact_shadows,
|
|
||||||
#endif
|
|
||||||
l_atten);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
|
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_view_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(closure_lit_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(surface_lib.glsl)
|
||||||
|
|
||||||
#ifdef USE_ALPHA_HASH
|
#ifdef USE_ALPHA_HASH
|
||||||
|
@@ -39,7 +39,7 @@ void main()
|
|||||||
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
|
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
|
||||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
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++) {
|
for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
|
||||||
LightData ld = lights_data[i];
|
LightData ld = lights_data[i];
|
||||||
@@ -48,8 +48,10 @@ void main()
|
|||||||
l_vector.xyz = ld.l_position - worldPosition;
|
l_vector.xyz = ld.l_position - worldPosition;
|
||||||
l_vector.w = length(l_vector.xyz);
|
l_vector.w = length(l_vector.xyz);
|
||||||
|
|
||||||
float l_vis = light_shadowing(
|
float l_vis = light_shadowing(ld, worldPosition, 1.0);
|
||||||
ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, true, 1.0);
|
|
||||||
|
l_vis *= light_contact_shadows(
|
||||||
|
ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, 1.0);
|
||||||
|
|
||||||
accum_light += l_vis;
|
accum_light += l_vis;
|
||||||
}
|
}
|
||||||
|
@@ -3,8 +3,13 @@
|
|||||||
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||||
|
|
||||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(closure_lit_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(surface_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
||||||
|
|
||||||
|
@@ -13,7 +13,15 @@ uniform float refractionDepth;
|
|||||||
vec3 worldNormal; \
|
vec3 worldNormal; \
|
||||||
vec3 viewNormal;
|
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[];
|
in ShaderStageInterface{SURFACE_INTERFACE} dataIn[];
|
||||||
|
|
||||||
out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
|
out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
|
||||||
@@ -24,7 +32,7 @@ out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
|
|||||||
dataOut.worldNormal = dataIn[vert].worldNormal; \
|
dataOut.worldNormal = dataIn[vert].worldNormal; \
|
||||||
dataOut.viewNormal = dataIn[vert].viewNormal;
|
dataOut.viewNormal = dataIn[vert].viewNormal;
|
||||||
|
|
||||||
#else
|
#else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/
|
||||||
|
|
||||||
IN_OUT ShaderStageInterface{SURFACE_INTERFACE};
|
IN_OUT ShaderStageInterface{SURFACE_INTERFACE};
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||||
|
|
||||||
/* Based on Frosbite Unified Volumetric.
|
/* Based on Frosbite Unified Volumetric.
|
||||||
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
|
* 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(vec2 v) { return dot(vec2(1.0 / 2.0), v); }
|
||||||
float avg(vec3 v) { return dot(vec3(1.0 / 3.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 avg(vec4 v) { return dot(vec4(1.0 / 4.0), v); }
|
||||||
|
|
||||||
|
float sqr(float v) { return v * v; }
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
#define saturate(a) clamp(a, 0.0, 1.0)
|
#define saturate(a) clamp(a, 0.0, 1.0)
|
||||||
@@ -93,6 +96,15 @@ float len_squared(vec3 a)
|
|||||||
return dot(a, 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);
|
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)
|
static void node_geometry_set_butfunc(bNodeType *ntype)
|
||||||
{
|
{
|
||||||
switch (ntype->type) {
|
switch (ntype->type) {
|
||||||
@@ -3441,9 +3434,6 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
|
|||||||
case GEO_NODE_POINTS_TO_VOLUME:
|
case GEO_NODE_POINTS_TO_VOLUME:
|
||||||
ntype->draw_buttons = node_geometry_buts_points_to_volume;
|
ntype->draw_buttons = node_geometry_buts_points_to_volume;
|
||||||
break;
|
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.
|
* This way the links can be added to the node tree while being stored in this list.
|
||||||
*/
|
*/
|
||||||
ListBase links;
|
ListBase links;
|
||||||
bool from_multi_input_socket;
|
|
||||||
int in_out;
|
int in_out;
|
||||||
} bNodeLinkDrag;
|
} 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");
|
nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
|
||||||
|
|
||||||
const int num_links = nodeCountSocketLinks(snode->edittree, sock);
|
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 */
|
/* dragged links are fixed on output side */
|
||||||
nldrag->in_out = SOCK_OUT;
|
nldrag->in_out = SOCK_OUT;
|
||||||
/* detach current links and store them in the operator data */
|
/* detach current links and store them in the operator data */
|
||||||
bNodeLink *link_to_pick;
|
|
||||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
|
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
|
||||||
if (link->tosock == sock) {
|
if (link->tosock == sock) {
|
||||||
if (sock->flag & SOCK_MULTI_INPUT) {
|
LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
|
||||||
nldrag->from_multi_input_socket = true;
|
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) {
|
BLI_addtail(&nldrag->links, linkdata);
|
||||||
LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
|
nodeRemLink(snode->edittree, link);
|
||||||
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);
|
/* send changed event to original link->tonode */
|
||||||
nodeRemLink(snode->edittree, link_to_pick);
|
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];
|
float cursor[2];
|
||||||
UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
|
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);
|
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
|
||||||
|
|
||||||
@@ -950,28 +941,7 @@ void NODE_OT_link(wmOperatorType *ot)
|
|||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
|
||||||
|
|
||||||
PropertyRNA *prop;
|
|
||||||
|
|
||||||
RNA_def_boolean(ot->srna, "detach", false, "Detach", "Detach and redirect existing links");
|
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 ***************** */
|
/* ********************** Make Link operator ***************** */
|
||||||
|
@@ -755,6 +755,10 @@ static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
|
|||||||
|
|
||||||
/* get parameters */
|
/* get parameters */
|
||||||
while (*code && *code != ')') {
|
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 */
|
/* test if it's an input or output */
|
||||||
qual = FUNCTION_QUAL_IN;
|
qual = FUNCTION_QUAL_IN;
|
||||||
if (BLI_str_startswith(code, "out ")) {
|
if (BLI_str_startswith(code, "out ")) {
|
||||||
|
@@ -4,7 +4,7 @@ void node_ambient_occlusion(
|
|||||||
{
|
{
|
||||||
vec3 bent_normal;
|
vec3 bent_normal;
|
||||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
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;
|
result_color = result_ao * color;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@@ -1,12 +1,27 @@
|
|||||||
#ifndef VOLUMETRICS
|
#ifndef VOLUMETRICS
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse)
|
||||||
|
|
||||||
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
|
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;
|
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);
|
out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance);
|
||||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
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
|
#else
|
||||||
/* Stub diffuse because it is not compatible with volumetrics. */
|
/* Stub diffuse because it is not compatible with volumetrics. */
|
||||||
# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT)
|
# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT)
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
#ifndef VOLUMETRICS
|
#ifndef VOLUMETRICS
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy)
|
||||||
|
|
||||||
void node_eevee_specular(vec4 diffuse,
|
void node_eevee_specular(vec4 diffuse,
|
||||||
vec4 specular,
|
vec4 specular,
|
||||||
float roughness,
|
float roughness,
|
||||||
@@ -12,34 +15,63 @@ void node_eevee_specular(vec4 diffuse,
|
|||||||
float ssr_id,
|
float ssr_id,
|
||||||
out Closure result)
|
out Closure result)
|
||||||
{
|
{
|
||||||
normal = normalize(normal);
|
CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
|
||||||
|
|
||||||
vec3 out_diff, out_spec, ssr_spec;
|
in_common.occlusion = occlusion;
|
||||||
eevee_closure_default_clearcoat(normal,
|
|
||||||
diffuse.rgb,
|
in_Diffuse_0.N = normal; /* Normalized during eval. */
|
||||||
specular.rgb,
|
in_Diffuse_0.albedo = diffuse.rgb;
|
||||||
vec3(1.0),
|
|
||||||
int(ssr_id),
|
in_Glossy_1.N = normal; /* Normalized during eval. */
|
||||||
roughness,
|
in_Glossy_1.roughness = roughness;
|
||||||
clearcoat_normal,
|
|
||||||
clearcoat * 0.25,
|
in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */
|
||||||
clearcoat_roughness,
|
in_Glossy_2.roughness = clearcoat_roughness;
|
||||||
occlusion,
|
|
||||||
true,
|
CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy);
|
||||||
out_diff,
|
|
||||||
out_spec,
|
|
||||||
ssr_spec);
|
|
||||||
|
|
||||||
float alpha = 1.0 - transp;
|
|
||||||
result = CLOSURE_DEFAULT;
|
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
|
#else
|
||||||
/* Stub specular because it is not compatible with volumetrics. */
|
/* 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)
|
# 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
|
#ifndef VOLUMETRICS
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction)
|
||||||
|
|
||||||
void node_bsdf_glass(vec4 color,
|
void node_bsdf_glass(vec4 color,
|
||||||
float roughness,
|
float roughness,
|
||||||
float ior,
|
float ior,
|
||||||
@@ -7,32 +10,38 @@ void node_bsdf_glass(vec4 color,
|
|||||||
float ssr_id,
|
float ssr_id,
|
||||||
out Closure result)
|
out Closure result)
|
||||||
{
|
{
|
||||||
N = normalize(N);
|
CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
|
||||||
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;
|
|
||||||
|
|
||||||
|
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(
|
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
|
#else
|
||||||
/* Stub glass because it is not compatible with volumetrics. */
|
/* Stub glass because it is not compatible with volumetrics. */
|
||||||
# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT)
|
# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT)
|
||||||
|
@@ -1,23 +1,32 @@
|
|||||||
#ifndef VOLUMETRICS
|
#ifndef VOLUMETRICS
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy)
|
||||||
|
|
||||||
void node_bsdf_glossy(
|
void node_bsdf_glossy(
|
||||||
vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result)
|
vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result)
|
||||||
{
|
{
|
||||||
N = normalize(N);
|
bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId);
|
||||||
vec3 out_spec, ssr_spec;
|
|
||||||
eevee_closure_glossy(N,
|
CLOSURE_VARS_DECLARE_1(Glossy);
|
||||||
vec3(1.0),
|
|
||||||
use_multiscatter != 0.0 ? vec3(1.0) : vec3(-1.0), /* HACK */
|
in_Glossy_0.N = N; /* Normalized during eval. */
|
||||||
int(ssr_id),
|
in_Glossy_0.roughness = roughness;
|
||||||
roughness,
|
|
||||||
1.0,
|
CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy);
|
||||||
true,
|
|
||||||
out_spec,
|
|
||||||
ssr_spec);
|
|
||||||
vec3 vN = mat3(ViewMatrix) * N;
|
|
||||||
result = CLOSURE_DEFAULT;
|
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
|
#else
|
||||||
/* Stub glossy because it is not compatible with volumetrics. */
|
/* Stub glossy because it is not compatible with volumetrics. */
|
||||||
# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
|
# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
|
||||||
|
@@ -1,41 +1,20 @@
|
|||||||
#ifndef VOLUMETRICS
|
#ifndef VOLUMETRICS
|
||||||
vec3 tint_from_color(vec3 color)
|
vec3 tint_from_color(vec3 color)
|
||||||
{
|
{
|
||||||
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
|
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 */
|
return (lum > 0.0) ? color / lum : vec3(0.0); /* normalize lum. to isolate hue+sat */
|
||||||
}
|
}
|
||||||
|
|
||||||
void convert_metallic_to_specular_tinted(vec3 basecol,
|
float principled_sheen(float NV)
|
||||||
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 f = 1.0 - 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. */
|
/* Empirical approximation (manual curve fitting). Can be refined. */
|
||||||
out_sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
|
float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
|
||||||
|
return sheen;
|
||||||
sheen_color = sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction)
|
||||||
|
|
||||||
void node_bsdf_principled(vec4 base_color,
|
void node_bsdf_principled(vec4 base_color,
|
||||||
float subsurface,
|
float subsurface,
|
||||||
vec3 subsurface_radius,
|
vec3 subsurface_radius,
|
||||||
@@ -59,434 +38,163 @@ void node_bsdf_principled(vec4 base_color,
|
|||||||
vec3 N,
|
vec3 N,
|
||||||
vec3 CN,
|
vec3 CN,
|
||||||
vec3 T,
|
vec3 T,
|
||||||
vec3 I,
|
const float do_diffuse,
|
||||||
float use_multiscatter,
|
const float do_clearcoat,
|
||||||
|
const float do_refraction,
|
||||||
|
const float do_multiscatter,
|
||||||
float ssr_id,
|
float ssr_id,
|
||||||
float sss_id,
|
float sss_id,
|
||||||
vec3 sss_scale,
|
vec3 sss_scale,
|
||||||
out Closure result)
|
out Closure result)
|
||||||
{
|
{
|
||||||
N = normalize(N);
|
/* Match cycles. */
|
||||||
ior = max(ior, 1e-5);
|
|
||||||
metallic = saturate(metallic);
|
metallic = saturate(metallic);
|
||||||
transmission = saturate(transmission);
|
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;
|
CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
|
||||||
transmission *= dielectric;
|
|
||||||
sheen *= dielectric;
|
|
||||||
subsurface_color *= dielectric;
|
|
||||||
|
|
||||||
vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec, sheen_color;
|
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||||
float out_sheen;
|
in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface);
|
||||||
vec3 ctint = tint_from_color(base_color.rgb);
|
|
||||||
convert_metallic_to_specular_tinted(
|
|
||||||
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
|
|
||||||
|
|
||||||
float NV = dot(N, cameraVec);
|
in_Glossy_1.N = N; /* Normalized during eval. */
|
||||||
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
|
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.
|
in_Refraction_3.N = N; /* Normalized during eval. */
|
||||||
* Most noticeable difference is at grazing angles since the bsdf lut
|
in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness;
|
||||||
* f0 color interpolation is done on top of this interpolation. */
|
in_Refraction_3.ior = ior;
|
||||||
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);
|
|
||||||
|
|
||||||
/* Really poor approximation but needed to workaround issues with renderpasses. */
|
CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);
|
||||||
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;
|
|
||||||
|
|
||||||
result = CLOSURE_DEFAULT;
|
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;
|
/* This will tag the whole eval for optimisation. */
|
||||||
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
|
if (do_diffuse == 0.0) {
|
||||||
result.transmittance = vec3(1.0 - alpha);
|
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,
|
/* Glossy_1 will always be evaluated. */
|
||||||
float subsurface,
|
float NV = dot(in_Glossy_1.N, cameraVec);
|
||||||
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;
|
|
||||||
|
|
||||||
vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color;
|
vec3 base_color_tint = tint_from_color(base_color.rgb);
|
||||||
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 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,
|
vec2 split_sum = brdf_lut(NV, roughness);
|
||||||
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);
|
|
||||||
|
|
||||||
result = CLOSURE_DEFAULT;
|
vec3 glossy_radiance_final = vec3(0.0);
|
||||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
|
if (transmission > 1e-5) {
|
||||||
result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
|
/* Glass Reflection: Reuse radiance from Glossy1. */
|
||||||
result.radiance += render_pass_diffuse_mask(diffuse, out_diff * diffuse);
|
vec3 out_glass_refl_radiance = out_Glossy_1.radiance;
|
||||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
|
||||||
result.radiance *= alpha;
|
/* Poor approximation since we baked the LUT using a fixed IOR. */
|
||||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
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);
|
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;
|
result.radiance *= alpha;
|
||||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
result.ssr_data.rgb *= alpha;
|
||||||
|
# ifdef USE_SSS
|
||||||
result.transmittance = vec3(1.0 - alpha);
|
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
|
#else
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
/* Stub principled because it is not compatible with volumetrics. */
|
/* 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(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)
|
||||||
# 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)
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,15 +1,30 @@
|
|||||||
#ifndef VOLUMETRICS
|
#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)
|
void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
|
||||||
{
|
{
|
||||||
N = normalize(N);
|
CLOSURE_VARS_DECLARE_1(Refraction);
|
||||||
vec3 out_refr;
|
|
||||||
color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
|
in_Refraction_0.N = N; /* Normalized during eval. */
|
||||||
eevee_closure_refraction(N, roughness, ior, true, out_refr);
|
in_Refraction_0.roughness = roughness;
|
||||||
vec3 vN = mat3(ViewMatrix) * N;
|
in_Refraction_0.ior = ior;
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction);
|
||||||
|
|
||||||
result = CLOSURE_DEFAULT;
|
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
|
#else
|
||||||
/* Stub refraction because it is not compatible with volumetrics. */
|
/* Stub refraction because it is not compatible with volumetrics. */
|
||||||
# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT)
|
# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT)
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
#ifndef VOLUMETRICS
|
#ifndef VOLUMETRICS
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse)
|
||||||
|
|
||||||
void node_subsurface_scattering(vec4 color,
|
void node_subsurface_scattering(vec4 color,
|
||||||
float scale,
|
float scale,
|
||||||
vec3 radius,
|
vec3 radius,
|
||||||
@@ -8,20 +11,29 @@ void node_subsurface_scattering(vec4 color,
|
|||||||
float sss_id,
|
float sss_id,
|
||||||
out Closure result)
|
out Closure result)
|
||||||
{
|
{
|
||||||
N = normalize(N);
|
CLOSURE_VARS_DECLARE_1(Diffuse);
|
||||||
vec3 out_diff;
|
|
||||||
vec3 vN = mat3(ViewMatrix) * N;
|
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;
|
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. */
|
closure_load_sss_data(scale, out_Diffuse_0.radiance, sss_albedo, int(sss_id), result);
|
||||||
vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
|
|
||||||
out_diff *= mix(vec3(1.0), color.rgb, texture_blur);
|
/* TODO(fclem) Try to not use this. */
|
||||||
result.radiance = render_pass_sss_mask(sss_albedo);
|
closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
|
||||||
closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Stub subsurface scattering because it is not compatible with volumetrics. */
|
/* 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)
|
# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT)
|
||||||
|
@@ -1,12 +1,20 @@
|
|||||||
#ifndef VOLUMETRICS
|
#ifndef VOLUMETRICS
|
||||||
|
|
||||||
|
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent)
|
||||||
|
|
||||||
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
|
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;
|
result = CLOSURE_DEFAULT;
|
||||||
eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance);
|
closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1.0, result);
|
||||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb);
|
||||||
result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Stub translucent because it is not compatible with volumetrics. */
|
/* Stub translucent because it is not compatible with volumetrics. */
|
||||||
# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT)
|
# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT)
|
||||||
|
@@ -200,8 +200,6 @@ typedef enum eNodeSocketFlag {
|
|||||||
SOCK_NO_INTERNAL_LINK = (1 << 9),
|
SOCK_NO_INTERNAL_LINK = (1 << 9),
|
||||||
/** Draw socket in a more compact form. */
|
/** Draw socket in a more compact form. */
|
||||||
SOCK_COMPACT = (1 << 10),
|
SOCK_COMPACT = (1 << 10),
|
||||||
/** Make the input socket accept multiple incoming links in the UI. */
|
|
||||||
SOCK_MULTI_INPUT = (1 << 11),
|
|
||||||
} eNodeSocketFlag;
|
} eNodeSocketFlag;
|
||||||
|
|
||||||
/* limit data in bNode to what we want to see saved? */
|
/* limit data in bNode to what we want to see saved? */
|
||||||
@@ -1195,13 +1193,6 @@ typedef struct NodeGeometryPointsToVolume {
|
|||||||
char _pad[6];
|
char _pad[6];
|
||||||
} NodeGeometryPointsToVolume;
|
} NodeGeometryPointsToVolume;
|
||||||
|
|
||||||
typedef struct NodeGeometryCollectionInfo {
|
|
||||||
/* GeometryNodeTransformSpace. */
|
|
||||||
uint8_t transform_space;
|
|
||||||
|
|
||||||
char _pad[7];
|
|
||||||
} NodeGeometryCollectionInfo;
|
|
||||||
|
|
||||||
/* script node mode */
|
/* script node mode */
|
||||||
#define NODE_SCRIPT_INTERNAL 0
|
#define NODE_SCRIPT_INTERNAL 0
|
||||||
#define NODE_SCRIPT_EXTERNAL 1
|
#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");
|
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)
|
static void rna_def_shader_node(BlenderRNA *brna)
|
||||||
|
@@ -215,7 +215,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
|
|||||||
class GeometryNodesEvaluator {
|
class GeometryNodesEvaluator {
|
||||||
private:
|
private:
|
||||||
blender::LinearAllocator<> allocator_;
|
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_;
|
Vector<const DInputSocket *> group_outputs_;
|
||||||
blender::nodes::MultiFunctionByNode &mf_by_node_;
|
blender::nodes::MultiFunctionByNode &mf_by_node_;
|
||||||
const blender::nodes::DataTypeConversions &conversions_;
|
const blender::nodes::DataTypeConversions &conversions_;
|
||||||
@@ -246,8 +246,8 @@ class GeometryNodesEvaluator {
|
|||||||
{
|
{
|
||||||
Vector<GMutablePointer> results;
|
Vector<GMutablePointer> results;
|
||||||
for (const DInputSocket *group_output : group_outputs_) {
|
for (const DInputSocket *group_output : group_outputs_) {
|
||||||
Vector<GMutablePointer> result = this->get_input_values(*group_output);
|
GMutablePointer result = this->get_input_value(*group_output);
|
||||||
results.append(result[0]);
|
results.append(result);
|
||||||
}
|
}
|
||||||
for (GMutablePointer value : value_by_input_.values()) {
|
for (GMutablePointer value : value_by_input_.values()) {
|
||||||
value.destruct();
|
value.destruct();
|
||||||
@@ -256,53 +256,32 @@ class GeometryNodesEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
|
||||||
Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
|
Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
|
||||||
const int total_inputs = from_sockets.size() + from_group_inputs.size();
|
const int total_inputs = from_sockets.size() + from_group_inputs.size();
|
||||||
|
BLI_assert(total_inputs <= 1);
|
||||||
|
|
||||||
if (total_inputs == 0) {
|
if (total_inputs == 0) {
|
||||||
/* The input is not connected, use the value from the socket itself. */
|
/* 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) {
|
if (from_group_inputs.size() == 1) {
|
||||||
return {get_unlinked_input_value(socket_to_compute)};
|
/* The input gets its value from the input of a group that is not further connected. */
|
||||||
}
|
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};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the socket now. */
|
/* Compute the socket now. */
|
||||||
|
const DOutputSocket &from_socket = *from_sockets[0];
|
||||||
this->compute_output_and_forward(from_socket);
|
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)
|
void compute_output_and_forward(const DOutputSocket &socket_to_compute)
|
||||||
@@ -323,14 +302,8 @@ class GeometryNodesEvaluator {
|
|||||||
GValueMap<StringRef> node_inputs_map{allocator_};
|
GValueMap<StringRef> node_inputs_map{allocator_};
|
||||||
for (const DInputSocket *input_socket : node.inputs()) {
|
for (const DInputSocket *input_socket : node.inputs()) {
|
||||||
if (input_socket->is_available()) {
|
if (input_socket->is_available()) {
|
||||||
Vector<GMutablePointer> values = this->get_input_values(*input_socket);
|
GMutablePointer value = this->get_input_value(*input_socket);
|
||||||
for (int i = 0; i < values.size(); ++i) {
|
node_inputs_map.add_new_direct(input_socket->identifier(), value);
|
||||||
/* 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]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,15 +393,13 @@ class GeometryNodesEvaluator {
|
|||||||
|
|
||||||
void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
|
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();
|
Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets();
|
||||||
|
|
||||||
const CPPType &from_type = *value_to_forward.type();
|
const CPPType &from_type = *value_to_forward.type();
|
||||||
|
|
||||||
Vector<const DInputSocket *> to_sockets_same_type;
|
Vector<const DInputSocket *> to_sockets_same_type;
|
||||||
for (const DInputSocket *to_socket : to_sockets_all) {
|
for (const DInputSocket *to_socket : to_sockets_all) {
|
||||||
const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo());
|
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) {
|
if (from_type == to_type) {
|
||||||
to_sockets_same_type.append(to_socket);
|
to_sockets_same_type.append(to_socket);
|
||||||
}
|
}
|
||||||
@@ -440,7 +411,7 @@ class GeometryNodesEvaluator {
|
|||||||
else {
|
else {
|
||||||
to_type.copy_to_uninitialized(to_type.default_value(), buffer);
|
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) {
|
else if (to_sockets_same_type.size() == 1) {
|
||||||
/* This value is only used on one input socket, no need to copy it. */
|
/* This value is only used on one input socket, no need to copy it. */
|
||||||
const DInputSocket *to_socket = to_sockets_same_type[0];
|
const DInputSocket *to_socket = to_sockets_same_type[0];
|
||||||
const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
|
value_by_input_.add_new(to_socket, value_to_forward);
|
||||||
to_socket, &from_socket);
|
|
||||||
|
|
||||||
add_value_to_input_socket(key, value_to_forward);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Multiple inputs use the value, make a copy for every input except for one. */
|
/* Multiple inputs use the value, make a copy for every input except for one. */
|
||||||
const DInputSocket *first_to_socket = to_sockets_same_type[0];
|
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);
|
Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
|
||||||
const CPPType &type = *value_to_forward.type();
|
const CPPType &type = *value_to_forward.type();
|
||||||
const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair(
|
|
||||||
first_to_socket, &from_socket);
|
value_by_input_.add_new(first_to_socket, value_to_forward);
|
||||||
add_value_to_input_socket(first_key, value_to_forward);
|
|
||||||
for (const DInputSocket *to_socket : other_to_sockets) {
|
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());
|
void *buffer = allocator_.allocate(type.size(), type.alignment());
|
||||||
type.copy_to_uninitialized(value_to_forward.get(), buffer);
|
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)
|
GMutablePointer get_unlinked_input_value(const DInputSocket &socket)
|
||||||
{
|
{
|
||||||
bNodeSocket *bsocket;
|
bNodeSocket *bsocket;
|
||||||
|
@@ -150,7 +150,6 @@ set(SRC
|
|||||||
geometry/nodes/node_geo_attribute_randomize.cc
|
geometry/nodes/node_geo_attribute_randomize.cc
|
||||||
geometry/nodes/node_geo_attribute_vector_math.cc
|
geometry/nodes/node_geo_attribute_vector_math.cc
|
||||||
geometry/nodes/node_geo_boolean.cc
|
geometry/nodes/node_geo_boolean.cc
|
||||||
geometry/nodes/node_geo_collection_info.cc
|
|
||||||
geometry/nodes/node_geo_common.cc
|
geometry/nodes/node_geo_common.cc
|
||||||
geometry/nodes/node_geo_edge_split.cc
|
geometry/nodes/node_geo_edge_split.cc
|
||||||
geometry/nodes/node_geo_join_geometry.cc
|
geometry/nodes/node_geo_join_geometry.cc
|
||||||
|
@@ -80,7 +80,6 @@ class DInputSocket : public DSocket {
|
|||||||
private:
|
private:
|
||||||
Vector<DOutputSocket *> linked_sockets_;
|
Vector<DOutputSocket *> linked_sockets_;
|
||||||
Vector<DGroupInput *> linked_group_inputs_;
|
Vector<DGroupInput *> linked_group_inputs_;
|
||||||
bool is_multi_input_socket_;
|
|
||||||
|
|
||||||
friend DerivedNodeTree;
|
friend DerivedNodeTree;
|
||||||
|
|
||||||
@@ -91,7 +90,6 @@ class DInputSocket : public DSocket {
|
|||||||
Span<const DGroupInput *> linked_group_inputs() const;
|
Span<const DGroupInput *> linked_group_inputs() const;
|
||||||
|
|
||||||
bool is_linked() const;
|
bool is_linked() const;
|
||||||
bool is_multi_input_socket() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DOutputSocket : public DSocket {
|
class DOutputSocket : public DSocket {
|
||||||
@@ -364,11 +362,6 @@ inline bool DInputSocket::is_linked() const
|
|||||||
return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0;
|
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.
|
* 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_align_rotation_to_vector(void);
|
||||||
void register_node_type_geo_sample_texture(void);
|
void register_node_type_geo_sample_texture(void);
|
||||||
void register_node_type_geo_points_to_volume(void);
|
void register_node_type_geo_points_to_volume(void);
|
||||||
void register_node_type_geo_collection_info(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -103,25 +103,6 @@ class GeoNodeExecParams {
|
|||||||
return input_values_.extract<T>(identifier);
|
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.
|
* 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_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_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_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 */
|
/* undefine macros */
|
||||||
#undef DefNode
|
#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);
|
quat_to_eul(rotation, quaternion);
|
||||||
|
|
||||||
if (object != self_object) {
|
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) {
|
/* Make a copy because the life time of the other mesh might be shorter. */
|
||||||
instances.add_instance(object, transform);
|
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 {
|
if (object->type == OB_VOLUME) {
|
||||||
float unit_transform[4][4];
|
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
|
||||||
unit_m4(unit_transform);
|
|
||||||
instances.add_instance(object, unit_transform);
|
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,
|
static void sample_mesh_surface(const Mesh &mesh,
|
||||||
const float4x4 &transform,
|
|
||||||
const float base_density,
|
const float base_density,
|
||||||
const FloatReadAttribute *density_factors,
|
const FloatReadAttribute *density_factors,
|
||||||
const int seed,
|
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 v0_index = mesh.mloop[looptri.tri[0]].v;
|
||||||
const int v1_index = mesh.mloop[looptri.tri[1]].v;
|
const int v1_index = mesh.mloop[looptri.tri[1]].v;
|
||||||
const int v2_index = mesh.mloop[looptri.tri[2]].v;
|
const int v2_index = mesh.mloop[looptri.tri[2]].v;
|
||||||
|
const float3 v0_pos = mesh.mvert[v0_index].co;
|
||||||
const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co);
|
const float3 v1_pos = mesh.mvert[v1_index].co;
|
||||||
const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co);
|
const float3 v2_pos = mesh.mvert[v2_index].co;
|
||||||
const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co);
|
|
||||||
|
|
||||||
float looptri_density_factor = 1.0f;
|
float looptri_density_factor = 1.0f;
|
||||||
if (density_factors != nullptr) {
|
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 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 v2_density_factor = std::max(0.0f, density_factors[v2_index]);
|
||||||
|
|
||||||
const float probablity = attribute_math::mix3<float>(
|
const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
|
||||||
bary_coord, v0_density_factor, v1_density_factor, v2_density_factor);
|
v2_density_factor * bary_coord.z;
|
||||||
|
|
||||||
const float hash = BLI_hash_int_01(bary_coord.hash());
|
const float hash = BLI_hash_int_01(bary_coord.hash());
|
||||||
if (hash > probablity) {
|
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);
|
*mesh_component.get_for_read(), component, bary_coords, looptri_indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AttributeInfo {
|
static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh,
|
||||||
std::string name;
|
const float max_density,
|
||||||
Vector<CustomDataType> data_types;
|
const float minimum_distance,
|
||||||
Vector<AttributeDomain> domains;
|
const FloatReadAttribute &density_factors,
|
||||||
};
|
const int seed,
|
||||||
|
Vector<float3> &r_positions,
|
||||||
struct ScatterPointsOnMeshOp {
|
Vector<float3> &r_bary_coords,
|
||||||
/* Input data. */
|
Vector<int> &r_looptri_indices)
|
||||||
const GeometryNodePointDistributeMethod distribute_method;
|
{
|
||||||
const std::string &density_attribute_name;
|
sample_mesh_surface(
|
||||||
const int seed;
|
mesh, max_density, nullptr, seed, r_positions, r_bary_coords, r_looptri_indices);
|
||||||
const float density;
|
Array<bool> elimination_mask(r_positions.size(), false);
|
||||||
|
update_elimination_mask_for_close_points(r_positions, minimum_distance, elimination_mask);
|
||||||
/* Output data. */
|
update_elimination_mask_based_on_density_factors(
|
||||||
Vector<float3> &positions;
|
mesh, density_factors, r_bary_coords, r_looptri_indices, elimination_mask);
|
||||||
Vector<float3> &bary_coords;
|
eliminate_points_based_on_mask(elimination_mask, r_positions, r_bary_coords, r_looptri_indices);
|
||||||
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 geo_node_point_distribute_exec(GeoNodeExecParams params)
|
static void geo_node_point_distribute_exec(GeoNodeExecParams params)
|
||||||
{
|
{
|
||||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||||
GeometrySet geometry_set_out;
|
GeometrySet geometry_set_out;
|
||||||
|
|
||||||
const GeometryNodePointDistributeMethod distribute_method =
|
GeometryNodePointDistributeMethod distribute_method =
|
||||||
static_cast<GeometryNodePointDistributeMethod>(params.node().custom1);
|
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));
|
params.set_output("Geometry", std::move(geometry_set_out));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float density = params.extract_input<float>("Density Max");
|
const float density = params.extract_input<float>("Density Max");
|
||||||
const std::string density_attribute_name = params.extract_input<std::string>(
|
const std::string density_attribute = params.extract_input<std::string>("Density Attribute");
|
||||||
"Density Attribute");
|
|
||||||
|
|
||||||
if (density <= 0.0f) {
|
if (density <= 0.0f) {
|
||||||
params.set_output("Geometry", std::move(geometry_set_out));
|
params.set_output("Geometry", std::move(geometry_set_out));
|
||||||
return;
|
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");
|
const int seed = params.get_input<int>("Seed");
|
||||||
|
|
||||||
Vector<float3> positions;
|
Vector<float3> positions;
|
||||||
Vector<float3> bary_coords;
|
Vector<float3> bary_coords;
|
||||||
Vector<int> looptri_indices;
|
Vector<int> looptri_indices;
|
||||||
Set<AttributeInfo> attributes;
|
switch (distribute_method) {
|
||||||
|
case GEO_NODE_POINT_DISTRIBUTE_RANDOM:
|
||||||
ScatterPointsOnMeshOp scatter_points_op{distribute_method,
|
sample_mesh_surface(
|
||||||
density_attribute_name,
|
*mesh_in, density, &density_factors, seed, positions, bary_coords, looptri_indices);
|
||||||
seed,
|
break;
|
||||||
density,
|
case GEO_NODE_POINT_DISTRIBUTE_POISSON:
|
||||||
positions,
|
const float minimum_distance = params.extract_input<float>("Distance Min");
|
||||||
bary_coords,
|
sample_mesh_surface_with_minimum_distance(*mesh_in,
|
||||||
looptri_indices,
|
density,
|
||||||
attributes};
|
minimum_distance,
|
||||||
BKE_foreach_geometry_component_recursive(geometry_set, scatter_points_op);
|
density_factors,
|
||||||
|
seed,
|
||||||
/* Eliminate points based on the minimum distance for the poisson disk case. */
|
positions,
|
||||||
if (distribute_method == GEO_NODE_POINT_DISTRIBUTE_POISSON) {
|
bary_coords,
|
||||||
Array<bool> elimination_mask(positions.size(), false);
|
looptri_indices);
|
||||||
const float minimum_distance = params.get_input<float>("Distance Min");
|
break;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int tot_points = positions.size();
|
const int tot_points = positions.size();
|
||||||
|
|
||||||
PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points);
|
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>();
|
geometry_set_out.get_component_for_write<PointCloudComponent>();
|
||||||
point_component.replace(pointcloud);
|
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));
|
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()) {
|
for (int i : node.inputs_.index_range()) {
|
||||||
const InputSocketRef &socket_ref = node_ref.input(i);
|
const InputSocketRef &socket_ref = node_ref.input(i);
|
||||||
DInputSocket &socket = *node.inputs_[i];
|
DInputSocket &socket = *node.inputs_[i];
|
||||||
socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT;
|
|
||||||
socket.id_ = UNINITIALIZED_ID;
|
socket.id_ = UNINITIALIZED_ID;
|
||||||
socket.node_ = &node;
|
socket.node_ = &node;
|
||||||
socket.socket_ref_ = &socket_ref;
|
socket.socket_ref_ = &socket_ref;
|
||||||
|
@@ -281,30 +281,25 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
|
|||||||
return count;
|
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)
|
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 *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
|
||||||
bNodeSocket *sock;
|
bNodeSocket *sock;
|
||||||
|
|
||||||
/* Iterate over all sockets of the target node, to find one that matches the same socket type.
|
sock = cur->next ? cur->next : first; /* wrap around the list end */
|
||||||
* 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. */
|
|
||||||
while (sock != cur) {
|
while (sock != cur) {
|
||||||
if (!nodeSocketIsHidden(sock) && node_link_socket_match(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)) {
|
sock = sock->next ? sock->next : first; /* wrap around the list end */
|
||||||
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. */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -314,6 +309,7 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
|||||||
bNodeSocket *sock = link->tosock;
|
bNodeSocket *sock = link->tosock;
|
||||||
bNodeLink *tlink, *tlink_next;
|
bNodeLink *tlink, *tlink_next;
|
||||||
|
|
||||||
|
/* inputs can have one link only, outputs can have unlimited links */
|
||||||
if (node != link->tonode) {
|
if (node != link->tonode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -134,54 +134,32 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
|
|||||||
GPU_link(mat, "set_rgb_one", &sss_scale);
|
GPU_link(mat, "set_rgb_one", &sss_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Due to the manual effort done per config, we only optimize the most common permutations. */
|
uint flag = GPU_MATFLAG_GLOSSY;
|
||||||
char *node_name;
|
if (use_diffuse) {
|
||||||
uint flag = 0;
|
flag |= GPU_MATFLAG_DIFFUSE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) {
|
if (use_refract) {
|
||||||
static char name[] = "node_bsdf_principled_metallic";
|
flag |= GPU_MATFLAG_REFRACT;
|
||||||
node_name = name;
|
|
||||||
flag = GPU_MATFLAG_GLOSSY;
|
|
||||||
}
|
}
|
||||||
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) {
|
if (use_subsurf) {
|
||||||
flag |= GPU_MATFLAG_SSS;
|
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;
|
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
|
||||||
|
|
||||||
GPU_material_flag_set(mat, flag);
|
GPU_material_flag_set(mat, flag);
|
||||||
|
|
||||||
return GPU_stack_link(mat,
|
return GPU_stack_link(mat,
|
||||||
node,
|
node,
|
||||||
node_name,
|
"node_bsdf_principled",
|
||||||
in,
|
in,
|
||||||
out,
|
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(&use_multi_scatter),
|
||||||
GPU_constant(&node->ssr_id),
|
GPU_constant(&node->ssr_id),
|
||||||
GPU_constant(&node->sss_id),
|
GPU_constant(&node->sss_id),
|
||||||
|
Reference in New Issue
Block a user