OSL Porting from RSL

I figured out how to do a color spline, see the example below. I had problems using macros, so I just replaced them with functions.

KMFlame.osl


#include "stdosl.h"


point snoise(point pt) {
    point sn; 
    sn=( 2 * noise(pt))-1; 
    return sn;}


point DNoise(point pt) {
    point DN; 
    DN=(2 * (noise(pt)) - point(1,1,1)); 
    return DN;}


float VLNoise(point Pt, float scale){
    float VLN;
    VLN = snoise(DNoise(Pt)+(scale*Pt));
    return VLN;}


shader KMFlame (
    float distortion = 0,
    float chaosscale = 1,
    float chaosoffset = 0, 
    float octaves = 7,
    float flameheight = 1,
    float flameamplitude = 0.5, 
    output color KMFlame= color(0,0,0)
    )
{
  point PP, PQ;
  float freq;
  float chaos, i, cmap;
  
PP = transform ("object", P);
  PQ = PP;
  PQ *= point (1, 1, exp(-PP[2]));
  freq = 1;  
  chaos = 0;
  for (i = 0;  i < octaves;  i += 1) {
      chaos += VLNoise (freq * PQ, distortion) / freq;
      freq *= 2;
    }
chaos =abs(chaosscale * chaos + chaosoffset);
cmap = 0.85 * chaos + 0.8 * (flameamplitude - flameheight * (PP[2]));
color colorarray[17]= {color(0,0,0), 
color(0,0,0),
color(0.10588235294117647, 0.0, 0.0),
color(0.21176470588235294, 0.0, 0.0),
color(0.3176470588235294, 0.0, 0.0),
color(0.42745098039215684, 0.0, 0.0),
color(0.5333333333333333, 0.0, 0.0),
color(0.6509803921568628, 0.0196078431372549, 0.0),
color(0.6509803921568628, 0.0196078431372549, 0.0),
color(0.8274509803921568, 0.23529411764705882, 0.0),
color(0.9058823529411765, 0.3568627450980392, 0.0),
color(0.9333333333333333, 0.5019607843137255, 0.0),
color(0.9568627450980393, 0.6352941176470588, 0.047058823529411764),
color(0.9725490196078431, 0.7333333333333333, 0.22745098039215686),
color(0.984313725490196, 0.8196078431372549, 0.45098039215686275),
color(0.996078431372549, 0.9254901960784314, 0.8235294117647058),
color(1.0, 0.9450980392156862, 0.9019607843137255),
color(1.0, 0.9450980392156862, 0.9019607843137255)
};




KMFlame = spline("linear",cmap,colorarray);
}
    

http://www.pasteall.org/pic/show.php?id=41597
http://www.pasteall.org/pic/show.php?id=41597

I tried Porting KMCyclone, and it chokes up at the same type of place. It seems to have problems with the macros at the beginning. I am not sure what is wrong with the macro. any advice is appreciated.

edit: I fixed this one by converting the macros into functions.


/* I took wave's lead and renamed starfield to KMCyclone.sl -- tal AT renderman DOT org */


/*
 * cyclone.sl - surface for a semi-opaque cloud layer to be put on an
 *              earth-like planetary model to model clouds and a cyclone.
 *
 * DESCRIPTION:
 *      When put on a sphere, sets the color & opacity of the sphere to
 *   make it look like the clouds surrounding an Earth-like planet, with
 *   a big cyclone.
 *      The shader works by creating a fractal turbulence function over
 *   the surface, then modulating the opacity based on this function in
 *   a way that looks like clouds on a planetary scale.
 *
 *
 * PARAMETERS:
 *    Ka, Kd - the usual meaning
 *    cloudcolor - the color of the clouds, usually white
 *    max_radius
 *    twist - controls the twisting of the clouds due to the cyclone.
 *    offset, scale - control the linear scaling of the cloud value.
 *    omega, octaves - controls the fractal characteristics of the clouds
 *
 *
 * HINTS:
 *    See the "planetclouds" shader for hints which apply equally well
 *    to this shader.
 *
 *
 * AUTHOR: Ken Musgrave
 *    Conversion to Shading Language and other minor changes by Larry Gritz.
 *
 * REFERENCES:
 *    _Texturing and Modeling: A Procedural Approach_, by David S. Ebert, ed.,
 *    F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, and Steven Worley.
 *    Academic Press, 1994.  ISBN 0-12-228760-6.
 *
 * HISTORY:
 *    ???? - original texture developed by Ken Musgrave.
 *    Feb 1994 - Conversion to Shading Language by L. Gritz
 *
 * last modified 1 March 1994 by lg
 */






#define TWOPI (2*M_PI)


/* Use signed Perlin noise */
//#define snoise(x) ((2*noise(x))-1)
//#define DNoise(p) (2*(point noise(p)) - point(1,1,1))
//#define VLNoise(Pt,scale) (snoise(DNoise(Pt)+(scale*Pt)))
#define VERY_SMALL (0.001)


point snoise(point pt) {
    point sn; 
    sn=( 2 * noise(pt))-1; 
    return sn;}


point DNoise(point pt) {
    point DN; 
    DN=(2 * (noise(pt)) - point(1,1,1)); 
    return DN;}


float VLNoise(point Pt, float scale){
    float VLN;
    VLN = snoise(DNoise(Pt)+(scale*Pt));
    return VLN;}




shader
KMCyclone (
     float max_radius = 1,
     float twist = 0.5,
     float scale = .7,
     float offset = .5,
     float omega = 0.675,
     float octaves = 4,
    output float CloudValue = 0)
{
  float radius, dist, angle, sine, cosine, eye_weight, value;
  point Pt;                 /* Point in texture space */
  point PN;                 /* Normalized vector in texture space */
  point PP;                 /* Point after distortion */
  float l, o, a, i;         /* Loop control for fractal sum */


  /* Transform to texture coordinates */
  Pt = transform ("shader", P);


  /* Rotate hit point to "cyclone space" */
  PN = normalize (Pt);
  radius = sqrt (PN[0]*PN[0] + PN[1]*PN[1]);


  if (radius < max_radius) {   /* inside of cyclone */
      /* invert distance from center */
      dist = pow (max_radius - radius, 3);
      angle = M_PI + twist * TWOPI * (max_radius-dist) / max_radius;
      sine = sin (angle);
      cosine = cos (angle);
      PP = point (Pt[0]*cosine - Pt[1]*sine,
          Pt[0]*sine + Pt[1]*cosine,
          Pt[2]);
      /* Subtract out "eye" of storm */
      if (radius < 0.05*max_radius) {  /* if in "eye" */
      eye_weight = (.1*max_radius - radius) * 10;   /* normalize */
      /* invert and make nonlinear */
      eye_weight = pow (1 - eye_weight, 4);
    }
      else eye_weight = 1;
    }
  else PP = Pt;


  if (eye_weight > 0) {   /* if in "storm" area */
      /* Compute VLfBm */
      l = 1;  o = 1;  a = 0;
      for (i = 0;  i < octaves  &&  o >= VERY_SMALL;  i += 1) {
      a += o * VLNoise (PP * l, 1);
      l *= 2;
      o *= omega;
    }
      value = abs (eye_weight * (offset + scale * a));
    }
  else value = 0;


  /* Thin the density of the clouds */
  CloudValue = abs(value);
}

http://www.pasteall.org/pic/41594http://www.pasteall.org/pic/show.php?id=41594

nice work :slight_smile:

Yes, this is interesting. I wondered how compatible OSL was with RSL?

OSL and Renderman are very compatible, with the exception of illumination loops, and light shaders, and stuff like that which have been replaced by closures. I hope they do a tutorial on writing closures, since they have to be done in c still.

I think the color and displacement part of OSL is more compatible with Renderman, especially since it was designed for Renderman shader writers to transition over to OSL seamlessly. There are a few small details that OSL does not like, from the Renderman shaders.

The biggest things that I notice, are below. Some of them I am thinking about including as feature requests.

  1. I want the common Outputs, like Ci, Ct to be available as outputs. Cycles reserves the variables, but I don’t know how to make it an output.
  2. P works, just fine, and you can transform it as you could in Renderman, with the same commands.
  3. Instead of using, xcomp,ycomp,and zcomp, you must us variable[0], variable[1],variable[2]
  4. s, and t have to be declared and assigned. You need is to do the following…
    float s = P[0];
    float t = P[1];
    5)“du” and “dv” are now “dy” & “dx”
  5. I have problems getting preprocessor macros to work because of type issues. My work around is to just convert them into functions.
  6. There are one or two functions missing in the pattern generation, I am not sure which ones, but most of them work just like in OSL, except the results tend to look nicer with build in global illumination.

Thanks for the detailed explanation. A few months back I was fairly involved in RSL on a daily basis and when I saw OSL emerge I thought…“Oh great, I just spent another few months developing a skill set that is on it’s way out.” It is nice to see there are some parallels. I have been waiting for 2.65 to come out so I would have a stable version to begin with.

I have been porting the watermelon shader from RSL Guide. There is one line of code that crashes blender, I’ve filed a bug report at https://projects.blender.org/tracker/index.php?func=detail&aid=33498&group_id=9&atid=498. It works if you comment it out. I also found a discrepancy between viewport and rendered when I used the dented shader that I ported. see below…

WATERMELON.OSL


#include "stdosl.h"
/* Define metrics for estimating filter widths, if none has already
 * been defined.  This is crucial for antialiasing.
 */
#ifndef MINFILTWIDTH
#  define MINFILTWIDTH 1.0e-6
#endif


float smoothpulse (float e0, float e1, float e2, float e3, float x)
	{return smoothstep(e0,e1,x) - smoothstep(e2,e3,x);}


/* Signed noise -- the original Perlin kind with range (-1,1) We prefer
 * signed noise to regular noise mostly because its average is zero.
 * We define three simple macros:snoisexy(x,y) - Perlin noise on a 2-D domain.*/
float snoisexy(float x, float y) 
	{return (2 * noise("perlin",x,y) - 1);}
vector vsnoise(point p) 
	{return 2 * (noise(p)) - 1;}
	
/* The filterwidthp macro is similar to filterwidth, but is for 
 * point data. */
float filterwidthp(point p) 
	{return max (sqrt(area(p)), MINFILTWIDTH);}


float filteredabs (float x, float dx){
    float integral (float t) {
	return sign(t) * 0.5 * t*t;
    }


    float x0 = x - 0.5*dx;
    float x1 = x0 + dx;
    return (integral(x1) - integral(x0)) / dx;}
    
/* If we know the filter size, we can crudely antialias snoise by fading
 * to its average value at approximately the Nyquist limit.
 */
float filteredsnoise(point p, float width) 
	{return snoise(p) * (1-smoothstep (0.2,0.75,width));}
vector filteredvsnoise(point p,float width) 
	{return vsnoise(p) * (1-smoothstep (0.2,0.75,width));}
	
/* Antialiased turbulence.  Watch out -- the abs() call introduces infinite
 * frequency content, which makes our antialiasing efforts much trickier!*/
float turbulence (
	point p, 
	float filtwidth, 
	float octaves, 
	float lacunarity, 
	float gain)
{
float amp = 1;
point pp = p;
float sum = 0, fw = filtwidth;
float i;
for (i = 0;  i < octaves;  i += 1) {
float n = filteredsnoise (pp, fw);
sum += amp * filteredabs (n, fw);
amp *= gain;  pp *= lacunarity;  fw *= lacunarity;}
return sum;}


/* A vector-valued antialiased fBm. */
vector vfBm (point p, float filtwidth,
      float octaves, float lacunarity, float gain)
{
    float amp = 1;
    point pp = p;
    vector sum = 0;
    float fw = filtwidth;
    float i;


    for (i = 0;  i < octaves;  i += 1) {
	sum += amp * filteredvsnoise (pp, fw);
	amp *= gain;  pp *= lacunarity;  fw *= lacunarity;
    }
    return sum;
}


shader watermelon(
	color baseColor = color(0.56,0.6,0.41),
	float baseFreq = 4,
	float label = 0.5,
	color stripeColor = color(0.35,0.45,0.31),
	float stripeFreq = 25,
	float stripeNoiAmp = 0.015,
	float stripeNoiLevels = 12,
	float stripeNoiFreq = 5,
	float detailFreq = 20,
	point st = P,
	output color Final = (0)
	)


{
/* Initialize shader variables */
color sc,lc;
float lo;
float s = st[0];
float t = st[1];


/*Layer 1 - Base color */


/*Transform P from "current" to "shader" */
point Pshad = transform("shader",P) * baseFreq + label;


/*calculate a very simple noise to drive the spline function*/
float smallnoise = noise(2 * Pshad);


/*create variations of the baseColor to pass it to the spline function */


color basevariation[11] = {
	baseColor - 0.0006265412909334433,
	baseColor - 0.0006265412909334433,
	baseColor - 6.504321932827129e-05,
	baseColor,
	baseColor + 0.0001829220207709304,
	baseColor + 0.0001829220207709304,
	baseColor - 6.504321932827129e-05,
	baseColor,
	baseColor + 0.0001829220207709304, 
	baseColor + color(0.0001829220207709304,0.0001829220207709304,0.0001829220207709304),
	baseColor + color(0.0001829220207709304,0.0001829220207709304,0.0001829220207709304)
	};
	
/* use the spline function to color the base of the watermelon */
sc = spline("linear", smallnoise,basevariation);


/* Layer 2 - Dark green stripes
 * compute base noise based on the texture coordinates.
 * This is a turbulence noise that uses gradual clamping.
 * it was taken from Steve May;s RmanNotes */
 
float width = filterwidthp(Pshad);
float cutoff = clamp(0.5 / width, 0, stripeNoiLevels); //4 = maxfreq
float f;


float turb = 0;
for (f=1; f < 0.5 * cutoff; f *= 2)
	turb += abs(snoise(Pshad * stripeNoiFreq * f)) / f;


float fade = clamp(2 * (cutoff -f) / cutoff, 0,1);
turb += fade * abs(snoise(Pshad * f))/f;


/* perturb s based on turb, add the label to control randomness */
float ss = s + snoise(turb + 912) * stripeNoiAmp + label;


lc = stripeColor;
/*use a noise to create broad long noisy stripes */
float stripeOp = abs(snoisexy(stripeFreq*ss, 0.6 *t));
float lo1 = smoothpulse(0.1,0.3,0.74,0.94,stripeOp);
lo = smoothpulse(0.5,0.3,0.74,0.94,stripeOp);


sc = mix(sc,lc,lo);


/* Layer 3 - Veins / Detail within th stripes */


Pshad = label + detailFreq * transform("shader",P);
float Pshadw = filterwidthp(Pshad);


/* First calculate the underlying color of the substrate
 * Use turbulence - use frequncy clamping */
 
turb = 0.5 * turbulence (Pshad, Pshadw, 5, 2, 0.5);
//color stripeDetail = spline("linear",turb,basevariation);


//sc = mix (sc,stripeDetail,lo1 * smoothstep(0.1,0.3,turb));


/* Layer 3 */


/*perturb the point lookup */
Pshad += vector(35.2, -21.9, 6.25) + vfBm(Pshad,Pshadw, 6, 2, 0.5);


/* Now calculate the veining function for the lookup area */
float turbsum, freq, i;
turbsum = 0;
freq = 1;
Pshad *= 0.75; // scale down the scale of Pshad
for(i = 0; i < 4; i += 1)
	{ turb = abs(filteredsnoise(Pshad * freq,Pshadw * freq));
	turb = pow (smoothstep (0.55,0.98,1 - turb), 30)/ freq;
	turbsum += (1-turbsum) * turb;
	freq *= 2;}
	
	turbsum *= smoothstep (-0.1,0.05, snoise((Pshad+vector(-4.4,8.34,27.1))));
	
	sc = mix (sc,stripeColor * 0.9, turbsum*lo1);


Final = sc;


}

DENTED.OSL


/* Copyrighted Pixar 1989 */
/* From the RenderMan Companion p.352 */
/* Listing 16.16  Displacement shader to dent a surface */


/*
 * dented(): Create a worn surface.
 */
normal PolygonDisplaceFix(normal N, float amount){
	point P;
	normal Ng;
	normal Ndiff;
	Ndiff = normalize(N) - normalize(Ng);
	P += amount * normalize(N);
	return normalize(calculatenormal(P)) + Ndiff;}
 
displacement
dented (
	float Km = 1.0,
	output float mag = 0)
{
	float size = 1.0;
	float magnitude = 0.0;
	float i;
	point P2;	
	P2 = transform ("object", P);
	for (i = 0; i < 6.0; i += 1.0)
		/* Calculate a simple fractal 1/f noise function */
		{magnitude += abs (.5 - noise (P2 * size)) / size;
		size *= 2.0;}
	mag =  (magnitude * magnitude * magnitude)* Km;
	P2 = P - normalize (N) * mag;
	N = calculatenormal(P2);
}

ViewPort vs Rendered

Viewport
http://www.pasteall.org/pic/show.php?id=41727

Rendered
http://www.pasteall.org/pic/show.php?id=41729

Moved from “Support > Lighting and Rendering” to “Coding > OSL Tests and Support”

Wouldn’t be too hard to pull the pre-processor code out of something like Pixie so macros worked in OSL. Not too sure on how the ‘OSL spec’ feels about having a pre-processor compile step involved though.

OSL uses the standard C preprocessor already, so macros work, see e.g. here:

I’m not sure why it didn’t work in this particular case, but I think the only reason they were macros in the original code is that RSL didn’t support functions at the time.

The problem I had was not with the fumctionality of the macros, I just could not figure out how to declare the type of the return value with macros. OSL would make the returned value unknown, and I would get error messages when trying to use those functions with real functions. I haven’t tried it with newer builds, so it may be an unusual case.