Hey, so I’ve tried your new code but am basically getting the same result as I was while trying to add more transforms myself…the transforms get loaded into the proper channel but the VrayMeshGeom object renders with no motion blur. It’s worth noting I’m doing this in Vray 3.60.04…has something changed since then?
Attached is an image showing the result I get. I placed a moving sphere to the right of my VrayMeshGeom object so you can see moblur is enabled. I also placed a plane behind everything to show that the VrayMeshGeom edges are crisp…no blur at all. I double checked the code and the 2nd transform offset for each VrayMeshGeom sphere is not equal to the first, so they should definitely be moving…but yet, no blur. Any ideas? I get the same result regardless of whether or not “animated” is checked in the VrayMeshGeom parameters.
There was some maximum value for the movement in getRandomSphere - what if just for the test you make it much bigger ?
Yea, I tried making that much bigger (default is 10, I set to 5000)…still no motion blur. I set breakpoints after center/center1 are assigned to the TraceTransforms and the values are quite spread out…but no blur is computed. Are you seeing the blur on your end?
This is what I got - but with V-Ray Next:
I’m still looking through the 3.6 code to see if there is any difference that might be causing the difference.
Actually I tried it with the 3.6 branch - it is also working the same in there ?
Hmmm…it’s possible that while I was tweaking things trying to get motion blur working before you posted your latest .zip file, I broken something somewhere else in the project. I will reset everything from scratch and see if I maybe that’s what the issue is.
Edit: so the only difference between a fresh VrayMeshGeom sample project and the code you sent, is that using my version of the SDK, the “mesh.setRayServer” function requires a RayServerInterface2 pointer, whereas in your code you were passing a RayServerInterface pointer. Same goes for the MeshTest init function, which I changed to RayServerInterface2 because that’s what gets returned by a call to vray->getSequenceData().rayserver, thus a RayServerInterface2 pointer is what gets passed in vraymeshgeom.cpp line 555. Other than that, everything is the same and I still get no moblur. I guess I’ll keep poking around in the meantime.
Ah, it’s working now! I had forgotten to check “animated” in the VrayMeshGeom rollout in this latest round of tests. I had done that previously with no luck, so I guess a combination of reverting the whole project + turning that on finally fixed things.
Thanks again for all your help Yavor, fingers crossed that this was the last bit of help I needed before being able to roll out all these new changes into my plugin 
The RayServerInterface2 ↔ RayServerInterface difference is expected - in V-Ray Next we merged RayServerInterface2 to first one.
I’m attaching the changed files as I have them in the 3.6 branch - the original ones were from the V-Ray Next branch:
Actually I tried with the 3.6 branch as it is nowadays. You said you are using 3.60.04 and the current one is past 3.60.05. The changes should be minimal but just in case - can you try with a stable nightly V-Ray 3.6 version ?
vraymeshgeom_36.zip (11.9 KB)
Aa nice to hear that it is working now. If there’s anything else - do write back 
So I’ve changed the code a bit (now my instances inherit from ShadeData instead of DefaultShadeData) and override getUVWderivs and getUVWbases functions using the code for triangle meshes found here:
https://forums.chaosgroup.com/forum/…nd-getuvwbases
I multiply the result of getUVWderivs by 0.05 and that gives me roughly the UVW filter blurring I’d expect. I don’t really like having that magic multiplication value in there but it’s a workaround for now.
Sorry about that - when I added the instancing code I forgot about setIntersectionData. The code there gets the object to world transformation from the StaticMeshInterfacePrimitive like this:
const VR::Transform &tm=VR::Transform(((VR::StaticMeshInterfacePrimitive*) mesh->owner)->tm);
instead the code should be something like this:
const VR::Transform &tm=mesh->tms.objectToWorld;
and for the motion blurred case something like this:
const VR::Transform &tm0=mesh->tms.objectToWorldT0;
const VR::Transform &tm1=mesh->tms.objectToWorldT1;
The StaticMeshVoxelPrimitive::tms/MovingMeshVoxelPrimitive::tms is the right place for transforms especially when having instanced voxels.
Thank you, worked like a charm!
By the way…did a render test with my new instance implementation vs my old one.
Scene: 10 million instances of a piece of geometry with 4k triangles. (40 billion triangles total)
Old implementation: 48 minutes, 60 gigs of RAM.
New implementation: 90 seconds, 30 gigs of RAM.
So it’s 60 times faster and uses half the RAM (and since a decent chunk of RAM is used by me to manage the data used to generate the instances, I could probably optimize my storage objects a bit and get that lower).
Safe to say, it was well worth the work required to get this all working!
Generally you can skip the VERT_NORMAL_CHANNEL at all - you’ll get the geometric normal of each triangle calculated automatically.
Alternatively if you have face normals calculated you can specify the same index in the 3 integers of FaceTopoData and you will get no averaging.
When I don’t specify vertex normals (or when I specify 3 identical normals indices per face) the mesh is faceted, and not smoothed based on the smoothing groups I assign to faces. When I do specify normals, I get smoothing, but just from the normals (like in the previous image I attached), not from the assigned smoothing groups. Are face smoothing groups ignored?
So it seems like the attributes I’m setting in the FACE_INFO_CHANNEL are being ignored. Is this the proper way to initialize it?
VR::MeshChannel &faceInfoChan = mesh.channels[mesh.numChannels++];
faceInfoChan.init(sizeof(VR::FaceInfoData), numFaces, FACE_INFO_CHANNEL, 0, MF_INFO_CHANNEL);
VR::FaceInfoData *infoData = (VR::FaceInfoData*) faceInfoChan.data;
Sorry for the delayed reply.
The mesh voxel primitives that you are using are not doing any calculations related to smoothing the normals - they just use the normals you specify(or the geometry normal). The smoothGroups member of FaceInfoData is only used as a data storage for that info - for example when exporting mesh to proxy from Max we store the smoothing groups Max provides in there and if you then want to convert the proxy back to mesh we restore the smoothing group information.
So in short - it’s up to you to calculate the smoothed normals and to supply them in the voxel channels.
There is a helper function in our SDK that can calculated smoothed normals based on the angle between normals. It is located in the smooth_normals.h header.
Ah…gotcha…didn’t realize the smoothing group values were purely for importing/exporting.
I define everything manually now (vert norms = averaged norms of adjacent faces that share smoothing groups) and am getting identical results to max’s built in smoothing group method. So, yay 
Good 
Probably we should add some comments about the smoothing groups (I also had to do a little digging to find out that they are only used for import/export).
Hey so I’m back again with another question regarding instances…
I’m having issues with motion blur. Namely, I can’t figure out the proper way to calculate the motion-blur-dependent transforms of my instances.
Currently what I’m doing is:
I call getMoblurInterval to get the start/end tick of the motion blur interval. Then I query my particles at those times, and use the transforms of the particles at those times as the tm0 and tm1 of my instances (stored in the TMS_CHANNEL). However, for moblur durations less than 1, this results in incorrect motion blur.
After closely examining the results of my tests, by measuring the exact distances that particles travel across the subframe range over the blur interval and comparing the value to what is rendered, it seems that the calculations for the transforms for the TMS_CHANNEL of the instance voxel should actually be:
tm0 = location of instance at moblur interval start tick
tm1 = location of instance at (moblur interval start tick + GetTicksPerFrame() * perTickVelocity)
In other words, the second transform should be spaced apart from the first transform by the per-frame velocity value of the instance (and is therefore moblur duration independent), rather than the location of the instance in space at the moblur interval end tick.
Is that correct?
That should generally work the way you are doing it. One thing that comes to mind - do you have changes in the topology of meshes in the motion blur interval (f.e changing number of faces/vertices) ?
We do something like this for regular meshes:
int numMeshes=vray->getSequenceData().params.moblur.geomSamples;
double frameStart, frameEnd;
VRenderInstance::getMoblurInterval(vray, frameStart, frameEnd);
TimeValue instanceTime;
float relativeTime; // Relative time which maps [0.0; 1.0] to the camera (global) mo-blur interval.
for (int i=0; i<numMeshes; i++) {
if (i==0) {
instanceTime=(TimeValue) frameStart;
relativeTime=0.0f;
}
else if (i==numMeshes-1) {
instanceTime=(TimeValue) frameEnd;
relativeTime=1.0f;
}
else {
float k=float(i)/float(numMeshes-1);
instanceTime=(TimeValue) (frameStart*(1.0f-k)+frameEnd*k);
relativeTime=(float) ((double(instanceTime)-frameStart)/(frameEnd-frameStart));
}
Matrix3 transform=node->GetObjTMAfterWSM(instanceTime);
...
}
Some of the calculations here are done in double to get correct results.