Cycles: support for environment texture "Mirror Ball" projection mode, next to
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Thu, 8 Mar 2012 19:52:58 +0000 (19:52 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Thu, 8 Mar 2012 19:52:58 +0000 (19:52 +0000)
existing "Equirectangular". This projection is useful to create light probes
from a chrome ball placed in a real scene. It expects as input a photograph of
the chrome ball, cropped so the ball just fits inside the image boundaries.

Example setup with panorama camera and mixing two (poor quality) photographs
from different viewpoints to avoid stretching and hide the photographer:
http://www.pasteall.org/pic/28036

intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/kernel_montecarlo.h
intern/cycles/kernel/svm/svm_image.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
intern/cycles/render/svm.cpp
intern/cycles/render/svm.h
source/blender/editors/space_node/drawnode.c
source/blender/makesdna/DNA_node_types.h
source/blender/makesrna/intern/rna_nodetree.c
source/blender/nodes/shader/nodes/node_shader_tex_environment.c

index 45076122467a575b894293980d7100f64701a546..5c26a4d216398bdae8afc16a517cd08a63ec444d 100644 (file)
@@ -332,6 +332,7 @@ static ShaderNode *add_node(BL::BlendData b_data, ShaderGraph *graph, BL::Shader
                        if(b_image)
                                env->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
                        env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
+                       env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
                        get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
                        node = env;
                        break;
index 66bd0ee9998a94b2557f8a192e33ed892339df8c..68f007cfd97a12495499df86d0b5ebd6f1b5a3fb 100644 (file)
@@ -224,6 +224,38 @@ __device float3 equirectangular_to_direction(float u, float v)
                cos(theta));
 }
 
+/* Mirror Ball <-> Cartesion direction */
+
+__device float3 mirrorball_to_direction(float u, float v)
+{
+       /* point on sphere */
+       float3 dir;
+
+       dir.x = 2.0f*u - 1.0f;
+       dir.z = 2.0f*v - 1.0f;
+       dir.y = -sqrt(max(1.0f - dir.x*dir.x - dir.z*dir.z, 0.0f));
+
+       /* reflection */
+       float3 I = make_float3(0.0f, -1.0f, 0.0f);
+
+       return 2.0f*dot(dir, I)*dir - I;
+}
+
+__device float2 direction_to_mirrorball(float3 dir)
+{
+       /* inverse of mirrorball_to_direction */
+       dir.y -= 1.0f;
+
+       float div = 2.0f*sqrt(max(-0.5f*dir.y, 0.0f));
+       if(div > 0.0f)
+               dir /= div;
+
+       float u = 0.5f*(dir.x + 1.0f);
+       float v = 0.5f*(dir.z + 1.0f);
+
+       return make_float2(u, v);
+}
+
 CCL_NAMESPACE_END
 
 #endif /* __KERNEL_MONTECARLO_CL__ */
index 3d737b483cbddbac1f7bdd5d42d3e444715cb5b5..eddd0f7034a8844b2a3f9638502caaf62b584670 100644 (file)
@@ -171,11 +171,20 @@ __device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float
 {
        uint id = node.y;
        uint co_offset, out_offset, alpha_offset, srgb;
+       uint projection = node.w;
 
        decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
 
        float3 co = stack_load_float3(stack, co_offset);
-       float2 uv = direction_to_equirectangular(co);
+       float2 uv;
+
+       co = normalize(co);
+       
+       if(projection == 0)
+               uv = direction_to_equirectangular(co);
+       else
+               uv = direction_to_mirrorball(co);
+
        float4 f = svm_image_texture(kg, id, uv.x, uv.y);
        float3 r = make_float3(f.x, f.y, f.z);
 
index 86f0f3127e9cce6d29184718be16fec63da21e7f..a98352aa85a7accb3a302c288efa7b9e297f1932 100644 (file)
@@ -146,19 +146,26 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
                compiler.stack_assign(alpha_out);
 
        if(slot != -1) {
-               int srgb = (is_float || color_space != "Color")? 0: 1;
                compiler.stack_assign(vector_in);
 
-               if(!tex_mapping.skip())
-                       tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+               int srgb = (is_float || color_space != "Color")? 0: 1;
+               int vector_offset = vector_in->stack_offset;
+
+               if(!tex_mapping.skip()) {
+                       vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+                       tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+               }
 
                compiler.add_node(NODE_TEX_IMAGE,
                        slot,
                        compiler.encode_uchar4(
-                               vector_in->stack_offset,
+                               vector_offset,
                                color_out->stack_offset,
                                alpha_out->stack_offset,
                                srgb));
+       
+               if(vector_offset != vector_in->stack_offset)
+                       compiler.stack_clear_offset(vector_in->type, vector_offset);
        }
        else {
                /* image not found */
@@ -183,7 +190,18 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
 
 /* Environment Texture */
 
+static ShaderEnum projection_init()
+{
+       ShaderEnum enm;
+
+       enm.insert("Equirectangular", 0);
+       enm.insert("Mirror Ball", 1);
+
+       return enm;
+}
+
 ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
+ShaderEnum EnvironmentTextureNode::projection_enum = projection_init();
 
 EnvironmentTextureNode::EnvironmentTextureNode()
 : TextureNode("environment_texture")
@@ -193,6 +211,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
        is_float = false;
        filename = "";
        color_space = ustring("Color");
+       projection = ustring("Equirectangular");
 
        add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
        add_output("Color", SHADER_SOCKET_COLOR);
@@ -228,22 +247,29 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
                compiler.stack_assign(color_out);
        if(!alpha_out->links.empty())
                compiler.stack_assign(alpha_out);
-
+       
        if(slot != -1) {
-               int srgb = (is_float || color_space != "Color")? 0: 1;
-
                compiler.stack_assign(vector_in);
 
-               if(!tex_mapping.skip())
-                       tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+               int srgb = (is_float || color_space != "Color")? 0: 1;
+               int vector_offset = vector_in->stack_offset;
+
+               if(!tex_mapping.skip()) {
+                       vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+                       tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+               }
 
                compiler.add_node(NODE_TEX_ENVIRONMENT,
                        slot,
                        compiler.encode_uchar4(
-                               vector_in->stack_offset,
+                               vector_offset,
                                color_out->stack_offset,
                                alpha_out->stack_offset,
-                               srgb));
+                               srgb),
+                       projection_enum[projection]);
+       
+               if(vector_offset != vector_in->stack_offset)
+                       compiler.stack_clear_offset(vector_in->type, vector_offset);
        }
        else {
                /* image not found */
@@ -351,11 +377,19 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
 
        if(vector_in->link)
                compiler.stack_assign(vector_in);
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        compiler.stack_assign(color_out);
-       compiler.add_node(NODE_TEX_SKY, vector_in->stack_offset, color_out->stack_offset);
+       compiler.add_node(NODE_TEX_SKY, vector_offset, color_out->stack_offset);
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void SkyTextureNode::compile(OSLCompiler& compiler)
@@ -402,8 +436,12 @@ void GradientTextureNode::compile(SVMCompiler& compiler)
 
        if(vector_in->link) compiler.stack_assign(vector_in);
 
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        if(!fac_out->links.empty())
                compiler.stack_assign(fac_out);
@@ -411,7 +449,10 @@ void GradientTextureNode::compile(SVMCompiler& compiler)
                compiler.stack_assign(color_out);
 
        compiler.add_node(NODE_TEX_GRADIENT,
-               compiler.encode_uchar4(type_enum[type], vector_in->stack_offset, fac_out->stack_offset, color_out->stack_offset));
+               compiler.encode_uchar4(type_enum[type], vector_offset, fac_out->stack_offset, color_out->stack_offset));
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void GradientTextureNode::compile(OSLCompiler& compiler)
@@ -448,8 +489,12 @@ void NoiseTextureNode::compile(SVMCompiler& compiler)
        if(detail_in->link) compiler.stack_assign(detail_in);
        if(distortion_in->link) compiler.stack_assign(distortion_in);
 
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        if(!fac_out->links.empty())
                compiler.stack_assign(fac_out);
@@ -457,12 +502,15 @@ void NoiseTextureNode::compile(SVMCompiler& compiler)
                compiler.stack_assign(color_out);
 
        compiler.add_node(NODE_TEX_NOISE,
-               compiler.encode_uchar4(vector_in->stack_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset),
+               compiler.encode_uchar4(vector_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset),
                compiler.encode_uchar4(color_out->stack_offset, fac_out->stack_offset));
        compiler.add_node(
                __float_as_int(scale_in->value.x),
                __float_as_int(detail_in->value.x),
                __float_as_int(distortion_in->value.x));
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void NoiseTextureNode::compile(OSLCompiler& compiler)
@@ -506,16 +554,23 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler)
        if(vector_in->link) compiler.stack_assign(vector_in);
        if(scale_in->link) compiler.stack_assign(scale_in);
 
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        compiler.stack_assign(color_out);
        compiler.stack_assign(fac_out);
 
        compiler.add_node(NODE_TEX_VORONOI,
                coloring_enum[coloring],
-               compiler.encode_uchar4(scale_in->stack_offset, vector_in->stack_offset, fac_out->stack_offset, color_out->stack_offset),
+               compiler.encode_uchar4(scale_in->stack_offset, vector_offset, fac_out->stack_offset, color_out->stack_offset),
                __float_as_int(scale_in->value.x));
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void VoronoiTextureNode::compile(OSLCompiler& compiler)
@@ -578,8 +633,12 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
        if(gain_in->link) compiler.stack_assign(gain_in);
        if(scale_in->link) compiler.stack_assign(scale_in);
 
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        if(!fac_out->links.empty())
                compiler.stack_assign(fac_out);
@@ -587,7 +646,7 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
                compiler.stack_assign(color_out);
 
        compiler.add_node(NODE_TEX_MUSGRAVE,
-               compiler.encode_uchar4(type_enum[type], vector_in->stack_offset, color_out->stack_offset, fac_out->stack_offset),
+               compiler.encode_uchar4(type_enum[type], vector_offset, color_out->stack_offset, fac_out->stack_offset),
                compiler.encode_uchar4(dimension_in->stack_offset, lacunarity_in->stack_offset, detail_in->stack_offset, offset_in->stack_offset),
                compiler.encode_uchar4(gain_in->stack_offset, scale_in->stack_offset));
        compiler.add_node(__float_as_int(dimension_in->value.x),
@@ -596,6 +655,9 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
                __float_as_int(offset_in->value.x));
        compiler.add_node(__float_as_int(gain_in->value.x),
                __float_as_int(scale_in->value.x));
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void MusgraveTextureNode::compile(OSLCompiler& compiler)
@@ -650,8 +712,12 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
        if(dscale_in->link) compiler.stack_assign(dscale_in);
        if(vector_in->link) compiler.stack_assign(vector_in);
 
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        if(!fac_out->links.empty())
                compiler.stack_assign(fac_out);
@@ -660,13 +726,16 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
 
        compiler.add_node(NODE_TEX_WAVE,
                compiler.encode_uchar4(type_enum[type], color_out->stack_offset, fac_out->stack_offset, dscale_in->stack_offset),
-               compiler.encode_uchar4(vector_in->stack_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset));
+               compiler.encode_uchar4(vector_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset));
 
        compiler.add_node(
                __float_as_int(scale_in->value.x),
                __float_as_int(detail_in->value.x),
                __float_as_int(distortion_in->value.x),
                __float_as_int(dscale_in->value.x));
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void WaveTextureNode::compile(OSLCompiler& compiler)
@@ -703,8 +772,12 @@ void MagicTextureNode::compile(SVMCompiler& compiler)
        if(distortion_in->link) compiler.stack_assign(distortion_in);
        if(scale_in->link) compiler.stack_assign(scale_in);
 
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        if(!fac_out->links.empty())
                compiler.stack_assign(fac_out);
@@ -713,10 +786,13 @@ void MagicTextureNode::compile(SVMCompiler& compiler)
 
        compiler.add_node(NODE_TEX_MAGIC,
                compiler.encode_uchar4(depth, color_out->stack_offset, fac_out->stack_offset),
-               compiler.encode_uchar4(vector_in->stack_offset, scale_in->stack_offset, distortion_in->stack_offset));
+               compiler.encode_uchar4(vector_offset, scale_in->stack_offset, distortion_in->stack_offset));
        compiler.add_node(
                __float_as_int(scale_in->value.x),
                __float_as_int(distortion_in->value.x));
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void MagicTextureNode::compile(OSLCompiler& compiler)
@@ -754,8 +830,12 @@ void CheckerTextureNode::compile(SVMCompiler& compiler)
        compiler.stack_assign(color2_in);
        if(scale_in->link) compiler.stack_assign(scale_in);
 
-       if(!tex_mapping.skip())
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_in->stack_offset);
+       int vector_offset = vector_in->stack_offset;
+
+       if(!tex_mapping.skip()) {
+               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
+       }
 
        if(!color_out->links.empty())
                compiler.stack_assign(color_out);
@@ -763,9 +843,12 @@ void CheckerTextureNode::compile(SVMCompiler& compiler)
                compiler.stack_assign(fac_out);
 
        compiler.add_node(NODE_TEX_CHECKER,
-               compiler.encode_uchar4(vector_in->stack_offset, color1_in->stack_offset, color2_in->stack_offset, scale_in->stack_offset),
+               compiler.encode_uchar4(vector_offset, color1_in->stack_offset, color2_in->stack_offset, scale_in->stack_offset),
                compiler.encode_uchar4(color_out->stack_offset, fac_out->stack_offset),
                __float_as_int(scale_in->value.x));
+
+       if(vector_offset != vector_in->stack_offset)
+               compiler.stack_clear_offset(vector_in->type, vector_offset);
 }
 
 void CheckerTextureNode::compile(OSLCompiler& compiler)
index 6c9ed422b88de34c7f2cb6535e363cf153a77326..e0329cb9b1d156ed25e78eeb07a9ac34a9016d24 100644 (file)
@@ -82,8 +82,10 @@ public:
        bool is_float;
        string filename;
        ustring color_space;
+       ustring projection;
 
        static ShaderEnum color_space_enum;
+       static ShaderEnum projection_enum;
 };
 
 class SkyTextureNode : public TextureNode {
index ae666ddfe68aed39c4af005ea74090a5f99b7777..46c6149ab32da03c0af7093d38c31dbc1f24b066 100644 (file)
@@ -161,6 +161,14 @@ int SVMCompiler::stack_find_offset(ShaderSocketType type)
        return offset;
 }
 
+void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset)
+{
+       int size = stack_size(type);
+
+       for(int i = 0; i < size; i++)
+               active_stack.users[offset + i]--;
+}
+
 void SVMCompiler::stack_backup(StackBackup& backup, set<ShaderNode*>& done)
 {
        backup.done = done;
@@ -261,11 +269,7 @@ void SVMCompiler::stack_clear_users(ShaderNode *node, set<ShaderNode*>& done)
                                        all_done = false;
 
                        if(all_done) {
-                               int size = stack_size(output->type);
-
-                               for(int i = 0; i < size; i++)
-                                       active_stack.users[output->stack_offset + i]--;
-
+                               stack_clear_offset(output->type, output->stack_offset);
                                output->stack_offset = SVM_STACK_INVALID;
 
                                foreach(ShaderInput *in, output->links)
@@ -279,11 +283,7 @@ void SVMCompiler::stack_clear_temporary(ShaderNode *node)
 {
        foreach(ShaderInput *input, node->inputs) {
                if(!input->link && input->stack_offset != SVM_STACK_INVALID) {
-                       int size = stack_size(input->type);
-
-                       for(int i = 0; i < size; i++)
-                               active_stack.users[input->stack_offset + i]--;
-
+                       stack_clear_offset(input->type, input->stack_offset);
                        input->stack_offset = SVM_STACK_INVALID;
                }
        }
@@ -514,14 +514,14 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don
                        generate_multi_closure(cl1in->link->parent, done, out1_offset);
 
                        if(fin)
-                               active_stack.users[out1_offset]--;
+                               stack_clear_offset(SHADER_SOCKET_FLOAT, out1_offset);
                }
 
                if(cl2in->link) {
                        generate_multi_closure(cl2in->link->parent, done, out2_offset);
 
                        if(fin)
-                               active_stack.users[out2_offset]--;
+                               stack_clear_offset(SHADER_SOCKET_FLOAT, out2_offset);
                }
        }
        else {
index d66d3816068d1e90d150e82a416eab47cafda5ca..d8a1b14d637f6df7e4e6b2b22986e3636a09d72f 100644 (file)
@@ -59,7 +59,10 @@ public:
 
        void stack_assign(ShaderOutput *output);
        void stack_assign(ShaderInput *input);
+       int stack_find_offset(ShaderSocketType type);
+       void stack_clear_offset(ShaderSocketType type, int offset);
        void stack_link(ShaderInput *input, ShaderOutput *output);
+
        void add_node(NodeType type, int a = 0, int b = 0, int c = 0);
        void add_node(int a = 0, int b = 0, int c = 0, int d = 0);
        void add_node(NodeType type, const float3& f);
@@ -115,7 +118,6 @@ protected:
 
        void stack_clear_temporary(ShaderNode *node);
        int stack_size(ShaderSocketType type);
-       int stack_find_offset(ShaderSocketType type);
        void stack_clear_users(ShaderNode *node, set<ShaderNode*>& done);
 
        bool node_skip_input(ShaderNode *node, ShaderInput *input);
index bc22e668b5abf1416d47834f7a85070851da6e16..64af846a79b2cd89dfae456b54d224410607a199 100644 (file)
@@ -1093,6 +1093,14 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
        uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
 }
 
+
+static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+       uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+       uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
+       uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+}
+
 static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE);
@@ -1225,7 +1233,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
                        ntype->uifunc= node_shader_buts_tex_image;
                        break;
                case SH_NODE_TEX_ENVIRONMENT:
-                       ntype->uifunc= node_shader_buts_tex_image;
+                       ntype->uifunc= node_shader_buts_tex_environment;
                        break;
                case SH_NODE_TEX_GRADIENT:
                        ntype->uifunc= node_shader_buts_tex_gradient;
index 0d309aad36c7fc2d4526a34557736990175eb791..dbb3f6bfc6636136f0cf9aac3d7202e066af317e 100644 (file)
@@ -475,7 +475,7 @@ typedef struct NodeTexChecker {
 
 typedef struct NodeTexEnvironment {
        NodeTexBase base;
-       int color_space, pad;
+       int color_space, projection;
 } NodeTexEnvironment;
 
 typedef struct NodeTexGradient {
@@ -585,6 +585,10 @@ typedef struct TexNodeOutput {
 #define SHD_COLORSPACE_NONE            0
 #define SHD_COLORSPACE_COLOR   1
 
+/* environment texture */
+#define SHD_PROJ_EQUIRECTANGULAR       0
+#define SHD_PROJ_MIRROR_BALL           1
+
 /* blur node */
 #define CMP_NODE_BLUR_ASPECT_NONE              0
 #define CMP_NODE_BLUR_ASPECT_Y                 1
index 2caf1f06585fe3f7d4c7301d9298b08bbb7622f2..d3a2e406992cf20e7332875ae47b8d0897a820b9 100644 (file)
@@ -1268,6 +1268,11 @@ static void def_sh_tex_environment(StructRNA *srna)
                {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data", "Image contains non-color data, for example a displacement or normal map, and will not be converted"},
                {0, NULL, 0, NULL, NULL}};
 
+       static const EnumPropertyItem prop_projection_items[] = {
+               {SHD_PROJ_EQUIRECTANGULAR, "EQUIRECTANGULAR", 0, "Equirectangular", "Equirectangular or latitude-longitude projection"},
+               {SHD_PROJ_MIRROR_BALL, "MIRROR_BALL", 0, "Mirror Ball", "Projection from an orthographic photo of a mirror ball"},
+               {0, NULL, 0, NULL, NULL}};
+       
        PropertyRNA *prop;
 
        prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
@@ -1277,13 +1282,19 @@ static void def_sh_tex_environment(StructRNA *srna)
        RNA_def_property_ui_text(prop, "Image", "");
        RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_image_update");
 
-       RNA_def_struct_sdna_from(srna, "NodeTexImage", "storage");
+       RNA_def_struct_sdna_from(srna, "NodeTexEnvironment", "storage");
        def_sh_tex(srna);
 
        prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_items(prop, prop_color_space_items);
        RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
        RNA_def_property_update(prop, 0, "rna_Node_update");
+
+       prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, prop_projection_items);
+       RNA_def_property_ui_text(prop, "Projection", "Projection of the input image");
+       RNA_def_property_update(prop, 0, "rna_Node_update");
+
 }
 
 static void def_sh_tex_image(StructRNA *srna)
index d6957e53f102bfd240d95e56f2ae460106c57992..8ecff6e3767f32d968568b80b0edd1d256c6422d 100644 (file)
@@ -45,6 +45,7 @@ static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode* no
        default_tex_mapping(&tex->base.tex_mapping);
        default_color_mapping(&tex->base.color_mapping);
        tex->color_space = SHD_COLORSPACE_COLOR;
+       tex->projection = SHD_PROJ_EQUIRECTANGULAR;
 
        node->storage = tex;
 }