I am trying to flip a mesh (mirror operation). For doing so if if "scale negatively" its geometry the faces are inside-outside and the mesh does not render properly.
const geom = new THREE.BoxGeometry(10,10,10);
geom.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
Instead, if I apply it directly to the mesh it works just fine:
this.mesh.scale.set(-1,1,1);
Unfortunatelly I need to apply it to the geometry
You can check the project using this at https://beta.bitbloq.cc/app/playground/3d
I fixed this changing manually faces order, maybe this could be applied directly on applyMatrix() function. If you agree I can PR
objectGeometry.applyMatrix(matrixWorld);
const ps = new THREE.Vector3();
const qs = new THREE.Quaternion();
const ss = new THREE.Vector3();
matrixWorld.decompose(ps, qs, ss);
if (ss.x * ss.y * ss.z < 0) {
objectGeometry.faces.forEach(face => {
const aux = face.a;
face.a = face.c;
face.c = aux;
});
objectGeometry.verticesNeedUpdate = true;
objectGeometry.normalsNeedUpdate = true;
(objectGeometry as THREE.Geometry).computeFaceNormals();
}
Unfortunatelly I need to apply it to the geometry
Why? Can you explain your use case a bit?
I fixed this changing manually faces order,
It's not only the winding order that needs to be fixed. UVs also have to be corrected.
If you agree I can PR
I think this use case needs to be solved on app level.
I need to use the geometry because I perform a CSG operation using the geometries, and thus, geometries vertices need to be on their final position.
As far as I understand mesh position, quaternion and scale does not affect the mesh.geometry vertices.
This is why I need to apply changes on the geometry.
It is a hacky continuation of a hack, but could you just flip Material.side whenever you flip the geometry?
AFAIK geometries do not have materials. What I really need is that geometries faces and normals are right. Currently, when a negative scale is applied, normals point to the wrong direction as faces have vertices in wrong order).
Mesh already works well flipping material (from previous comment of @Mugen87 )
Ah, of course, if you need to be able to merge the geometries... Unless you use multiple render groups and multiple materials. You would in principle need only two render groups at any time, with two corresponding materials: One unflipped and one flipped. Then, whenever you must merge geometries, you take care to join the groups that have the same flipping. Or use the solution that you proposed above.
Closing. This needs to be solved in app level. https://stackoverflow.com/a/54496265/5250847 might help in this context.
Closing. This needs to be solved in app level
I think proper support for negatively scaling a geometry is a perfectly-reasonable request.
I doubt users want to invert their geometry and have the winding order or normals inconsistent, which is what currently happens with
geometry.scale( - 1, 1, 1 );
There are two intended use cases:
We support the first incorrectly, and we do not support the later at all.
I leave this up to @mrdoob.
Fact is, user can manipulate geometry data in various ways. Often with a comprehensible reason. Not sure to cover such use cases in the library...
@mrdoob
I am thinking that geometry.scale( - 1, 1, 1 ) should not turn the geometry inside-out. Fixing that would just require flipping the winding order.
If we did that, then to create a sky sphere would require material.side = THREE.BackSide and perhaps setting texture.repeat.x to - 1. Alternatively, we could create SkyBox/SphereGeometry.
If we did that, then to create a sky sphere would require
material.side = THREE.BackSideand perhaps settingtexture.repeat.xto - 1.
I think that sounds good to me.
I am thinking that geometry.scale( - 1, 1, 1 ) should not turn the geometry inside-out.
If we did that, then to create a sky sphere would require material.side = THREE.BackSide and perhaps setting texture.repeat.x to - 1.
I think that sounds good to me.
Ugh... Works for textured spheres, but doesn't work for video textures or BoxGeometry. So forget that idea...
@mrdoob If geometry.scale( - 1, 1, 1 ) was changed so it did not turn the geometry inside-out, we will need another way to create sky boxes and sky spheres.
How would you feel about creating SkyBoxGeometry and SkySphereGeometry. If not, we would need a method BufferGeometry.invert(), but am thinking that is a bit too general for our needs.
BufferGeometry.flipX()? 馃槄
In my testbed, I created BufferGeometry.reverseWindingOrder().
But since we need it only for two specific use cases, I instead suggested creating SkyBoxGeometry and SkySphereGeometry, which can be part of the examples only.
They may be useful for the future enhancements to scene.background, though, so they could be part of the library.
Can we make it so that the winding order is reversed when the matrix passed to applyMatrix has a negative scale?
Can we make it so that the winding order is reversed when the matrix passed to applyMatrix has a negative scale?
I expect you mean negative determinant.
Be aware, you have to ensure tangents are handled correctly. It also must work for indexed and non-indexed buffer geometry, and handle any number and type of buffer geometry attributes. It should also handle all draw modes. Normal maps may be an issue. There may be other issues to consider...
We will have to decide if this is worth pursuing -- and what the API should be.
Maybe wait to see if there is more demand for it...
This would be a very important feature! Just imagine a complex model like a vehicle, where I can save tremendous file size (reducing download times) by cloning geometries. Today I do that already but it costs additional draw calls (I have to mirror the geometries by applying negative scales to the parented mesh)! If I can mirror the geometries instead I would be able to use InstancedMesh() or I can merge buffer geometries (BufferGeometryUtils.mergeBufferGeometries) to reduce draw calls! For me current the most important feature to be able to bring model complexity to the next level!
This would be a very important feature!
@Peters69 What feature/methods are you referring to, exactly?
Flipping a geometry by negative scaling = scale(-1,1,1). I was finally able to fix normals with a function I found on another discussion (changing face winding order), but I think this should better work by default for easy usage. I mirrored geometries (to optimize download size), fixed normals and merged them again to optimize draw calls.
Until now I fliped meshes containing the geometries, but at the expense of additional draw calls!
I would love to use the InstancedMesh API but if I mirror a geometry there I'm not able to fix it with the same functions (or I just don't know how). I think it would be great we can just do what was requested in this discussion, flipping geometries by using applyMatrix(new THREE.Matrix4().makeScale(-1,1,1)). Without limits (also for instances) or using any workaround fixing the normals.
I used the function "flipBufferGeometryNormals(geometry)" from shared discussion to fix normals on fliped buffer geometries. How can I do this using the InstancedMesh API?
https://stackoverflow.com/questions/16824650/three-js-how-to-flip-normals-after-negative-scale
I hope this is more exact. Let me know if you need more input.
Most helpful comment
We will have to decide if this is worth pursuing -- and what the API should be.
Maybe wait to see if there is more demand for it...