I don’t really know how nodes work but this seems to make its own copy of the converted image each run so it would probably be pretty slow if used realtime.
If it could be turned into a pixel filter that works like *nix pipes then it should be speedy enough, I’ll look at some of the other shader nodes to see if I can figure out how they work.
Anyway, here’s the code. I had to cheat a little and include CMP_util.h as an easy way to get the struct CompBuf that it uses to store the image data. All I really did was to change around some names so it shows up as a material node, my c coding skills are about as good as my Spanish – I know just enough to get by.
Index: source/blender/blenkernel/BKE_node.h
===================================================================
--- source/blender/blenkernel/BKE_node.h (revision 19002)
+++ source/blender/blenkernel/BKE_node.h (working copy)
@@ -233,6 +233,7 @@
#define SH_NODE_COMBRGB 121
#define SH_NODE_HUE_SAT 122
#define NODE_DYNAMIC 123
+#define SH_NODE_NORMAL_MAP 124
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
Index: source/blender/blenkernel/intern/node.c
===================================================================
--- source/blender/blenkernel/intern/node.c (revision 19002)
+++ source/blender/blenkernel/intern/node.c (working copy)
@@ -2873,6 +2873,7 @@
nodeRegisterType(ntypelist, &sh_node_seprgb);
nodeRegisterType(ntypelist, &sh_node_combrgb);
nodeRegisterType(ntypelist, &sh_node_hue_sat);
+ nodeRegisterType(ntypelist, &sh_node_normal_map);
}
static void registerTextureNodes(ListBase *ntypelist)
Index: source/blender/nodes/SHD_node.h
===================================================================
--- source/blender/nodes/SHD_node.h (revision 19002)
+++ source/blender/nodes/SHD_node.h (working copy)
@@ -62,6 +62,7 @@
extern bNodeType sh_node_seprgb;
extern bNodeType sh_node_combrgb;
extern bNodeType sh_node_hue_sat;
+extern bNodeType sh_node_normal_map;
#endif
Index: source/blender/nodes/intern/SHD_nodes/SHD_normalMap.c
===================================================================
--- source/blender/nodes/intern/SHD_nodes/SHD_normalMap.c (revision 0)
+++ source/blender/nodes/intern/SHD_nodes/SHD_normalMap.c (revision 0)
@@ -0,0 +1,134 @@
+/**
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+
+*/
+
+#include "../SHD_util.h"
+#include "../CMP_util.h"
+
+/* **************** Normal Tools ******************** */
+
+static bNodeSocketType sh_node_normal_in[]= {
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_normal_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_normal_map(CompBuf *stackbuf, CompBuf *cbuf,float *vec)
+{
+ int x, y, sx, sy;
+ float *out= stackbuf->rect;
+ float *xright,*xleft,*height;
+ float *ytop,*ybot;
+ float sum;
+ int dxp,dyp,dxn,dyn;
+
+
+ sx=cbuf->x;
+ sy=cbuf->y;
+
+ for (y=0; y < sy; y++) {
+ for (x=0; x < sx; x++,out+=stackbuf->type) {
+
+ height = compbuf_get_pixel(cbuf, vec, x-cbuf->xrad, y-cbuf->yrad, cbuf->xrad, cbuf->yrad);
+
+ //find the tangent vectors in x and y directions
+ //check corners and sides
+ if (x == 0) dxn = 0;
+ else dxn = -1;
+ if (y == 0) dyn = 0;
+ else dyn = -1;
+ if (x == sx-1) dxp = 0;
+ else dxp = 1;
+ if (y == sy-1) dyp = 0;
+ else dyp = 1;
+
+ xright = compbuf_get_pixel(cbuf, vec,x+dxp-cbuf->xrad,y-cbuf->yrad, cbuf->xrad, cbuf->yrad);
+ xleft = compbuf_get_pixel(cbuf, vec,x+dxn-cbuf->xrad,y-cbuf->yrad, cbuf->xrad, cbuf->yrad);
+ ytop = compbuf_get_pixel(cbuf, vec,x-cbuf->xrad,y+dyp-cbuf->yrad, cbuf->xrad, cbuf->yrad);
+ ybot = compbuf_get_pixel(cbuf, vec,x-cbuf->xrad,y+dyn-cbuf->yrad, cbuf->xrad, cbuf->yrad);
+
+
+ //calculate the difference in height
+ out[0]=(xright[0]+xright[1]+xright[2])- (xleft[0]+xleft[1]+xleft[2]);
+ out[1]=(ytop[0]+ytop[1]+ytop[2])- (ybot[0]+ybot[1]+ybot[2]);
+
+ sum = sqrt(out[0]*out[0]+out[1]*out[1]+1);
+
+ //convert to RGB, scale RG to (-1,1), B to (0,1) to get normal map
+ out[0] = ((-out[0]/sum)+1)/2;
+ out[1] = ((-out[1]/sum)+1)/2;
+ out[2] = 1/sum;
+ out[3] = 1;
+
+ }
+ }
+
+}
+static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(in[0]->data)
+ {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf;
+
+ cbuf= typecheck_compbuf(cbuf, CB_RGBA);
+
+ // allocs
+ stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1);
+
+ do_normal_map(stackbuf,cbuf,in[0]->vec);
+
+ out[0]->data= stackbuf;
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ }
+}
+
+bNodeType sh_node_normal_map= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_NORMAL_MAP,
+ /* name */ "Normal Map",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_normal_in,
+ /* output sock */ sh_node_normal_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_normal,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copysotragefunc */ NULL,
+ /* id */ NULL
+};
+
+
Maybe someone who actually know what they’re doing can look it over.
Don’t know about including this in the build I maintain since I think it’s going about things just wrong but maybe if I can figure out how to do it properly.