What if you could render 3D primitives directly inside Nuke, with lighting, shadows, reflections, and even depth maps without using scanline render or ray render node ?
While many use it for image filters, color processing, or procedural textures, BlinkScript is powerful enough to handle raymarching algorithms.
By combining BlinkScript with SDF math, we can essentially create a lightweight renderer inside Nuke.
Signed Distance Fields (SDF) in NukeSigned Distance Fields are mathematical functions that describe how far a point in space is from the surface of a shape.
For example:A sphere is defined by the distance from its center minus its radius.A box is defined by checking distances against its half-extents.
More complex shapes like toruses and cylinders are also possible with compact formulas.The magic happens when you combine these formulas with a raymarching loop.
Each pixel on the image plane casts a ray into 3D space, and the script marches forward step by step until it “hits” the surface of a primitive.Features of the SDF Primitives RendererThis BlinkScript kernel is designed to be flexible and artist-friendly.
Here’s what you can control:🎲 Primitive SelectionSphereBox (with adjustable roundness for beveled edges)Torus (major + minor radii)Capped CylinderEach primitive can be positioned, scaled, and rotated using yaw, pitch, roll controls.
🌍 Ground PlaneYou can enable a ground plane to catch shadows and anchor your objects. The plane color and height are adjustable.
💡 Lighting & ShadingThe renderer includes a physically-inspired shading model:
Direct Lighting: Directional light with intensity and color controlsAmbient Light: Base fill to soften shadows
Specular Highlights: With adjustable roughness and specular gainShadows: Hard raytraced shadows with tweakable hardness

Ambient Occlusion: Adds depth and realismA subtle Fresnel rim lighting effect is also included, giving objects a cinematic glow at glancing angles.
🎨 Output ModesYou can choose between four output passes:
Beauty – Final shaded renderNormals – Useful for relighting inside NukeDepth – Normalized Z-depth for compositing tricks like fog or DOFMask – Simple white silhouette for mattes
// SDF_PrimitivesRenderer : sphere/box/torus/cylinder with lighting, AO, shadow, ground plane// Output modes: 0=Beauty, 1=Normals, 2=Depth, 3=Mask// Paste into a BlinkScript node. Set output RGBA.kernel SDF_PrimitivesRenderer : ImageComputationKernel<ePixelWise>{Image<eWrite, eAccessPoint> dst;param:// Render / camerafloat2 res; // (width,height) — set to your formatfloat fov; // vertical FOV in degreesfloat3 camPos;float3 camTarget;float3 camUp;// Primitive selectionint primType; // 0=Sphere, 1=Box, 2=Torus, 3=Cylinderfloat3 primSize; // xyz: radius/halfsize/major-minor where applicablefloat3 primPos; // object positionfloat3 rotYPR; // yaw,pitch,roll in degreesfloat roundness; // box edge roundness (for Box only)// Ground planeint usePlane; // 0/1float planeY; // plane height (Y)float3 planeColor;// Shadingfloat3 baseColor; // albedo for primitivefloat3 lightDir; // normalized-ishfloat3 lightCol;float3 ambientCol;float roughness; // smaller = sharperfloat specGain;float aoGain;float shadowHard;// Outputint outputMode; // 0 Beauty, 1 Normals, 2 Depth, 3 Maskfloat maxDepth; // for depth normalizationfloat time; // seconds (for anim if desired)void define(){defineParam(res, "Resolution", float2(1280.0f,720.0f));defineParam(fov, "FOV", 35.0f);defineParam(camPos, "CamPos", float3(0.0f, 0.4f, 3.6f));defineParam(camTarget, "CamTarget", float3(0.0f, 0.3f, 0.0f));defineParam(camUp, "CamUp", float3(0.0f, 1.0f, 0.0f));defineParam(primType, "Primitive", 0);defineParam(primSize, "PrimSize", float3(0.6f,0.6f,0.6f));defineParam(primPos, "PrimPos", float3(0.0f, 0.6f, 0.0f));defineParam(rotYPR, "Rot_YPR", float3(20.0f, 10.0f, 0.0f));defineParam(roundness, "BoxRound", 0.08f);defineParam(usePlane, "UsePlane", 1);defineParam(planeY, "PlaneY", 0.0f);defineParam(planeColor, "PlaneColor", float3(0.45f,0.46f,0.48f));defineParam(baseColor, "BaseColor", float3(0.85f,0.78f,0.65f));defineParam(lightDir, "LightDir", float3(0.6f,0.7f,0.4f));defineParam(lightCol, "LightColor", float3(1.0f,0.98f,0.95f));defineParam(ambientCol, "Ambient", float3(0.07f,0.08f,0.09f));defineParam(roughness, "Roughness", 0.30f);defineParam(specGain, "SpecGain", 0.7f);defineParam(aoGain, "AOGain", 0.55f);defineParam(shadowHard, "ShadowHard", 1.0f);defineParam(outputMode, "OutputMode", 0);defineParam(maxDepth, "MaxDepth", 6.0f);defineParam(time, "Time", 0.0f);}// ---------- math helpers ----------float3 normalizeSafe(float3 v){ float L=length(v); return (L>0.0f)? v/L : float3(0.0f); }float3 rotateY(float3 p,float a){ float c=cos(a),s=sin(a); return float3(c*p.x + s*p.z, p.y, -s*p.x + c*p.z); }float3 rotateX(float3 p,float a){ float c=cos(a),s=sin(a); return float3(p.x, c*p.y - s*p.z, s*p.y + c*p.z); }float3 rotateZ(float3 p,float a){ float c=cos(a),s=sin(a); return float3(c*p.x - s*p.y, s*p.x + c*p.y, p.z); }// SDF primitivesfloat sdSphere(float3 p, float r){ return length(p) - r; }float sdBox(float3 p, float3 b, float r){ // rounded boxfloat3 q = float3(fabs(p.x),fabs(p.y),fabs(p.z)) - b + float3(r,r,r);float3 m = float3(max(q.x,0.0f), max(q.y,0.0f), max(q.z,0.0f));float outside = length(m) - r;float inside = min(max(q.x, max(q.y,q.z)), 0.0f);return outside + inside;}float sdTorus(float3 p, float2 t){ // t.x=major, t.y=minorfloat2 q = float2(length(float2(p.x,p.z)) - t.x, p.y);return length(q) - t.y;}float sdCappedCylinder(float3 p, float h, float r){float2 d = float2(length(float2(p.x,p.z)) - r, fabs(p.y) - h);float outside = length(float2(max(d.x,0.0f), max(d.y,0.0f)));float inside = min(max(d.x,d.y),0.0f);return outside + inside;}// Scene SDFfloat mapScene(float3 p){// transform into object space for primitivefloat yaw=rotYPR.x*0.01745329252f, pitch=rotYPR.y*0.01745329252f, roll=rotYPR.z*0.01745329252f;float3 po = p - primPos;po = rotateY(rotateX(rotateZ(po, -roll), -pitch), -yaw);float d = 1e9f;if (primType==0){ // Sphered = sdSphere(po, primSize.x);} else if (primType==1){ // Box (rounded)d = sdBox(po, primSize, roundness);} else if (primType==2){ // Torusd = sdTorus(po, float2(primSize.x, primSize.y)); // x=major, y=minor} else { // Cylinder (capped)d = sdCappedCylinder(po, primSize.y, primSize.x); // x=radius, y=half-height}if (usePlane!=0){// infinite plane at y=planeYfloat dp = p.y - planeY;d = min(d, dp); // union with plane}return d;}float3 calcNormal(float3 p){float e=0.0015f;float3 ex=float3(e,0,0), ey=float3(0,e,0), ez=float3(0,0,e);float nx = mapScene(p+ex) - mapScene(p-ex);float ny = mapScene(p+ey) - mapScene(p-ey);float nz = mapScene(p+ez) - mapScene(p-ez);return normalizeSafe(float3(nx,ny,nz));}float ambientOcclusion(float3 p, float3 n){float occ=0.0f, sca=1.0f;for (int i=1;i<=5;i++){float hr = 0.03f*(float)i;float dd = mapScene(p + n*hr);occ += (hr - dd) * sca;sca *= 0.6f;}float ao = 1.0f - aoGain*occ;if(ao<0.0f) ao=0.0f; if(ao>1.0f) ao=1.0f;return ao;}float hardShadow(float3 ro, float3 rd){float t=0.02f;for (int i=0;i<72;i++){float3 pos = ro + rd*t;float h = mapScene(pos);if(h < 0.0012f) return 0.0f;t += max(0.01f, h*0.9f) * shadowHard;if(t > 8.0f) break;}return 1.0f;}void process(int2 ip){// camera rayfloat2 uv = float2((float)ip.x,(float)ip.y);float2 ndc = float2((uv.x/res.x - 0.5f)*(res.x/res.y), (0.5f - uv.y/res.y));float vfov = fov * 0.01745329252f;float3 fwd = normalizeSafe(camTarget - camPos);float3 right = normalizeSafe(cross(fwd, camUp));float3 upv = normalizeSafe(cross(right, fwd));float3 rd = normalizeSafe(fwd + right*ndc.x*tan(vfov*0.5f)*2.0f + upv*ndc.y*tan(vfov*0.5f)*2.0f);float3 ro = camPos;// raymarchfloat t=0.0f; bool hit=false; float d=0.0f;for (int i=0;i<160;i++){float3 pos = ro + rd*t;d = mapScene(pos);if (d < 0.0012f){ hit=true; break; }t += clamp(d, 0.002f, 0.08f);if (t > maxDepth) break;}float3 col=float3(0.0f);float alpha=0.0f;if (hit){float3 pos = ro + rd*t;float3 nrm = calcNormal(pos);// beauty / shadingfloat3 L = normalizeSafe(lightDir);float3 V = normalizeSafe(-rd);float ndotl = clamp(dot(nrm, L), 0.0f, 1.0f);float3 H = normalizeSafe(L + V);float ndoth = clamp(dot(nrm, H), 0.0f, 1.0f);float specExp = max(2.0f, 1.0f / max(0.02f, roughness));float spec = pow(ndoth, specExp) * specGain;float ao = ambientOcclusion(pos, nrm);float sh = hardShadow(pos + nrm*0.002f, L);// pick color by surface (primitive vs plane)float3 surfCol = baseColor;if (usePlane!=0){// if our hit is the plane, tweak color (simple test)// sample 1 step below point: if distance small -> on planefloat onPlane = (fabs((pos.y - planeY)) < 0.0025f) ? 1.0f : 0.0f;surfCol = (onPlane>0.5f) ? planeColor : baseColor;}float3 beauty = ambientCol*ao + surfCol*(ndotl*sh)*lightCol + spec*lightCol;if (outputMode==0){col = beauty;// Fresnel rim for freefloat fres = pow(1.0f - clamp(dot(nrm,V),0.0f,1.0f), 5.0f);col += surfCol * (0.05f * fres);} else if (outputMode==1){col = nrm * 0.5f + 0.5f; // normals 0..1} else if (outputMode==2){float z = t / maxDepth; if(z<0.0f) z=0.0f; if(z>1.0f) z=1.0f;col = float3(z,z,z);} else {col = float3(1.0f,1.0f,1.0f); // mask}alpha = 1.0f;}SampleType(dst) o(0.0f);o[0]=col.x; o[1]=col.y; o[2]=col.z; o[3]=alpha;dst() = o;}};
B