Name Mismatch Error

I’ve got some hacked together code for mocap FBX rigs, and I just can’t seem to find the source of this error… This Code works totally fine in TouchDesigner build 2022.31030 and BEFORE… but seems to be broken in the later build versions of TD?

Vertex Shader Compile Results:

Compiled Successfully

=============
Pixel Shader Compile Results:

Compiled Successfully

=============
Shader Link Results:
ERROR: Linking vertex and fragment stages: Member names and types must match:
    Block: _Geometry
        vertex stage: " vec4 Color"
        fragment stage: " vec4 Cd"

But for the life of me I cannot seem to find the discrepancy between Cd and Color variables in these shaders? To me it looks consistent, and I’m using Cd in the _Geometry block in both stages… I’ve looked at the _Geometry block several times but maybe someone can help me spot the error in these shader code?

Vertex

#define DEG_TO_RAD 0.0174533


struct Geometry {
	vec3 P;
	vec3 localP;
	vec3 N;
	vec3 localN;
	vec2 uv;
	vec4 Cd;
	int cameraIndex;
	
};

float saturate(in float value) {
	return clamp(value, 0.0, 1.0);
}

float rand(vec2 co){
	return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float map(float value, float inMin, float inMax, float outMin, float outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

vec2 map(vec2 value, vec2 inMin, vec2 inMax, vec2 outMin, vec2 outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

vec3 map(vec3 value, vec3 inMin, vec3 inMax, vec3 outMin, vec3 outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

vec4 map(vec4 value, vec4 inMin, vec4 inMax, vec4 outMin, vec4 outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

///////////////////////////////////////////////////////////////////////////////

mat4 make_scale(vec3 S)
{
	mat4 m = mat4(1);
	m[0][0] = S.x;
	m[1][1] = S.y;
	m[2][2] = S.z;
	return m;
}

mat4 make_rotationXYZ(vec3 Rxyz)
{
	mat4 m = mat4(1);
	vec3 r = Rxyz * -vec3(DEG_TO_RAD);

	float cx = cos(r.x);
	float cy = cos(r.y);
	float cz = cos(r.z);
	
	float sx = sin(r.x);
	float sy = sin(r.y);
	float sz = sin(r.z);

	m[0] = vec4(cy * cz, 
		-cy * sz, 
		sy, 0);
	m[1] = vec4(cz * sx * sy + cx * sz, 
		cx * cz - sx * sy * sz, 
		-cy * sx, 0);
	m[2] = vec4(-cx * cz * sy + sx * sz,
		cz * sx + cx * sy * sz, 
		cx * cy, 0);
	m[3] = vec4(0, 0, 0, 1);

	return m;
}

mat4 make_translate(vec3 T)
{
	mat4 m = mat4(1);
	m[3] = vec4(T, 1);
	return m;
}

mat4 make_transformSRT(vec3 T, vec3 Rxyz, vec3 S)
{
	return make_translate(T) * make_rotationXYZ(Rxyz) * make_scale(S);
}

///////////////////////////////////////////////////////////////////////////////

float sRGB_to_linear(float v) {
	return pow(v, 2.2);
}

vec3 sRGB_to_linear(vec3 v) {
	return pow(v, vec3(2.2));
}

vec4 sRGB_to_linear(vec4 v) {
	return pow(v, vec4(2.2));
}

///////////////////////////////////////////////////////////////////////////////

vec3 blend_normal(vec3 n1, vec3 n2, float mix) {
	float m = (mix - 0.5) * 2;
	return normalize(
		vec3(n1.xy * clamp(1 - m, 0, 1)
			+ n2.xy * clamp(1 + m, 0, 1),
			 n1.z * n2.z)
	);
}

vec3 blend_normal(vec3 n1, vec3 n2) {
	return blend_normal(n1, n2, 0.5);
}

///////////////////////////////////////////////////////////////////////////////

vec4 sampler_projection_uv(sampler2D tex, vec2 uv) {
	return texture(tex, uv);
}

vec4 sampler_projection_box(sampler2D tex, vec3 P, vec3 N, float blend_feather, float box_scale) {
	vec3 blend = vec3(0);
	blend.x = abs(dot(vec3(1, 0, 0), N));
	blend.y = abs(dot(vec3(0, 1, 0), N));
	blend.z = abs(dot(vec3(0, 0, 1), N));

	float a = blend_feather;
	float eps = 1e-6;

	float m = max(max(blend.x, blend.y), blend.z);
	blend.x = smoothstep(a + eps, 0, (m - blend.x));
	blend.y = smoothstep(a + eps, 0, (m - blend.y));
	blend.z = smoothstep(a + eps, 0, (m - blend.z));
	// blend = normalize(blend);

	vec4 color = vec4(0, 0, 0, 1);

	P *= box_scale;
	P = P - 0.5;

	color = mix(color, texture(tex, P.yz), blend.x);
	color = mix(color, texture(tex, P.zx), blend.y);
	color = mix(color, texture(tex, P.xy), blend.z);

	return color;
}

vec4 sampler_projection_box_normal(sampler2D tex, vec3 P, vec3 N, float blend_feather, float box_scale) {
	vec3 blend = vec3(0);
	blend.x = abs(dot(vec3(1, 0, 0), N));
	blend.y = abs(dot(vec3(0, 1, 0), N));
	blend.z = abs(dot(vec3(0, 0, 1), N));

	float a = blend_feather;
	float eps = 1e-6;

	float m = max(max(blend.x, blend.y), blend.z);
	blend.x = smoothstep(a + eps, 0, (m - blend.x));
	blend.y = smoothstep(a + eps, 0, (m - blend.y));
	blend.z = smoothstep(a + eps, 0, (m - blend.z));
	// blend = normalize(blend);

	P *= box_scale;
	P = P - 0.5;

	vec3 uvw = vec3(0, 0, 1);

	uvw = blend_normal(uvw, texture(tex, P.yz).xyz - vec3(0.5, 0.5, 0), blend.x);
	uvw = blend_normal(uvw, texture(tex, P.zx).xyz - vec3(0.5, 0.5, 0), blend.y);
	uvw = blend_normal(uvw, texture(tex, P.xy).xyz - vec3(0.5, 0.5, 0), blend.z);
	
	uvw += vec3(0.5, 0.5, 0);
	return vec4(uvw, 1);
}

///////////////////////////////////////////////////////////////////////////////

float fresnel(vec3 N, vec3 V, float strength){
	float border = 1.0 - (abs(dot(-normalize(V), normalize(N))));
	return clamp(border * (1.0 + strength) - strength, 0.0, 1.0);
}

float fresnel(Geometry geom, float strength){
	TDMatrix M = uTDMats[int(geom.cameraIndex)];
	vec3 V = normalize(M.camInverse[3].xyz - geom.P);
	return fresnel(V, geom.N, strength);
}

#ifdef PIXEL_SHADER

vec3 flatNormal(vec3 vPosition){
	vec3 dx = dFdy(vPosition.xyz);    
	vec3 dy = dFdx(vPosition.xyz);
	
	vec3 n = normalize(cross(normalize(dx), normalize(dy)));
	if(gl_FrontFacing == true)
		n = normalize(cross(normalize(dy), normalize(dx)));
		
	return n;
}

#endif

#define VERTEX_SHADER

out _Geometry {
	vec3 P;
	vec3 localP;
	vec3 N;
	vec3 localN;
	vec2 uv;
	vec4 Cd;
	flat int cameraIndex;
	
	flat uint instanceTextureIndex;
	
	flat int instanceID;

} oGeom;


// global uniforms
uniform sampler2D uBaseColorTex;
uniform float uDeformFrame;

uniform sampler2D uDeformTex_B;
uniform vec2 uDeformCacheTexel_B;

uniform sampler2D uDeformTex_A;
uniform vec2 uDeformCacheTexel_A;


uniform sampler2D uEmissionTex;
uniform sampler2D uNormalMap;
//uniform sampler2D uParamsTex;

uniform vec3 uPreTranslate;
uniform float uPreScale;

// mocap animation textures
uniform float uMocapAw;
uniform float uMocapBw;

uniform samplerBuffer InstanceWeight; // sets which mocap clip plays

// blendshape deform data
uniform float uTexWidth;
uniform sampler2D uBlendDeform;
uniform sampler2D uBlendDeform1;
uniform sampler2D uBlendDeform2;

in float PointNum;

#define MAX_JOINTS 4
in vec4 pCapt[4];



mat4 getBoneMatrix(int index, float pct)
{
	
	mat4 mocapA = mat4(
		texture(uDeformTex_A, vec2(pct, (index * 4. + 0.5)*uDeformCacheTexel_A.y)),
		texture(uDeformTex_A, vec2(pct, (index * 4. + 1.5)*uDeformCacheTexel_A.y)),
		texture(uDeformTex_A, vec2(pct, (index * 4. + 2.5)*uDeformCacheTexel_A.y)),
		texture(uDeformTex_A, vec2(pct, (index * 4. + 3.5)*uDeformCacheTexel_A.y))
	);
	
	mat4 mocapB = mat4(
		texture(uDeformTex_B, vec2(pct, (index * 4. + 0.5)*uDeformCacheTexel_B.y)),
		texture(uDeformTex_B, vec2(pct, (index * 4. + 1.5)*uDeformCacheTexel_B.y)),
		texture(uDeformTex_B, vec2(pct, (index * 4. + 2.5)*uDeformCacheTexel_B.y)),
		texture(uDeformTex_B, vec2(pct, (index * 4. + 3.5)*uDeformCacheTexel_B.y))
	);
	
	// randomize weights 
	//float weight = rand(gl_InstanceID);
	//TDInstanceID()
	//float weight = rand(vec2(TDInstanceID(),1.));
	
	float weight = texelFetch(InstanceWeight, TDInstanceID()).x;
	
	//mat4 mocapOut = (mocapA* uMocapAw) + (mocapB * uMocapBw);
	mat4 mocapOut = (mocapA* weight) + (mocapB * (1-weight));
	
	return mocapOut;
}



vec4 SkinnedDeform(vec4 pos, float frame)
{
	vec4 newp = vec4(0.0, 0.0, 0.0, 1.0);
	int index;
	
#if MAX_JOINTS > 0
	if (pCapt[0].x >= 0.0)
	{
		index = int(pCapt[0].x);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[0].y;
	}
	else
	{
		return pos;
	}
#endif

#if MAX_JOINTS > 1
	if (pCapt[0].z >= 0.0)
	{
		index = int(pCapt[0].z);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[0].w;
	}
#endif

#if MAX_JOINTS > 2
	if (pCapt[1].x >= 0.0)
	{
		index = int(pCapt[1].x);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[1].y;
	}
#endif

#if MAX_JOINTS > 3
	if (pCapt[1].z >= 0.0)
	{
		index = int(pCapt[1].z);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[1].w;
	}
#endif

#if MAX_JOINTS > 4
	if (pCapt[2].x >= 0.0)
	{
		index = int(pCapt[2].x);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[2].y;
	}
#endif

#if MAX_JOINTS > 5
	if (pCapt[2].z >= 0.0)
	{
		index = int(pCapt[2].z);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[2].w;
	}
#endif

#if MAX_JOINTS > 6
	if (pCapt[3].x >= 0.0)
	{
		index = int(pCapt[3].x);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[3].y;
	}
#endif

#if MAX_JOINTS > 7
	if (pCapt[3].z >= 0.0)
	{
		index = int(pCapt[3].z);
		newp += (getBoneMatrix(index, frame) * pos) * pCapt[3].w;
	}
#endif

	newp.w = 1.0;
	return newp;
}

// <<<
// >>> codeblock: `vertex_tangetnt_define` /project1/Boids/Principal2/NormalMap/TangentAttribute/CodeBlock1

in vec4 T;
out mat3 vTM;
vec4 vT = T;
// <<<


void main() 
{
	
	Geometry geom;
	geom.P = P;
	geom.localP = P;
	geom.N = N;
	geom.localN = N;
	geom.uv = uv[0].xy;
	geom.Cd = TDInstanceColor(Cd);
	geom.cameraIndex = TDCameraIndex();
	

	
	// custon attributes
	
	
	// vertex update local space
	{
		{
			// >>> codeblock: 
			
			// sets a random frame index per instance
			float F = uDeformFrame + rand(vec2(gl_InstanceID*.0344326234,1.));
			//float F = uDeformFrame;
				
			
			
			
			
			
			
			// blendshape logic 
			float tindex = TDInstanceTextureIndex();  // index starts at 0 -gets the texture instance index
			
						
			// man texture logic
			// read in blend iteration texture
			float PointIndex = gl_InstanceID;
			
			// condition to switch to find the man instances - based on texture instance index
			float manblend = 0;
			if (tindex > 8){
				manblend = 1;
			}
						
			// man deform texture
			float vertexX = (PointNum+0.5) / uTexWidth;
			vec4 blendpos = texture(uBlendDeform2, vec2(vertexX,0.5)); // man deform
			geom.P += blendpos.xyz * manblend;
			
			
			
			
			
			
			// large person
			// calculate random percentage of all instances
			float blendlarge = round(rand(vec2(gl_InstanceID*.0344326234,1.))-0.15); // 35 % large people
			
			// large person deform tex
			float vertexX2 = (PointNum+0.5) / uTexWidth;
			vec4 blendpos2 = texture(uBlendDeform, vec2(vertexX2,0.5));  // blend large person deform
			geom.P += blendpos2.xyz * blendlarge;
			
				
			
			
			
			// Taper leg logic
			float blendtaper = 0;
			if (tindex == 5 || tindex == 7 || tindex == 10 || tindex == 11){
				blendtaper = 1;
			}
			
			float blendvariance = round(rand(vec2(gl_InstanceID*.034,2.)));
			
			// taper leg deform tex
			float vertexX3 = (PointNum+0.5) / uTexWidth;
			vec4 blendpos3 = texture(uBlendDeform1, vec2(vertexX3,0.5));  // taper leg deform
			geom.P += blendpos3.xyz * clamp(blendtaper+blendvariance,0,1);
					

						
			
			
			// fetch mocap deformation			
			geom.P = SkinnedDeform(vec4(geom.P, 1), F).xyz;
			geom.N = SkinnedDeform(vec4(geom.N, 0), F).xyz;


			// <<<
		}

	}

	// local to world vertex update
	{
	
		geom.P += uPreTranslate;
		geom.P *= uPreScale;
		
		geom.P = TDDeform(geom.P).xyz;
			
		geom.N = normalize(TDDeformNorm(geom.N));
	}
	
	// vertex update world space
	{
		{
			// >>> codeblock: `vertex_tangetnt_update` /project1/Boids/Principal2/NormalMap/TangentAttribute/CodeBlock2

			vTM = TDCreateTBNMatrix(geom.N, normalize(TDDeformNorm(vT.xyz)), vT.w);
			// <<<
		}

	}

	gl_Position = TDWorldToProj(geom.P.xyz);


	// bw added to get the id
	//oGeom.instanceID = TDinstanceID(); // this didn't work 
	oGeom.instanceID = gl_InstanceID; // this passes the instance ID to the pixel shader

	oGeom.cameraIndex = geom.cameraIndex;
	oGeom.P = geom.P;
	oGeom.localP = geom.localP;
	oGeom.N = geom.N;
	oGeom.localN = geom.localN;
	oGeom.uv = geom.uv;
	oGeom.Cd = geom.Cd;
	
	// added for instance texture data BW
	oGeom.instanceTextureIndex = TDInstanceTextureIndex();	
}



Pixel

#define DEG_TO_RAD 0.0174533


struct Geometry {
	vec3 P;
	vec3 localP;
	vec3 N;
	vec3 localN;
	vec2 uv;
	vec4 Cd;
	int cameraIndex;
	
};

float saturate(in float value) {
	return clamp(value, 0.0, 1.0);
}

float rand(vec2 co){
	return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float map(float value, float inMin, float inMax, float outMin, float outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

vec2 map(vec2 value, vec2 inMin, vec2 inMax, vec2 outMin, vec2 outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

vec3 map(vec3 value, vec3 inMin, vec3 inMax, vec3 outMin, vec3 outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

vec4 map(vec4 value, vec4 inMin, vec4 inMax, vec4 outMin, vec4 outMax) {
	return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

///////////////////////////////////////////////////////////////////////////////

mat4 make_scale(vec3 S)
{
	mat4 m = mat4(1);
	m[0][0] = S.x;
	m[1][1] = S.y;
	m[2][2] = S.z;
	return m;
}

mat4 make_rotationXYZ(vec3 Rxyz)
{
	mat4 m = mat4(1);
	vec3 r = Rxyz * -vec3(DEG_TO_RAD);

	float cx = cos(r.x);
	float cy = cos(r.y);
	float cz = cos(r.z);
	
	float sx = sin(r.x);
	float sy = sin(r.y);
	float sz = sin(r.z);

	m[0] = vec4(cy * cz, 
		-cy * sz, 
		sy, 0);
	m[1] = vec4(cz * sx * sy + cx * sz, 
		cx * cz - sx * sy * sz, 
		-cy * sx, 0);
	m[2] = vec4(-cx * cz * sy + sx * sz,
		cz * sx + cx * sy * sz, 
		cx * cy, 0);
	m[3] = vec4(0, 0, 0, 1);

	return m;
}

mat4 make_translate(vec3 T)
{
	mat4 m = mat4(1);
	m[3] = vec4(T, 1);
	return m;
}

mat4 make_transformSRT(vec3 T, vec3 Rxyz, vec3 S)
{
	return make_translate(T) * make_rotationXYZ(Rxyz) * make_scale(S);
}

///////////////////////////////////////////////////////////////////////////////

float sRGB_to_linear(float v) {
	return pow(v, 2.2);
}

vec3 sRGB_to_linear(vec3 v) {
	return pow(v, vec3(2.2));
}

vec4 sRGB_to_linear(vec4 v) {
	return pow(v, vec4(2.2));
}

///////////////////////////////////////////////////////////////////////////////

vec3 blend_normal(vec3 n1, vec3 n2, float mix) {
	float m = (mix - 0.5) * 2;
	return normalize(
		vec3(n1.xy * clamp(1 - m, 0, 1)
			+ n2.xy * clamp(1 + m, 0, 1),
			 n1.z * n2.z)
	);
}

vec3 blend_normal(vec3 n1, vec3 n2) {
	return blend_normal(n1, n2, 0.5);
}

///////////////////////////////////////////////////////////////////////////////

vec4 sampler_projection_uv(sampler2D tex, vec2 uv) {
	return texture(tex, uv);
}

vec4 sampler_projection_box(sampler2D tex, vec3 P, vec3 N, float blend_feather, float box_scale) {
	vec3 blend = vec3(0);
	blend.x = abs(dot(vec3(1, 0, 0), N));
	blend.y = abs(dot(vec3(0, 1, 0), N));
	blend.z = abs(dot(vec3(0, 0, 1), N));

	float a = blend_feather;
	float eps = 1e-6;

	float m = max(max(blend.x, blend.y), blend.z);
	blend.x = smoothstep(a + eps, 0, (m - blend.x));
	blend.y = smoothstep(a + eps, 0, (m - blend.y));
	blend.z = smoothstep(a + eps, 0, (m - blend.z));
	// blend = normalize(blend);

	vec4 color = vec4(0, 0, 0, 1);

	P *= box_scale;
	P = P - 0.5;

	color = mix(color, texture(tex, P.yz), blend.x);
	color = mix(color, texture(tex, P.zx), blend.y);
	color = mix(color, texture(tex, P.xy), blend.z);

	return color;
}

vec4 sampler_projection_box_normal(sampler2D tex, vec3 P, vec3 N, float blend_feather, float box_scale) {
	vec3 blend = vec3(0);
	blend.x = abs(dot(vec3(1, 0, 0), N));
	blend.y = abs(dot(vec3(0, 1, 0), N));
	blend.z = abs(dot(vec3(0, 0, 1), N));

	float a = blend_feather;
	float eps = 1e-6;

	float m = max(max(blend.x, blend.y), blend.z);
	blend.x = smoothstep(a + eps, 0, (m - blend.x));
	blend.y = smoothstep(a + eps, 0, (m - blend.y));
	blend.z = smoothstep(a + eps, 0, (m - blend.z));
	// blend = normalize(blend);

	P *= box_scale;
	P = P - 0.5;

	vec3 uvw = vec3(0, 0, 1);

	uvw = blend_normal(uvw, texture(tex, P.yz).xyz - vec3(0.5, 0.5, 0), blend.x);
	uvw = blend_normal(uvw, texture(tex, P.zx).xyz - vec3(0.5, 0.5, 0), blend.y);
	uvw = blend_normal(uvw, texture(tex, P.xy).xyz - vec3(0.5, 0.5, 0), blend.z);
	
	uvw += vec3(0.5, 0.5, 0);
	return vec4(uvw, 1);
}

///////////////////////////////////////////////////////////////////////////////

float fresnel(vec3 N, vec3 V, float strength){
	float border = 1.0 - (abs(dot(-normalize(V), normalize(N))));
	return clamp(border * (1.0 + strength) - strength, 0.0, 1.0);
}

float fresnel(Geometry geom, float strength){
	TDMatrix M = uTDMats[int(geom.cameraIndex)];
	vec3 V = normalize(M.camInverse[3].xyz - geom.P);
	return fresnel(V, geom.N, strength);
}

#ifdef PIXEL_SHADER

vec3 flatNormal(vec3 vPosition){
	vec3 dx = dFdy(vPosition.xyz);    
	vec3 dy = dFdx(vPosition.xyz);
	
	vec3 n = normalize(cross(normalize(dx), normalize(dy)));
	if(gl_FrontFacing == true)
		n = normalize(cross(normalize(dy), normalize(dx)));
		
	return n;
}

#endif

////
//// from google filament https://github.com/google/filament/
////

#define PI (3.14159265358979)
#define MIN_ROUGHNESS 0.06

float D_GGX(float roughness, float NoH, const vec3 h) {
    float a = NoH * roughness;
    float k = roughness / ((1.0 - NoH * NoH) + a * a);
    float d = k * k * (1.0 / PI);
    return clamp(d, 0, 65504.0);
}

float V_SmithGGXCorrelated(float roughness, float NoV, float NoL) {
    float a2 = roughness * roughness;
    float lambdaV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2);
    float lambdaL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2);
    float v = 0.5 / (lambdaV + lambdaL);
    return clamp(v, 0, 65504.0);
}

float V_SmithGGXCorrelated_Fast(float roughness, float NoV, float NoL) {
	// Hammon 2017, "PBR Diffuse Lighting for GGX+Smith Microsurfaces"
	float v = 0.5 / mix(2.0 * NoL * NoV, NoL + NoV, roughness);
	return clamp(v, 0, 65504.0);
}

// float pow5(float x) {
//     float x2 = x * x;
//     return x2 * x2 * x;
// }

vec3 F_Schlick(const vec3 f0, float f90, float VoH) {
    // return f0 + (f90 - f0) * pow5(1.0 - VoH);
	return f0 + (f90 - f0) * pow(2.0, (-5.55473 * VoH - 6.98316) * VoH);
}

float F_Schlick(float f0, float f90, float VoH) {
    // return f0 + (f90 - f0) * pow5(1.0 - VoH);
	return f0 + (f90 - f0) * pow(2.0, (-5.55473 * VoH - 6.98316) * VoH);
}

vec3 Irradiance_SphericalHarmonics(const vec3 shCoeffs[9], const vec3 n) {
    return max(
          shCoeffs[0]
        + shCoeffs[1] * (n.y)
        + shCoeffs[2] * (n.z)
        + shCoeffs[3] * (n.x)
        + shCoeffs[4] * (n.y * n.x)
        + shCoeffs[5] * (n.y * n.z)
        + shCoeffs[6] * (3.0 * n.z * n.z - 1.0)
        + shCoeffs[7] * (n.z * n.x)
        + shCoeffs[8] * (n.x * n.x - n.y * n.y)
        , 0.0);
}

////

float distribution(float roughness, float NoH, const vec3 h) {
	return D_GGX(roughness, NoH, h);
}

float visibility(float roughness, float NoV, float NoL) {
	return V_SmithGGXCorrelated_Fast(roughness, NoV, NoL);
}

vec3 fresnel(const vec3 f0, float LoH) {
    float f90 = saturate(dot(f0, vec3(50.0 * 0.33)));
    return F_Schlick(f0, f90, LoH);
}

float diffuse(float roughness, float NoV, float NoL, float LoH) {
	return 1 / PI;
}

vec3 specular(float roughness, vec3 f0, const vec3 h,
		float NoV, float NoL, float NoH, float LoH) {
	float D = distribution(roughness, NoH, h);
	float V = visibility(roughness, NoV, NoL);
	vec3 F = fresnel(f0, LoH);
	return vec3(D * V) * F;
}

vec3 diffuseIrradiance(const vec3 shCoeffs[9], const vec3 n) {
    return Irradiance_SphericalHarmonics(shCoeffs, n);
}

////

struct PBRMaterial {
	vec3 baseColor;
	vec3 diffuseColor;
	float roughness;
	float perceptualRoughness;
	float metallic;
	float reflectance;
	vec3 emission;
	vec3 f0;
	float ao;
};

vec3 evaluateDirectLighting(int index, const vec3 P, const vec3 V, const vec3 N, const PBRMaterial material) {
	TDLight LightParams = uTDLights[index];

	if (length(LightParams.diffuse) < 1e-4)
		return vec3(0);

	vec3 lightColor = LightParams.diffuse;
	float attenuation = 1;
	vec3 lightVector;
	vec3 L;

	if (LightParams.position.xyz == LightParams.direction)
	{
		// distant light

		lightVector = -LightParams.direction.xyz;
		L = normalize(lightVector);
	}
	else
	{
		// point and cone light

		lightVector = LightParams.position.xyz - P;
		L = normalize(lightVector);

		float lightDistance = length(lightVector);

#ifdef TD_PICKING_ACTIVE
		// calc distant falloff
		{
			float lightAtten = lightDistance * LightParams.attenScaleBiasRoll.x;
			lightAtten += LightParams.attenScaleBiasRoll.y;
			lightAtten = clamp(lightAtten, 0.0, 1.0) * 1.57079633;
			lightAtten = sin(lightAtten);
			attenuation *= pow(lightAtten, LightParams.attenScaleBiasRoll.z);
		}
#endif

		// calc cone falloff
		if (LightParams.coneLookupScaleBias.x > 0.0)
		{
			float spotEffect = dot(LightParams.direction, -L);
			spotEffect = (spotEffect * LightParams.coneLookupScaleBias.x) + LightParams.coneLookupScaleBias.y;
			spotEffect = texture(sTDConeLookups[index], spotEffect).r;
			attenuation *= spotEffect;
		}
	}

	attenuation *= (1 - TDShadow(index, P));

	if (abs(attenuation) <= 1e-4)
		return vec3(0);
	
	vec3 H = normalize(L + V);
	float NoV = saturate(dot(N, V));
	float NoL = saturate(dot(N, L));
	float NoH = saturate(dot(N, H));
	float LoH = saturate(dot(L, H));

	vec3 Fd = material.diffuseColor * diffuse(material.roughness, NoV, NoL, LoH);
	vec3 Fr = specular(material.roughness, material.f0, H, NoV, NoL, NoH, LoH);
	vec3 Lo = (Fd + Fr) * lightColor * NoL * attenuation;

	return Lo;
}

vec3 evaluateIBL(int index, const vec3 P, const vec3 V, const vec3 N, const PBRMaterial material)
{
	TDEnvLight LightParams = uTDEnvLights[index];

	if (length(LightParams.color.rgb) < 1e-4)
		return vec3(0);

	float NoV = saturate(dot(N, V));
	vec3 H = normalize(N + V);
	float NoH = saturate(dot(N, H));

	vec3 lightColor = LightParams.color.rgb;
	mat3 envMapRotate = LightParams.rotate;
	vec3 R = (2.0 * dot(N, V) * N) - V;
	R = envMapRotate * R;
	R = normalize(R);
	vec2 mapCoord = TDCubeMapToEquirectangular(R);

	vec2 size = textureSize(sTDEnvLight2DMaps[index], 0);
	float mipCount = 1 + floor(log2(max(size.x, size.y)));
	float mipLevel = saturate(material.perceptualRoughness) * mipCount;
	vec3 prefilteredColor = textureLod(sTDPrefiltEnvLight2DMaps[index], mapCoord, mipLevel).rgb;
	prefilteredColor = sRGB_to_linear(prefilteredColor);

	vec2 dfg = texture(sTDBRDFLookup, vec2(NoV, material.perceptualRoughness)).xy;

	vec3 diffuse = vec3(0);

	// diffuse = diffuseIrradiance(uTDEnvLightBuffers[index].shCoeffs, R) / 1.5;

	// TODO: IBL diffuse term should be updated more
	{
		vec3 diffuseContrib = vec3(0);
		const float C1 = 0.429043;
		const float C2 = 0.511664;
		const float C3 = 0.743125;
		const float C4 = 0.886227;
		const float C5 = 0.247708;

		vec3 diffEnvMapCoord = envMapRotate * N;
		diffuseContrib += C1 * (diffEnvMapCoord.x * diffEnvMapCoord.x - diffEnvMapCoord.y * diffEnvMapCoord.y) *  uTDEnvLightBuffers[index].shCoeffs[8].rgb;
		diffuseContrib += C3 * diffEnvMapCoord.z * diffEnvMapCoord.z *  uTDEnvLightBuffers[index].shCoeffs[6].rgb;
		diffuseContrib += C4 *  uTDEnvLightBuffers[index].shCoeffs[0].rgb;
		diffuseContrib -= C5 *  uTDEnvLightBuffers[index].shCoeffs[6].rgb;
		diffuseContrib += 2.0 * C1 * (diffEnvMapCoord.x * diffEnvMapCoord.y * uTDEnvLightBuffers[index].shCoeffs[4].rgb + diffEnvMapCoord.x * diffEnvMapCoord.z * uTDEnvLightBuffers[index].shCoeffs[7].rgb + diffEnvMapCoord.y * diffEnvMapCoord.z * uTDEnvLightBuffers[index].shCoeffs[5].rgb);
		diffuseContrib += 2.0 * C2 * (diffEnvMapCoord.x *  uTDEnvLightBuffers[index].shCoeffs[3].rgb + diffEnvMapCoord.y *  uTDEnvLightBuffers[index].shCoeffs[1].rgb + diffEnvMapCoord.z * uTDEnvLightBuffers[index].shCoeffs[2].rgb);

		diffuseContrib /= 1.6;

		diffuse = diffuseContrib;
	}

	vec3 Fd = diffuse * material.diffuseColor * (1 / PI);
	vec3 Fr = (dfg.xxx * material.f0 + dfg.yyy) * prefilteredColor;
	// vec3 Fr = mix(dfg.yyy, dfg.xxx, material.f0) * prefilteredColor;
	// vec3 Fr = mix(dfg.yyy, dfg.xxx, F) * prefilteredColor;
	vec3 Lo = (Fd + Fr) * lightColor;

	return Lo;
}

vec3 evaluatePBR(const vec3 P, const vec3 V, const vec3 N, const PBRMaterial material)
{
	vec3 color = vec3(0);

	// direct lighting
	if (TD_NUM_LIGHTS > 0)
	{
		for (int i = 0; i < TD_NUM_LIGHTS; i++)
		{
			color.rgb += evaluateDirectLighting(i, P, V, N, material) * material.ao;
		}
	}

	// image based lighting
	if (TD_NUM_ENV_LIGHTS > 0)
	{
		for (int i = 0; i < TD_NUM_ENV_LIGHTS; i++)
		{
			color.rgb += evaluateIBL(i, P, V, N, material) * material.ao;
		}
	}

	return color;
}

#define PIXEL_SHADER

in _Geometry {
	vec3 P;
	vec3 localP;
	vec3 N;
	vec3 localN;
	vec2 uv;
	vec4 Cd;
	flat int cameraIndex;
	
	flat uint instanceTextureIndex;
	
	flat int instanceID;

} iGeom;

out vec4 fragColor;

// global uniforms
uniform float uRoughness;

uniform sampler2D uBaseColorTex;
uniform float uBumpScale;
uniform float uDeformFrame;
uniform sampler2D uDeformTex;
uniform sampler2D uEmissionTex;
uniform sampler2D uNormalMap;
//uniform sampler2D uParamsTex;

// masks - masks are now loaded in as 1/2 the instanced texture
//uniform sampler2D uClothingMask;
//uniform sampler2D uSkinMask;
//uniform sampler2D uHairMask;
//uniform sampler2D uPantMask;


// global define


// pixel derine
// >>> codeblock: `pixel_tangetnt_define` /project1/Boids/Principal2/NormalMap/TangentAttribute/CodeBlock4

in mat3 vTM;
// <<<


void main()
{
	Geometry geom;
	geom.P = iGeom.P;
	geom.localP = iGeom.localP;
	geom.N = iGeom.N;
	geom.localN = iGeom.localN;
	geom.uv = iGeom.uv;
	geom.Cd = iGeom.Cd;
	geom.cameraIndex = iGeom.cameraIndex;

	//geom.instanceTextureIndex = iGeom.instanceTextureIndex;

	// custon attributes
	

	TDCheckDiscard();

	// update normals
	{
		vec3 uvw = vec3(0.0, 0.0, 1);
		vec3 out_uvw = vec3(0.0, 0.0, 1);

		{
			// >>> codeblock: `` /project1/Boids/Principal2/NormalMap/CodeBlock5

			vec4 normalMap = sampler_projection_uv(uNormalMap, (mat3(make_transformSRT(vec3(0.000000, 0.000000, 0), vec3(0, 0, 0.000000), vec3(1.000000, 1.000000, 0))) * vec3(geom.uv.xy, 1)).xy);
			vec3 norm = (2.0 * (normalMap.xyz - 0.5)).xyz;

			uvw = norm;
			uvw.xy *= uBumpScale;


			// <<<
		}
		out_uvw = blend_normal(out_uvw, uvw);

		// apply tangent rotation
		out_uvw = vTM * out_uvw;
		geom.N = normalize(out_uvw);
	}

	PBRMaterial mat;
	
	// initialize material parameters
	{
		
		vec2 uv = geom.uv;
		
		// read in masks
		//float shirt_mask = texture(uClothingMask, uv).r;
		//float skin_mask = texture(uSkinMask, uv).r;
		//float hair_mask = texture(uHairMask, uv).r;
		//float pant_mask = texture(uPantMask, uv).r;
		
		
		// for color tints
		//vec3 skincol = TDInstanceCustomAttrib0(iGeom.instanceID).xyz;
		//vec3 pantcol = TDInstanceCustomAttrib1(iGeom.instanceID).xyz;
		//vec3 haircol = TDInstanceCustomAttrib2(iGeom.instanceID).xyz;
		
		
		mat.baseColor = vec3(1.);

		// apply tints
		//mat.baseColor *= geom.Cd.rgb * shirt_mask + (1-shirt_mask);
		//mat.baseColor *= skincol * skin_mask + (1-skin_mask);
		//mat.baseColor *= pantcol * pant_mask + (1-pant_mask);
		//mat.baseColor *= haircol * hair_mask + (1-hair_mask);
		//
		
		
			
		//mat.metallic = 1;
		//mat.roughness = 0.5;
		//mat.reflectance = 0.5;
		//mat.ao = 1;
		mat.emission = vec3(0);
	}

	// update PBR material parameters
	{
		{
			// >>> codeblock: `` /project1/Boids/Principal2/CodeBlock

			vec2 uv = geom.uv;
			
			// split the UV's into left and right half
			vec2 col_uv = vec2(uv.x/2,uv.y);
			vec2 mask_uv = vec2(uv.x/2+0.5,uv.y);
			// adding instance textures
			//vec4 baseColor = sRGB_to_linear(texture(uBaseColorTex, uv));
			vec4 baseColor = sRGB_to_linear(TDInstanceTexture(iGeom.instanceTextureIndex, col_uv));
			vec4 maskColor = sRGB_to_linear(TDInstanceTexture(iGeom.instanceTextureIndex, mask_uv));
			
			
			vec3 skincol = TDInstanceCustomAttrib0(iGeom.instanceID).xyz;
			vec3 pantcol = TDInstanceCustomAttrib1(iGeom.instanceID).xyz;
			vec3 haircol = TDInstanceCustomAttrib2(iGeom.instanceID).xyz;
			
			//maskColor.r = pants
			//maskColor.g = shirt
			//maskColor.b = hair
			//maskColor.a = skin
			
			
			mat.baseColor *= geom.Cd.rgb * maskColor.g + (1-maskColor.g);
			mat.baseColor *= pantcol * maskColor.r + (1-maskColor.r);
			mat.baseColor *= haircol * maskColor.b + (1-maskColor.b);
			mat.baseColor *= skincol * maskColor.a + (1-maskColor.a);
			
			
			
			mat.baseColor *= baseColor.rgb;
			
			
			geom.Cd.a *= baseColor.a;

			//vec4 param = texture(uParamsTex, uv);
			
			
			
			
			mat.metallic = 0.;
			mat.reflectance = .75;//1.;
					
			
			float hairrough = 0.4;
			float skinrough = 0.45;
			float clothrough = 0.85;
			
			float clothmask = clamp(maskColor.g + maskColor.r,0,1);
			
			//float totalrough = clothmask*clothrough;
			//float totalrough = maskColor.b*hairrough;
			//float totalrough = maskColor.a*skinrough;
			
			float totalrough = (clothmask*clothrough) + (maskColor.b*hairrough) + (maskColor.a*skinrough);
			
			//mat.roughness = uRoughness;
			mat.roughness = totalrough;
			
			mat.ao = 1;
			
			vec3 emission = sRGB_to_linear(texture(uEmissionTex, uv)).rgb;
			mat.emission += max(emission, vec3(0));
			// <<<
		}
	}

	// calclate some parameters
	{
		mat.perceptualRoughness = mat.roughness;
		mat.roughness = mat.perceptualRoughness * mat.perceptualRoughness;
		mat.roughness = clamp(mat.roughness, MIN_ROUGHNESS, 1.0);
		mat.diffuseColor = mat.baseColor.rgb * (1 - mat.metallic);

		float reflectance = clamp(mat.reflectance, 0, 2);
		reflectance = 0.16 * reflectance * reflectance;
		mat.f0 = mat.baseColor.rgb * mat.metallic + (reflectance * (1.0 - mat.metallic));
	}

	if (!TDFrontFacing(geom.P, iGeom.N))
		geom.N = -geom.N;

	TDMatrix M = uTDMats[iGeom.cameraIndex];
	vec3 V = normalize(M.camInverse[3].xyz - geom.P);

	vec4 color = vec4(0, 0, 0, 1);
	color.rgb += evaluatePBR(geom.P, V, geom.N, mat);
	color.rgb += mat.emission;
	color.a = geom.Cd.a;



	TDAlphaTest(color.a);

	color.rgb = pow(color.rgb, vec3(1/2.2));
	fragColor = TDOutputSwizzle(color);
}

This is odd. Can you post the full .toe file so I can take a look?
Malcolm

yea let me try to clean up the toe a little and I can post this… this is a maybe also a bug that David Braun mentioned potentially in the later builds of TD with regards to some GLSL MAT code, but I’ll do a little work on my end to make this more clear example of the problem if i can.

@malcolm - This toe file works perfectly fine in version 2023.31030 attached at bottom - but somewhere around build version 2023.11510 and above it breaks, in my case I am testing on 2023.12000 but I know some of the earlier versions are also busted.

In my testing I also setup a switch to between 2 versions of the GLSL text files I had the hunch maybe I would do a find and replace to either change “Cd” to “color” or vice versa… but instead I chose to change everything to the British spelling “colour” to avoid any kind of hard coded variable conflict naming.

Both version of the GLSL text files the one that uses variable name “Cd” and the one that uses “colour” will work perfectly fine in build version 2023.31030 - you can use a switch Dat to toggle between 0-1 and they both will work. (this is an important test because it will show how it will breaks in later versions)

Now if you open this same file in build 2023.12000 or later the shader will produce the name mismatch error using the switch Dat set to 0 - this is the exact original code that uses the “Cd” variable names to reproduce the name mismatch error.

Now, if you set the switch Dat to1 which uses the updated find/replace version changing “Cd” to “colour” that error message is now gone, but the shader still doesn’t’ compile correctly.

what I would theorize is that somewhere in the underlying code there is a need to use either “Cd” or “color” exactly named as such but they may be underlying mismatched in the fragment and vertex stages in the later builds? or in some update the underlying name from Cd to color changed in one stage but not the other and they have to be named as such? not really sure, maybe this detective work helps.

here is the toe file if you want to run it through your own testing. any help in the matter would be greatly appreciated.
FBX_MasterPlaback_simple_for_derivative.10.toe (979.9 KB)

@DavidBraun - Tagging David Braun cause he may be somewhat familiar with this issue ^ :pray:

There was a similar issue discussed with the Boids example when going from 2022 builds to 2023.11340. compilation error in Boids with modern TD version · Issue #8 · DBraun/TouchDesigner_Shared · GitHub I never figured it out.

You can work around this issue by using a variable named something other than Cd for your color. The problem is for prep to support POPs we renamed the color attribute from Cd to Color, and there is a #define being applied to the shader to help with that. I don’t think it’s the correct solution though so I need to find a better way to handle this.

well… I’m not entirely sure that will completely solve the issue. My test case above might have been a little obtuse but if you follow my logic.

To recap what I was testing and why, I renamed all instances of “Cd” to “colour” I used the british spelling to get around any name conflict errors with “color” because this is just a variable after all I should be able to name it “foo” I would assume? So that works in the older builds 2023.31010 So then I load the same file, in the newer builds such as 2023.12000 and it removes the mismatch name error and the shader doesn’t flag any other errors, but the shader is still not outputting correctly… that could point to some other unidentified error in the newer builds with the MAT GLSL code, but since there is no error with the renamed “colour” and yet the shader isn’t outputting correctly, I’m sort of at a loss.

Right sorry, I was focusing on the GLSL compile error, which does go away. But ya something else is happening that has changed the shaders behavior (it does compile correctly after your rename).
Looking into it more

1 Like

So the problem is that the way we put skinned deform data on the GPU is different now (prep for POPs again). We don’t fill the pCapt in attribute anymore, that data is instead stored in two different arrays which can be accessed with

int[] TDAttrib_BoneIndices(uint vertID);
float[] TDAttrib_BoneWeights(uint vertID);
1 Like

ah ok thanks for pointing that out @malcolm - that should hopefully pinpoint my error enough for a fix. I will look into those arrays and see how to replace the pCapt. very much appreciated.

In future builds the GLSL MAT will give a warning if it detects that pCapt was used. I’ve also avoided the error caused by the #define Cd Color we added to the start of all shaders to be instead vec4 Cd = Color;, which should still maintain the backwards compatibility change for us using ‘Color’ instead of ‘Cd’ in shaders now, but avoid the #define replacement that was breaking your shader. Thanks for the report and your patience.

2 Likes

@malcolm - I’m trying to replace the pCapt bone skin deform data but having an issue using those replacement TDAtrrib_BoneIndices functions. What build version of TD should I be using to get that to work? (Ideally I can get it working on build v 2023.12000)

Can you post the code snippet you’ve made, and the describe the issues you are having in more detail? Compile errors? Just nothing showing?

I’m sure this is not a TD error or bug, this is just me not knowing what I am doing… This from your help docs, and is basically the “old way” to do skinning setup with the pCapt https://derivative.ca/UserGuide/Deforming_Geometry_%28Skinning%29
specifically this:

 vec4 TDSkinnedDeform(vec4 pos)
 {
   vec4 newp = vec4(0.0, 0.0, 0.0, 1.0);
   int index;
   if (pCapt[0].x >= 0.0)
   {
       index = int(pCapt[0].x);
       newp += (TDBoneMat(index) * pos) * pCapt[0].y;
   }
   else
   {
       return pos;
   }
   if (pCapt[0].z >= 0.0)
   {
       index = int(pCapt[0].z);
       newp += (TDBoneMat(index) * pos) * pCapt[0].w;
   }
   if (pCapt[1].x >= 0.0)
   {
       index = int(pCapt[1].x);
       newp += (TDBoneMat(index) * pos) * pCapt[1].y;
   }
   if (pCapt[1].z >= 0.0)
   {
       index = int(pCapt[1].z);
       newp += (TDBoneMat(index) * pos) * pCapt[1].w;
   }
   if (pCapt[2].x >= 0.0)
   {
       index = int(pCapt[2].x);
       newp += (TDBoneMat(index) * pos) * pCapt[2].y;
   }
   if (pCapt[2].z >= 0.0)
   {
       index = int(pCapt[2].z);
       newp += (TDBoneMat(index) * pos) * pCapt[2].w;
   }
   newp.w = 1.0;
   return newp;
 }

I’m not super familiar with what this code does really I mostly just copied / pasted from examples so I’m not sure in what instances or how the pCapt would be replaced by these functions, and or if I need to do anything in the SOPs to prep?

Is there a help document or example page of how to setup deforming skin GLSL shaders with these new TDAttrib functions?

int[] TDAttrib_BoneIndices(uint vertID);
float[] TDAttrib_BoneWeights(uint vertID);

@malcolm - when I try to use those new functions I get a “no matching overloaded function”, which usually means the function was mistyped or just not called properly , or that it doesn’t exist. I suppose I’m probably not using it correctly and would be helpful to have a working example of a skin deformer using the TD_Attrib functions.

I tested this in build 2023.12000 and also 2023.31701 (POPs alpha build)

Sorry, for these custom attributes you’ll want to use the ‘Attributes’ page to declare them. Here is an updated version of the file. I’ve changed the ‘Attributes’ page of the GLSL MAT, and the shader code has been updated to remove the declaration of pCapt. Finally the deforms are now done with

vec4 ApplySingleBoneDeform(vec4 pos, int i, float frame)
{
	int ind = TDAttrib_BoneIndices()[i];
	if (ind >= 0.0)
	{
		float weight = TDAttrib_BoneWeights()[i];
		return (getBoneMatrix(ind, frame) * pos) * weight;
	}
	else
	{
		return vec4(0.0);
	}
}

vec4 SkinnedDeform(vec4 pos, float frame)
{
	vec4 newp = vec4(0.0, 0.0, 0.0, 1.0);
	int index;
	
	for (int i = 0; i < MAX_JOINTS; i++)
		newp += ApplySingleBoneDeform(pos, i, frame);

	newp.w = 1.0;
	return newp;
}

FBX_MasterPlaback_update.toe (981.1 KB)

1 Like

Wow @malcolm - you are amazing! thank you so much for this example.