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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Stockner <lukas.stockner@freenet.de>2018-05-27 01:46:37 +0300
committerLukas Stockner <lukas.stockner@freenet.de>2018-05-27 02:24:57 +0300
commit48155c210a3fd65f6fc2b5be3357b47a8af3711a (patch)
treea937261c81b959a79e8a2521a44b87a2d73fa749 /intern/cycles/render
parentef502854feb6b81119954206bff414d4507f4f3c (diff)
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources. The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp. Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried. Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file. The user interface of the node is similar to the script node, the user can either select an internal Text or load a file. Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot. The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light, rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport. Reviewers: #cycles, dingto, sergey, brecht Reviewed By: #cycles, dingto, brecht Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey Differential Revision: https://developer.blender.org/D1543
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/graph.cpp6
-rw-r--r--intern/cycles/render/light.cpp122
-rw-r--r--intern/cycles/render/light.h17
-rw-r--r--intern/cycles/render/nodes.cpp100
-rw-r--r--intern/cycles/render/nodes.h22
-rw-r--r--intern/cycles/render/osl.cpp9
-rw-r--r--intern/cycles/render/osl.h5
-rw-r--r--intern/cycles/render/scene.cpp3
-rw-r--r--intern/cycles/render/scene.h3
-rw-r--r--intern/cycles/render/svm.cpp7
-rw-r--r--intern/cycles/render/svm.h5
11 files changed, 288 insertions, 11 deletions
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 096de878e51..59e1a12c3a1 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -774,6 +774,12 @@ void ShaderGraph::default_inputs(bool do_osl)
connect(texco->output("Generated"), input);
}
+ if(input->flags() & SocketType::LINK_TEXTURE_NORMAL) {
+ if(!texco)
+ texco = new TextureCoordinateNode();
+
+ connect(texco->output("Normal"), input);
+ }
else if(input->flags() & SocketType::LINK_TEXTURE_UV) {
if(!texco)
texco = new TextureCoordinateNode();
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 8dec7e4ea64..f0824ef4319 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -25,6 +25,8 @@
#include "render/shader.h"
#include "util/util_foreach.h"
+#include "util/util_hash.h"
+#include "util/util_path.h"
#include "util/util_progress.h"
#include "util/util_logging.h"
@@ -175,6 +177,9 @@ LightManager::LightManager()
LightManager::~LightManager()
{
+ foreach(IESSlot *slot, ies_slots) {
+ delete slot;
+ }
}
bool LightManager::has_background_light(Scene *scene)
@@ -858,6 +863,9 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce
device_update_background(device, dscene, scene, progress);
if(progress.get_cancel()) return;
+ device_update_ies(dscene);
+ if(progress.get_cancel()) return;
+
if(use_light_visibility != scene->film->use_light_visibility) {
scene->film->use_light_visibility = use_light_visibility;
scene->film->tag_update(scene);
@@ -872,6 +880,7 @@ void LightManager::device_free(Device *, DeviceScene *dscene)
dscene->lights.free();
dscene->light_background_marginal_cdf.free();
dscene->light_background_conditional_cdf.free();
+ dscene->ies_lights.free();
}
void LightManager::tag_update(Scene * /*scene*/)
@@ -879,5 +888,118 @@ void LightManager::tag_update(Scene * /*scene*/)
need_update = true;
}
+int LightManager::add_ies_from_file(ustring filename)
+{
+ string content;
+ /* If the file can't be opened, call with an empty string */
+ path_read_text(filename.c_str(), content);
+
+ return add_ies(ustring(content));
+}
+
+int LightManager::add_ies(ustring content)
+{
+ uint hash = hash_string(content.c_str());
+
+ thread_scoped_lock ies_lock(ies_mutex);
+
+ /* Check whether this IES already has a slot. */
+ size_t slot;
+ for(slot = 0; slot < ies_slots.size(); slot++) {
+ if(ies_slots[slot]->hash == hash) {
+ ies_slots[slot]->users++;
+ return slot;
+ }
+ }
+
+ /* Try to find an empty slot for the new IES. */
+ for(slot = 0; slot < ies_slots.size(); slot++) {
+ if(ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) {
+ break;
+ }
+ }
+
+ /* If there's no free slot, add one. */
+ if(slot == ies_slots.size()) {
+ ies_slots.push_back(new IESSlot());
+ }
+
+ ies_slots[slot]->ies.load(content);
+ ies_slots[slot]->users = 1;
+ ies_slots[slot]->hash = hash;
+
+ need_update = true;
+
+ return slot;
+}
+
+void LightManager::remove_ies(int slot)
+{
+ thread_scoped_lock ies_lock(ies_mutex);
+
+ if(slot < 0 || slot >= ies_slots.size()) {
+ assert(false);
+ return;
+ }
+
+ assert(ies_slots[slot]->users > 0);
+ ies_slots[slot]->users--;
+
+ /* If the slot has no more users, update the device to remove it. */
+ need_update |= (ies_slots[slot]->users == 0);
+}
+
+void LightManager::device_update_ies(DeviceScene *dscene)
+{
+ /* Clear empty slots. */
+ foreach(IESSlot *slot, ies_slots) {
+ if(slot->users == 0) {
+ slot->hash = 0;
+ slot->ies.clear();
+ }
+ }
+
+ /* Shrink the slot table by removing empty slots at the end. */
+ int slot_end;
+ for(slot_end = ies_slots.size(); slot_end; slot_end--) {
+ if(ies_slots[slot_end-1]->users > 0) {
+ /* If the preceding slot has users, we found the new end of the table. */
+ break;
+ }
+ else {
+ /* The slot will be past the new end of the table, so free it. */
+ delete ies_slots[slot_end-1];
+ }
+ }
+ ies_slots.resize(slot_end);
+
+ if(ies_slots.size() > 0) {
+ int packed_size = 0;
+ foreach(IESSlot *slot, ies_slots) {
+ packed_size += slot->ies.packed_size();
+ }
+
+ /* ies_lights starts with an offset table that contains the offset of every slot,
+ * or -1 if the slot is invalid.
+ * Following that table, the packed valid IES lights are stored. */
+ float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size);
+
+ int offset = ies_slots.size();
+ for(int i = 0; i < ies_slots.size(); i++) {
+ int size = ies_slots[i]->ies.packed_size();
+ if(size > 0) {
+ data[i] = __int_as_float(offset);
+ ies_slots[i]->ies.pack(data + offset);
+ offset += size;
+ }
+ else {
+ data[i] = __int_as_float(-1);
+ }
+ }
+
+ dscene->ies_lights.copy_to_device();
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 97b7b971c73..5f8677ee2f2 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -21,6 +21,8 @@
#include "graph/node.h"
+#include "util/util_ies.h"
+#include "util/util_thread.h"
#include "util/util_types.h"
#include "util/util_vector.h"
@@ -86,6 +88,11 @@ public:
LightManager();
~LightManager();
+ /* IES texture management */
+ int add_ies(ustring ies);
+ int add_ies_from_file(ustring filename);
+ void remove_ies(int slot);
+
void device_update(Device *device,
DeviceScene *dscene,
Scene *scene,
@@ -115,9 +122,19 @@ protected:
DeviceScene *dscene,
Scene *scene,
Progress& progress);
+ void device_update_ies(DeviceScene *dscene);
/* Check whether light manager can use the object as a light-emissive. */
bool object_usable_as_light(Object *object);
+
+ struct IESSlot {
+ IESFile ies;
+ uint hash;
+ int users;
+ };
+
+ vector<IESSlot*> ies_slots;
+ thread_mutex ies_mutex;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index c468924fa66..3dad4d1a346 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -16,6 +16,7 @@
#include "render/image.h"
#include "render/integrator.h"
+#include "render/light.h"
#include "render/nodes.h"
#include "render/scene.h"
#include "render/svm.h"
@@ -384,10 +385,10 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
/* TODO(sergey): It's not so simple to pass custom attribute
* to the texture() function in order to make builtin images
* support more clear. So we use special file name which is
- * "@<slot_number>" and check whether file name matches this
+ * "@i<slot_number>" and check whether file name matches this
* mask in the OSLRenderServices::texture().
*/
- compiler.parameter("filename", string_printf("@%d", slot).c_str());
+ compiler.parameter("filename", string_printf("@i%d", slot).c_str());
}
if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "linear");
@@ -567,7 +568,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
compiler.parameter(this, "filename");
}
else {
- compiler.parameter("filename", string_printf("@%d", slot).c_str());
+ compiler.parameter("filename", string_printf("@i%d", slot).c_str());
}
compiler.parameter(this, "projection");
if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
@@ -954,6 +955,97 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_voronoi_texture");
}
+/* IES Light */
+
+NODE_DEFINE(IESLightNode)
+{
+ NodeType* type = NodeType::add("ies_light", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(IESLightNode);
+
+ SOCKET_STRING(ies, "IES", ustring());
+ SOCKET_STRING(filename, "File Name", ustring());
+
+ SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_NORMAL);
+
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+IESLightNode::IESLightNode()
+: TextureNode(node_type)
+{
+ light_manager = NULL;
+ slot = -1;
+}
+
+ShaderNode *IESLightNode::clone() const
+{
+ IESLightNode *node = new IESLightNode(*this);
+
+ node->light_manager = NULL;
+ node->slot = -1;
+
+ return node;
+}
+
+IESLightNode::~IESLightNode()
+{
+ if(light_manager) {
+ light_manager->remove_ies(slot);
+ }
+}
+
+void IESLightNode::get_slot()
+{
+ assert(light_manager);
+
+ if(slot == -1) {
+ if(ies.empty()) {
+ slot = light_manager->add_ies_from_file(filename);
+ }
+ else {
+ slot = light_manager->add_ies(ies);
+ }
+ }
+}
+
+void IESLightNode::compile(SVMCompiler& compiler)
+{
+ light_manager = compiler.light_manager;
+ get_slot();
+
+ ShaderInput *strength_in = input("Strength");
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *fac_out = output("Fac");
+
+ int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+
+ compiler.add_node(NODE_IES,
+ compiler.encode_uchar4(
+ compiler.stack_assign_if_linked(strength_in),
+ vector_offset,
+ compiler.stack_assign(fac_out),
+ 0),
+ slot,
+ __float_as_int(strength));
+
+ tex_mapping.compile_end(compiler, vector_in, vector_offset);
+}
+
+void IESLightNode::compile(OSLCompiler& compiler)
+{
+ light_manager = compiler.light_manager;
+ get_slot();
+
+ tex_mapping.compile(compiler);
+
+ compiler.parameter("slot", slot);
+ compiler.add(this, "node_ies_light");
+}
+
/* Musgrave Texture */
NODE_DEFINE(MusgraveTextureNode)
@@ -1470,7 +1562,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
}
if(slot != -1) {
- compiler.parameter("filename", string_printf("@%d", slot).c_str());
+ compiler.parameter("filename", string_printf("@i%d", slot).c_str());
}
if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", tfm);
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 58c3d472cd3..35a7df690c3 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -25,6 +25,7 @@
CCL_NAMESPACE_BEGIN
class ImageManager;
+class LightManager;
class Scene;
class Shader;
@@ -281,6 +282,27 @@ public:
}
};
+class IESLightNode : public TextureNode {
+public:
+ SHADER_NODE_NO_CLONE_CLASS(IESLightNode)
+
+ ~IESLightNode();
+ ShaderNode *clone() const;
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
+ ustring filename;
+ ustring ies;
+
+ float strength;
+ float3 vector;
+
+private:
+ LightManager *light_manager;
+ int slot;
+
+ void get_slot();
+};
+
class MappingNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MappingNode)
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index f1a22350060..dde622bff8a 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -99,7 +99,9 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
* compile shaders alternating */
thread_scoped_lock lock(ss_mutex);
- OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager);
+ OSLCompiler compiler((void*)this, (void*)ss,
+ scene->image_manager,
+ scene->light_manager);
compiler.background = (shader == scene->default_background);
compiler.compile(scene, og, shader);
@@ -546,11 +548,14 @@ OSLNode *OSLShaderManager::osl_node(const std::string& filepath,
/* Graph Compiler */
-OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_)
+OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_,
+ ImageManager *image_manager_,
+ LightManager *light_manager_)
{
manager = manager_;
shadingsys = shadingsys_;
image_manager = image_manager_;
+ light_manager = light_manager_;
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
background = false;
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 95e35dd857b..7a3208c402a 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -120,7 +120,9 @@ protected:
class OSLCompiler {
public:
- OSLCompiler(void *manager, void *shadingsys, ImageManager *image_manager);
+ OSLCompiler(void *manager, void *shadingsys,
+ ImageManager *image_manager,
+ LightManager *light_manager);
void compile(Scene *scene, OSLGlobals *og, Shader *shader);
void add(ShaderNode *node, const char *name, bool isfilepath = false);
@@ -146,6 +148,7 @@ public:
bool background;
ImageManager *image_manager;
+ LightManager *light_manager;
private:
#ifdef WITH_OSL
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index ba47e3ab6f8..b35cdbd3db5 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -76,7 +76,8 @@ DeviceScene::DeviceScene(Device *device)
svm_nodes(device, "__svm_nodes", MEM_TEXTURE),
shaders(device, "__shaders", MEM_TEXTURE),
lookup_table(device, "__lookup_table", MEM_TEXTURE),
- sobol_directions(device, "__sobol_directions", MEM_TEXTURE)
+ sobol_directions(device, "__sobol_directions", MEM_TEXTURE),
+ ies_lights(device, "__ies", MEM_TEXTURE)
{
memset(&data, 0, sizeof(data));
}
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 04bd4735a86..6c67433c9fc 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -119,6 +119,9 @@ public:
/* integrator */
device_vector<uint> sobol_directions;
+ /* ies lights */
+ device_vector<float> ies_lights;
+
KernelData data;
DeviceScene(Device *device);
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index c5b4060d5c3..eb8a35a271f 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -58,7 +58,7 @@ void SVMShaderManager::device_update_shader(Scene *scene,
svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
SVMCompiler::Summary summary;
- SVMCompiler compiler(scene->shader_manager, scene->image_manager);
+ SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->light_manager);
compiler.background = (shader == scene->default_background);
compiler.compile(scene, shader, svm_nodes, 0, &summary);
@@ -154,10 +154,13 @@ void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *s
/* Graph Compiler */
-SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_manager_)
+SVMCompiler::SVMCompiler(ShaderManager *shader_manager_,
+ ImageManager *image_manager_,
+ LightManager *light_manager_)
{
shader_manager = shader_manager_;
image_manager = image_manager_;
+ light_manager = light_manager_;
max_stack_use = 0;
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index 18be0fa9a22..7cf1e4ad791 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -95,7 +95,9 @@ public:
string full_report() const;
};
- SVMCompiler(ShaderManager *shader_manager, ImageManager *image_manager);
+ SVMCompiler(ShaderManager *shader_manager,
+ ImageManager *image_manager,
+ LightManager *light_manager);
void compile(Scene *scene,
Shader *shader,
array<int4>& svm_nodes,
@@ -125,6 +127,7 @@ public:
ImageManager *image_manager;
ShaderManager *shader_manager;
+ LightManager *light_manager;
bool background;
protected: