I’m still working on my product configurator (Kitchen knifes) and I need some advice/tips !
Coding isn’t really a problem for me, even though I haven’t tried making my own shaders (scary stuff haha).
But 3D modelling is a whole new world for me, and I’m pretty sure I’m not going in the right direction.
I have a 3D model of a kitchen knife, with a mesh for the blade, and another for the handle. So a pretty simple 3D object! But my blade has to look metallic, show a brand logo, and should also be able to show another drawing on it (a personnalisation option, could be a picture, another logo, text, whatever…).
I tried several things in blender which seem to work :
3 uv maps, blade + logo + drawing
2 uv maps, blade + drawing, and the logo is another mesh, a plane shrinkwrapped on the blade.
But once in Playcanvas, I can’t manage to get the same result!
I can only use 2 UVs, and the result is a bit weird (the drawing has an impact on the metallic material, even though the UV for the drawing doesn’t cover the whole blade).
And the shrinkwrapped plane has lost it’s transparency.
I think you are getting close! Indeed in PlayCanvas and in general in most realtime 3D engines you have two UV coordinate sets to work with.
In your case the way I would approach that would be:
Split the knife in two nodes in Blender, one for the metallic surface and one for wooden handler. Use UV0 (first UV set) for each node to unwrap.
When importing that in PlayCanvas you will get two material slots (mesh instances) for your model, so you can assign a unique material for each surface.
For the logo you can use a detail texture, no need for a plane surface/polygons for that (you can get z fighting from a distance). You can use the UV1 channel to get the position right and then in code set the detail channel for your metal material to your logo image. It will blend correctly without affecting or getting affected by metalness. For on detail maps here:
I looked at the engraving example and it looks a bit hard for me right now, but I’m going to try the DiffuseDetailMap (Detail Diffuse Map?).
Right now I have my metal material with no main DiffuseMap, and UV1 with a decoration. So if I understand it well, I can put my logo on the blade with the DiffuseDetailMap on UV1?
I also searched for examples in other product customizers and I found this one that is interesting.
In this one, their logo blends with the decoration (leaving a border around the logo). They can rotate the texture, that makes me wonder if they first generate an image outside of their 3D engine, mixing the decoration and logo (in a html canvas perhaps?), and only then they put it as texture on their 3D model.
Is that a crazy and heavy processing idea?
I already use something like that. An user can send his own picture, I load it in a canvas, change the pixels so it becomes transparent and greyscale, and set it as a DiffuseMap. It works OK as long as you send a PNG.
Some gifs !
The exemple configurator I found
My work so far (you can try it also here but it might not work 24/24 because I regulary break everything haha, and don’t mind the mess in the code, I should will clean it up)
Some problems I need some help with :
I need to invert the Alpha. For this example I did it myself first manually on the texture.
I searched a bit and it looks like I’ll have to use a custom shader?
Also I have a glitch on the logo, that disappears if I zoom on it.
Hmm looks like to be mip map related. If I disable mip maps on the texture, the lines disappear. This does explain why it doesn’t show when you are close up to the model before
clamp mode just means that the edge pixels are used outside of the 0…1 range on the UV coordinates. If you want transparent outside, you need 1 pixel transparent border around the texture.
Unfortunately, adding a transparent border didn’t change much.
I remade my UV maps in order to avoid a maximum of zooming in, used black & white textures with a nice (white) border because I couldn’t find how to invert an alpha texture, and now the glitch appears really far away.
So now I limited the distance of the camera and I think that will do it for now haha : test_couteau - PLAYCANVAS
Also, while playing with DiffuseDetailMap, I found … DiffuseMapRotation, and now I feel stupid, this answers one of my previous questions
the DiffuseMapRotation is pretty recent thing I believe, and I suspect it wasn’t there when you asked
When you have a transparent / white or whatever you need border, and turn off mipmaps on those textures, you should not have any leaking pixels. But if you have mipmaps, the story is more complicated, as mipmaps are created by averaging pixels and your edges are no longer full transparent.
You could likely fix it up by modifying mimap data directly (if not compressed), or perhaps you could write a shader (chunk) which tests if u or v coordinate is outside of 0…1 range and simply return fully transparent pixel.
But perhaps not using mipmaps is acceptable simple solution?
Limiting distance as you currently do is tricky … as it might work on some devices, but a distance would need to be different on lower DPI devices, as mipmaps will kick in a lot sooner.
I’ll disable the mipmaps, for a product configurator the distance to the object is always more or less the same
Thanks for the help guys !
A V1 of my project should come out soon
You can do a manual rotation of the UVs, the bellow function takes in a center(Vec2) of rotation, an amount of rotation(float), the mesh(mesh) you want to translate the uvs of and the UV channel(int)
You will have to do some translation of the rotation from radians to degrees or what ever you want to use as rotator, but this should get you started on doing it manually.
RotateUv.prototype.rotateUV = function(center, rotation, mesh, channel){
uvs = [];
mesh.getUvs(channel, uvs);
for(var i = 0; i < uvs.length; i += 2){
uvs[i] -= center.x;
uvs[i+1] -= center.y;
var x = uvs[i];
var y = uvs[i+1];
uvs[i] = x * Math.cos(rotation) - y * Math.sin(rotation);
uvs[i+1] = x * Math.sin(rotation) + y * Math.cos(rotation);
uvs[i] += center.x;
uvs[i+1] += center.y;
}
mesh.setUvs(channel, uvs);
mesh.update();
};