The full map function (without providing all the function definitions is like):
// DATA DRIVEN MAP FUNCTION
param mapColor(vec3 p) {
sShaderData shaderData;
// Initialise re[0] // STILL NEED param as colours blend!! So format index as a result is wrong!
shaderData.re[0].r = param(vec4(1.0,0.0,0.0,1.0), 0.0, 1e5); // color, groupID, dist
shaderData.re[0].e = vec3(0.0, 0.0, 0.0); // E# value for shape
// calculate all joints! In relation to p.
for (int i=0;i<shaderData.numJoints;i++) {
int i2=2*i;
shaderData.joints[i].position = opRotate(p-transform[i2].xyz, transform[i2+1]); // J# in prev code
// transform[i2].w i.e position.w hold Joint Worley Factor.
if (transform[i2].w!=0.0) {
// calculate joint worley in relation to p if necessary
shaderData.joints[i].worley = worley(p, transform[i2].w);
}
}
vec4 size=vec4(0.0,0.0,0.0,0.0); //w is perimiter
// process shapes
for (int j=0; j<shaderData.numShapes; j++) {
// what do we get?
int sJ = j; // this is just in case the shader get far enough ahead in parallel that it is doing another loop
sShapeData s = shaderData.shapes[sJ];
shaderData.re[sJ].e = shaderData.joints[s.jointID].position;
// evaluate positioning! With parent joint.
// if shape position away from joint
if ((s.flags&1)==0) shaderData.re[sJ].e = shaderData.re[sJ].e - s.position;
// if shape rotation (check flags)
if ((s.flags&2)==0) shaderData.re[sJ].e = opRotate(shaderData.re[sJ].e, s.rotation);
// store position before distortions
vec3 orgP=shaderData.re[sJ].e;
// apply shape distortions if applicable
if (s.distType>0) {
vec3 v = s.distParams;
switch (s.distType) {
case 1: //opPushX
shaderData.re[sJ].e = opPushX(shaderData.re[sJ].e,v.x); break;
case 2: //opPushY
shaderData.re[sJ].e = opPushY(shaderData.re[sJ].e,v.x); break;
case 3: //opPushZ
shaderData.re[sJ].e = opPushZ(shaderData.re[sJ].e,v.x); break;
case 4: //opElongateX
size.xyz = vec3(v.x,0.0,0.0);
shaderData.re[sJ].e = opElongateX(shaderData.re[sJ].e,v.x); break;
case 5: //opElongateY
size.xyz = vec3(0.0,v.x,0.0);
shaderData.re[sJ].e = opElongateY(shaderData.re[sJ].e,v.x); break;
case 6: //opElongateZ
size.xyz = vec3(0.0,0.0,v.x);
shaderData.re[sJ].e = opElongateZ(shaderData.re[sJ].e,v.x); break;
case 7: //opElongateXY
size.xyz = vec3(v.xy,0.0);
shaderData.re[sJ].e = opElongateXY(shaderData.re[sJ].e,size.xyz); break;
case 8: //opElongateXZ
size.xyz = vec3(v.x,0.0,v.y);
shaderData.re[sJ].e = opElongateXZ(shaderData.re[sJ].e,size.xyz); break;
case 9: //opElongateYZ
size.xyz = vec3(0.0,v.xy);
shaderData.re[sJ].e = opElongateYZ(shaderData.re[sJ].e,size.xyz); break;
case 10: //opElongateXYZ
size.xyz = v.xyz;
shaderData.re[sJ].e = opElongate(shaderData.re[sJ].e,size.xyz); break;
case 11: //opTwistX
shaderData.re[sJ].e = opTwistX(shaderData.re[sJ].e,v.x); break;
case 12: //opTwistY
shaderData.re[sJ].e = opTwistY(shaderData.re[sJ].e,v.x); break;
case 13: //opTwistZ
shaderData.re[sJ].e = opTwistZ(shaderData.re[sJ].e,v.x); break;
case 14: //opRound?
break;
}
}
// evaluate shape
vec4 w = s.sdfParams; //assignment causes copy to be made is accessing copy quicker than via full path object?
float r;
switch (s.sdfType) {
case 0: // roundedConeAtoB for skeleton. Capsule AtoB not included as only in tool shaders!
r = sdConeAtoB(shaderData.re[sJ].e, shaderData.joints[int(w.x)].position, shaderData.joints[int(w.y)].position, w.x, w.y);
break;
case 1: r = sdSphere(shaderData.re[sJ].e, w.x); break;
case 2: r = sdBox(shaderData.re[sJ].e, w.xyz); break;
case 3: r = sdEllipsoid(shaderData.re[sJ].e, w.xyz); break;
case 4: r = sdCone(shaderData.re[sJ].e, w.x, w.y, w.z, w.w); break;
case 5: r = sdPlane(shaderData.re[sJ].e,w.xyz); break;
case 6: r = sdCapsule(shaderData.re[sJ].e, w.x, w.y, w.z); break;
case 7: r = sdPyramid(shaderData.re[sJ].e, w.x, w.y); break;
case 8: r = sdSteele(shaderData.re[sJ].e, w.x, w.y); break;
case 9: r = sdRhombus(shaderData.re[sJ].e, w.x, w.y, w.z, w.w); break;
case 10: r = sdBoundingBox(shaderData.re[sJ].e,w.xyz,w.w); break;
case 11: r = sdTorus(shaderData.re[sJ].e,w.xy); break;
case 12: r = sdLink(shaderData.re[sJ].e,w.x,w.y,w.z); break;
case 13: r = sdHexPrism(shaderData.re[sJ].e,w.xy); break;
case 14: r = sdCylinder(shaderData.re[sJ].e,w.x,w.y); break;
case 15: r = sdCappedTorus(shaderData.re[sJ].e,w.xy,w.z,w.w); break;
case 16: r = sdConeCapped(shaderData.re[sJ].e,w.x,w.y,w.z); break;
case 17: r = sdSolidAngle(shaderData.re[sJ].e,w.x,w.y); break;
case 18: r = sdTriPrism(shaderData.re[sJ].e,w.xy); break;
case 19: r = sdRoundedCylinder(shaderData.re[sJ].e,w.x,w.y,w.z); break;
case 20: r = sdRoundBox(shaderData.re[sJ].e,w.xyz,w.w); break;
case 21: r = sdRoundCone(shaderData.re[sJ].e, w.x, w.y, w.z, w.w); break;
case 22: vec3 p0 = shaderData.joints[int(w.x)].position; vec3 p1 = shaderData.joints[int(w.y)].position;
vec3 p2 = shaderData.joints[int(w.z)].position; r = sdTriangle(p, p0, p1, p2 ); break;
case 23: r = sdDodecahedron(shaderData.re[sJ].e, w.x); break;
case 24: r = sdIsohedron(shaderData.re[sJ].e, w.x); break;
}
// store param data for shape
shaderData.re[sJ].r.d = r;
shaderData.re[sJ].r.group = 0.0;
shaderData.re[sJ].r.color = shaderData.formats[s.formatID].color;
// apply surface displacement if applicable (inc textures)
if (shaderData.formats[s.formatID].forType==2) {
shaderData.re[sJ].r.d -= sdDisplacementWorley(shaderData.joints[s.jointID].worley,
shaderData.formats[s.formatID].forData.x, shaderData.formats[s.formatID].forData.y,
shaderData.formats[s.formatID].forStyle);
} else {
if (shaderData.formats[s.formatID].forType==3) {
//texturing use vec3 size (contains elongation), p as orgPos.
//only calculate perimiter and add shape dimensions if needed.
if (shaderData.formats[s.formatID].texID > 0.0) {
if (shaderData.re[sJ].r.d < 0.25) { // check against a minimum distance? Add this to data passed in?
switch (shaderData.formats[s.formatID].forStyle) {
case 0:
vec3 n = abs(normalize(orgP));
float bA = tex3D(orgP, shaderData.formats[s.formatID].forData.xy, n, shaderData.formats[s.formatID].texID).x;
shaderData.re[sJ].r.d -= (bA-1.0)*shaderData.formats[s.formatID].forData.z;
}
}
}
}
}
}
// process combines
for (int k=0;k<shaderData.numShapes;k++) {
sCombineData c = shaderData.combines[k];
float p0=c.combParams.x;
float p1=c.combParams.y;
switch (c.combType) {
case 0: shaderData.re[c.rOut].r = opUnion(shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 1: shaderData.re[c.rOut].r = opIntersect(shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 2: shaderData.re[c.rOut].r = opSubtract(shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 3: shaderData.re[c.rOut].r = opSmoothUnion(p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 4: shaderData.re[c.rOut].r = opSmoothIntersect(p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 5: shaderData.re[c.rOut].r = opSmoothSubtract(p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 6: shaderData.re[c.rOut].r = opUnionChamfer(p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 7: shaderData.re[c.rOut].r = opIntersectChamfer(p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 8: shaderData.re[c.rOut].r = opSubtractChamfer(p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 9: shaderData.re[c.rOut].r = opUnionColumns(vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 10: shaderData.re[c.rOut].r = opIntersectColumns(vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 11: shaderData.re[c.rOut].r = opSubtractColumns(vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 12: shaderData.re[c.rOut].r = opUnionStairs(vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 13: shaderData.re[c.rOut].r = opIntersectStairs(vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 14: shaderData.re[c.rOut].r = opSubtractStairs(vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 20: shaderData.re[c.rOut].r = copUnion(c.group,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 21: shaderData.re[c.rOut].r = copIntersect(c.group,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 22: shaderData.re[c.rOut].r = copSubtract(c.group,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 23: shaderData.re[c.rOut].r = copSmoothUnion(c.group,p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 24: shaderData.re[c.rOut].r = copSmoothIntersect(c.group,p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 25: shaderData.re[c.rOut].r = copSmoothSubtract(c.group,p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 26: shaderData.re[c.rOut].r = copUnionChamfer(c.group,p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 27: shaderData.re[c.rOut].r = copIntersectChamfer(c.group,p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 28: shaderData.re[c.rOut].r = copSubtractChamfer(c.group,p0,shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 29: shaderData.re[c.rOut].r = copUnionColumns(c.group,vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 30: shaderData.re[c.rOut].r = copIntersectColumns(c.group,vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 31: shaderData.re[c.rOut].r = copSubtractColumns(c.group,vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 32: shaderData.re[c.rOut].r = copUnionStairs(c.group,vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 33: shaderData.re[c.rOut].r = copIntersectStairs(c.group,vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
case 34: shaderData.re[c.rOut].r = copSubtractStairs(c.group,vec2(p0,p1),shaderData.re[c.rOut].r,shaderData.re[c.rIn].r); break;
}
}
return shaderData.re[0].r;
}
And unfortunately many of the SDF functions are not small especially when texturing is included. Hence trying to prevent the unrolling. It is frustrating because I know graphics cards these days can do this. They need to given the huge data expansion with buffers and the like. But when I get told unrolling is forced it does not tell me why so very difficult to find the source that triggers it.