Rotating an instanced object using a GLSL shader. Possible?

ok,

I have finally had the time to start (trying) to get my head around GLSL shaders.

I was wondering if you could rotate instanced objects (individually) using a glsl shader.

I understand how to adjust position and scale (well, the technique for adjusting scale in the pushpin tox which is a bit limited) but have not come across anything referring to rotation…

I understand that I could rotate instanced objects using the instance parameters in the Geo node, but I would imaging it to be quicker for large amounts of objects using GLSL…

Thanks in advance…

I’m not sure if rotating within the shader will be faster. Instance transformations are done on the GPU also. It might be faster if your procedurally transforming though and not using CHOPs and/or DATs. Either way I think your biggest hit will be drawing pixels in the render.

If you do want to rotate in the shader though you’ll need to multiply the point by a rotation matrix.

The good news is the instance transformation is done after the shader so your don’t have to move the point to the center of the scene relative it’s instance’s centroid.

ie.mat3 rot = myRotationMatrix(rotate[gl_InstanceID]) vec3 point = rot * P;

where myRotationMatrix is a function that takes a vec3 for rotation values and creates a rotation matrix. Rotate[i] is a vec3 uniform array with a different set of rotations for each instance. I don’t think this will be faster than the native instancing transforms though but I could be wrong.

Actually just reading the wiki it turns out that a transformation matrix is calculated on the CPU and the then sent to the GPU for each instance if rotations are present, if not then just an array for translate and scale are sent. So depending where your bottleneck is, calculating the transformation matrix on the GPU might be faster…

Also if you use a 4x4 matrix you can scale, translate and scale with the single matrix

cheers
Keith

Thanks for that.

I have only had a few days to look at GLSL over the break, but I will see if I can get this working.

I am a designer, not a programmer, so it takes a lot of banging my head against the monitor to make these things work …

Thanks again,

eek. This is still beyond me. I need to get my head around rotation matrices before I can write the function.

Found this about rotation matrices if anyine is interested… open.gl/transformations

I will write it on a nail and bang it into my head when I can find a hammer…

It took me a bit to get my head around matrix transformation as well, so here’s an example to help you out. I can’t find one of the sites I used to help me learn how to make a rotation matrix by hand but I posted a couple links below. The first seems build the exact matrix I made below.

Here is the modified vertex shader of standard phong exported shader. It has a couple of transformations. First function that creates a rotation matrix is declared. Then another function that makes a 4x4 transformation matrix is declared ( that also uses the first function).

Then two variables are created each of which calls one of the matrix functions. One is a mat4 which is used to translate, scale and rotate the object. The second is mat3 which do another rotation after the first transform.

Notice the two matrices are made outside of the main() function. The matrices are only created once for the object, not for every point. If you want to use them and input different values based on point or instance id’s then they’ll need to be created within the main() function.

[code]uniform vec3 uTranslate;
uniform vec3 uScale;
uniform vec3 uRotate;
uniform vec3 uRotate2;

out Vertex {
vec4 color;
vec3 camSpaceVert;
vec3 camVector;
vec3 norm;
}vVert;

// Return rotation matrix
mat3 rotationMatrixXYZ(vec3 r)
{
float cx = cos(radians(r.x));
float sx = sin(radians(r.x));
float cy = cos(radians(r.y));
float sy = sin(radians(r.y));
float cz = cos(radians(r.z));
float sz = sin(radians(r.z));

return mat3(cy * cz, 	cx * sz + sx * sy * cz, 	sx * sz - cx * sy * cz,
			-cy * sz,	cx * cz - sx * sy * sz,		sx * cz + cx * sy * sz,
			sy,			-sx * cy,					cx * cy);				   

}

//return transformation matrix
mat4 xFormXYZ(vec3 t, vec3 sc, vec3 r)
{
mat3 scale = mat3( sc.x, 0.0, 0.0,
0.0, sc.y, 0.0,
0.0, 0.0, sc.z);

mat3 xfm = rotationMatrixXYZ(uRotate)  * scale;

return mat4(xfm[0][0], xfm[0][1], xfm[0][2], 0.0,
			xfm[1][0], xfm[1][1], xfm[1][2], 0.0,
			xfm[2][0], xfm[2][1], xfm[2][2], 0.0,
			t.x,       t.y, t.z,  1.0 );	

/* this would be valid as well
return mat4(xfm[0], 0.0,
xfm[1], 0.0,
xfm[2], 0.0,
t, 1.0 );
*/
}

mat4 xfm = xFormXYZ(uTranslate, uScale, uRotate);
mat3 rot2 = rotationMatrixXYZ(uRotate2);

void main()
{

//multilply the point by the transform matrix, it must be a vec4 because the matrix is 4x4 matrix and includes translation
vec4 point = xfm * vec4(P, 1.0);
//the normal needs to be rotated also but not translated so the w component is 0.0
vec3 normal = (xfm * vec4(N, 0.0)).xyz;

//do another rotation after first transformation - just need vec3's this time becuase the rotation matrix is 3x3
point.xyz = rot2 * point.xyz;
normal = rot2 * normal;



// First deform the vertex and normal
// TDDeform always returns values in world space
vec4 worldSpaceVert =TDDeform(point);
vec4 camSpaceVert = uTDMat.cam * worldSpaceVert;
gl_Position = TDCamToProj(camSpaceVert);

// This is here to ensure we only execute lighting etc. code
// when we need it. If picking is active we don't need this, so
// this entire block of code will be ommited from the compile.
// The TD_PICKING_ACTIVE define will be set automatically when
// picking is active.

#ifndef TD_PICKING_ACTIVE

vec3 camSpaceNorm = uTDMat.camForNormals * TDDeformNorm(normal).xyz;
vVert.norm.stp = camSpaceNorm.stp;
vVert.camSpaceVert.xyz = camSpaceVert.xyz;
vVert.color = TDInstanceColor(Cd);
vec3 camVec = -camSpaceVert.xyz;
vVert.camVector.stp = camVec.stp;

#else // TD_PICKING_ACTIVE

// This will automatically write out the nessesarily values
// for this shader to work with picking.
// See the documentation if you want to write custom values for picking.
TDWritePickingValues();

#endif // TD_PICKING_ACTIVE
}
[/code]

engineering.purdue.edu/~bethel/rot2.pdf
fastgraph.com/makegames/3drotation/

cheers
Keith
Transform matrix example.toe (7.73 KB)

1 Like

Wow. Thanks for your help. That is awesome.

I have to admit, at this stage, i find it much easier to follow an example and expand from there, rather than try to write a whole shader from scratch in order to teach myself a principle.

This will get me well under way.

I will now see what I can do with InstanceIDs.

Thanks again.

Finally got around to adjusting Keith’s .toe to work with Instanced geometry. Sure helped me, so hopefully this will help someone else… (please excuse any obvious programming faux pars, I am still learning GLSL shaders).

Way to many instances here, but I was interested in the performance of GLSL technique VS the Top to Chop method.

In order to check the speed of the GLSL version, I progressively increased the instances. I maxed out at about 1000*1000 before my machine started to drop below 60FPS (have not checked FPS in perform mode yet). If anyone wants want to change the number of instances, set the “grid” rows and columns to a lower value. This seems pretty good. Especially seeing as I can use a much higher resolution image to drive the change than I could with the Top to Chop technique. This alone may be a deciding factor for choosing this method.

If I get a chance, I will attempt to compare the two options for performance.
Transform matrix example.12.toe (9.21 KB)

I modified this a bit so the effect would be a little more obvious, and made the GLSL vertex shader a bit more clear (at least to me) and updated it to TD’s specific GLSL functions.

My only question is how can I modify this so it can translate all the instances positions entirely within the vertex shader? I want to get rid of the Grid SOP. Would I multiply the Translation Matrix in line after the Scale Matrix? So the matrices go in Rotate, Scale, Translate order. Is this where that initial mat4 matrix comes into use? I couldn’t figure out how to implement a Translation Matrix into it, so i reduced it down to a mat3.
transformMatrixMod.toe (9.94 KB)

To build a 4x4 translation matrix
opengl-tutorial.org/beginner … n-matrices

The GLSL code right now has this

vec4 worldSpacePos =TDDeform(pointPos);

Behind the scenes, inside TDDeform, TouchDesigner gets the translation from a point on the instanced SOP (in this case a grid), and applies that translation to the point.

So suppose you’ve done a texture lookup on an image, or checked an array, or used noise to build your mat4 myTranslation. I think you should use this line of code to replace the earlier one.

vec4 worldSpacePos = myTranslation*vec4(pointPos,1.);

Ya mat4 is necessary. Tim Gerritsen on slack helped me piece it together. It was more straightforward than I expected. Also that link you posted is a great resource, helped with my understanding a lot. I’m going to clean up a few things in the .toe and make it more readable and easier to play around with parameters and see what they do. I’ll post it here when I’m done, hopefully will help others understand how to do basic transforms in GLSL using sampled textures.

Ok, cleaned it up and made Perform Mode interactive. Hopefully this helps people understand and implement it into their own projects.
GLSL Instancing - Transform Matrices.toe (15 KB)

Well usefull , thx that helps a lot!