这个OSL可以把凹凸或者置换贴图转成法线贴图,节点连接方式如下:
Source:默认是Green通道,因为该通道受到压缩的影响最小。如果你想匹配置换贴图的效果,可以切换到Red通道。
Quality:
Radius:采样区域的半径
Radius_x_Source Power_x_Source
#include <octane-oslintrin.h>
// IMPORTANT: Make sure the input
// is using OSL delayed UV projection.
//
// This shader will convert a height map to a tangent normal map
// based on the average value, luminance or intensity of one of the RGB channels.
//
// If you need many of these nodes with Quality set to High,
// please consider using the baking texture node.
//
// Version: 1.0
//
// Milan - milanm @ Otoy forums
// 0 - Average, 1 - Luminance, 2 - Red, 3 - Green, 4 - Blue.
float toFloat( int method, color input )
{
if (method<=0||method>=5)
{return (input[0]+input[1]+input[2])/3;}
else if (method==1)
{return luminance(input);}
return input[method-2];
}
float liftz(float z, float lift) { return 1-lift*(1-z); }
shader mm_HeightToNormal(
color Input = 1,
point Projection = point(u,v,0),
int Source = 3
[[ string widget = "mapper",
string options = "Average:0|Luminance:1|Red:2|Green:3|Blue:4" ]],
int Quality = 1
[[ string widget = "mapper",
string options = "Low (fast):0|Medium:1|High (slow):2" ]],
float Radius = 1 [[ float sensitivity = 0.01, float min=0, float slidermax=2 ]],
float Power = 1 [[ float sensitivity = 0.1, float min=0, float slidermax=5 ]],
color PowerMap = 1,
float Z_Power = 0.5 [[float min=0,float slidermax=5]],
float Scale = 1 [[ float sensitivity = 0.1, float min=0, float slidermax=1 ]],
float Radius_x_Source = 0.5 [[float min=0,float max=1]],
float Power_x_Source = 0.5 [[float min=0,float max=1]],
float Falloff = 0 [[ float min=0, float max=1 ]],
output color c = 0)
{
color norm = 1;
float x, y, z, bScale, sc;
float uu = Projection[0];
float vv = Projection[1];
float Power2 = Power*PowerMap[1];
if (Radius_x_Source||Power_x_Source)
{
bScale = toFloat(Source,_evaluateDelayed(Input,uu,vv));
sc = mix(Power2,Power2*bScale,Power_x_Source)*Scale;
}
else { bScale = 1; sc = Power2*Scale; }
float o = (( mix(Radius,Radius*bScale,Radius_x_Source) )/1000)*Scale;
float VD = mix(1,dot(-I,N),Falloff);
if (Quality==0)
{
sc*=2;
float ho = o*0.5;
// 3 samples
float m = toFloat(Source,_evaluateDelayed(Input,uu-ho,vv-ho));
float up = toFloat(Source,_evaluateDelayed(Input,uu-ho,vv+ho));
float rg = toFloat(Source,_evaluateDelayed(Input,uu+ho,vv-ho));
x = (m-rg);
y = (m-up);
z = liftz( sqrt(1-((x*x)+(y*y))), Z_Power );
norm = mix(color(0.5,0.5,1),color(x,y,z)/2+0.5,sc*VD);
norm[2] = clamp(norm[2],0.5,1.0);
c = norm;
c = normalize(c*2-1)*0.5+0.5;
return;
}
else if (Quality==1)
{
// 4 samples
float dn = toFloat(Source,_evaluateDelayed(Input,uu,vv-o));
float lf = toFloat(Source,_evaluateDelayed(Input,uu-o,vv));
float up = toFloat(Source,_evaluateDelayed(Input,uu,vv+o));
float rg = toFloat(Source,_evaluateDelayed(Input,uu+o,vv));
x = (lf-rg);
y = (dn-up);
z = liftz( sqrt(1-((x*x)+(y*y))), Z_Power );
norm = mix(color(0.5,0.5,1),color(x,y,z)*0.5+0.5,sc*VD);
norm[2] = clamp(norm[2],0.500001,1.0);
c = normalize(norm*2-1)*0.5+0.5;
return;
}
else if (Quality>=2) // Some plugins don't have a mapper ui
{
sc*=0.25;
// 8 samples
float up = toFloat(Source,_evaluateDelayed(Input,uu,vv+o));
float dn = toFloat(Source,_evaluateDelayed(Input,uu,vv-o));
float lf = toFloat(Source,_evaluateDelayed(Input,uu-o,vv));
float rg = toFloat(Source,_evaluateDelayed(Input,uu+o,vv));
float ur = toFloat(Source,_evaluateDelayed(Input,uu+o,vv+o));
float dr = toFloat(Source,_evaluateDelayed(Input,uu+o,vv-o));
float ul = toFloat(Source,_evaluateDelayed(Input,uu-o,vv+o));
float dl = toFloat(Source,_evaluateDelayed(Input,uu-o,vv-o));
x = (sc*VD) * -(dr-dl+2*(rg-lf)+ur-ul);
y = (sc*VD) * -(ul-dl+2*(up-dn)+ur-dr);
z = 1;
norm = normalize(vector(x,y,z));
norm[2] = liftz( sqrt(1-((norm[0]*norm[0])+(norm[1]*norm[1]))), Z_Power*0.25 );
c = norm*0.5+0.5;
c[2] = clamp(c[2],0.5,1);
return;
}
}