How soften hard edges

Hi,

I’m trying to soften hard edges for a model.

I am following https://stackoverflow.com/questions/35136282/how-to-smooth-mesh-triangles-in-stl-loaded-buffergeometry/39204556#39204556

Is the above methodology accepted solution correct? after making the changes in this solution I get no errors but the object renders gray.
noTexture

Debug on material does not show complete information:
console.log("Material type " + vaseMesh.material.type + " color: " + vaseMesh.material.color + " ao name: " + vaseMesh.material.aoMap.name);
"Material type MeshStandardMaterial color: [object Object] ao name: "

Can you please give me some guidance what I may be doing wrong?
Thank you for your help, Sergio

myObjectLoader.load( "Photog_Vase1/LowPoly_repos.obj", function ( group ) {
					var geometry = group.children[ 0 ].geometry;
					geometry.attributes.uv2 = geometry.attributes.uv;
					geometry.center();
					geometry.computeBoundingBox();
	                geometry.computeVertexNormals();

	                var attrib = geometry.getAttribute('position');
	                if(attrib === undefined) {
	                    throw new Error('a given BufferGeometry object must have a position attribute.');
	                }
	                var positions = attrib.array;
	                var vertices = [];
	                for(var i = 0, n = positions.length; i < n; i += 3) {
	                    var x = positions[i];
	                    var y = positions[i + 1];
	                    var z = positions[i + 2];
	                    vertices.push(new THREE.Vector3(x, y, z));
	                }
	                var faces = [];
	                for(var i = 0, n = vertices.length; i < n; i += 3) {
	                    faces.push(new THREE.Face3(i, i + 1, i + 2));
	                }

	                var geo = new THREE.Geometry();

	                geo.vertices = vertices;
	                geo.faces = faces;
	                geo.computeFaceNormals();              
	                geo.mergeVertices()
	                geo.computeVertexNormals();
	               
					vaseMesh = new THREE.Mesh(geo, material);
					vaseMesh.material=material;
					//debug for this does not show most information=> "Material type MeshStandardMaterial color: [object Object] ao name: "
					console.log("Material type " + vaseMesh.material.type + " color: " + vaseMesh.material.color + " ao name: " + vaseMesh.material.aoMap.name);

					material.normalScale.x = -1;
					vaseMesh.castShadow = true;
					vaseMesh.receiveShadow = true;
					scene.add( vaseMesh );
					console.log("Finished adding to scene");

					vaseMesh.position.set(0,0,0);

					} , onProgress,onError);
				}

You shouldn’t have to use THREE.Geometry. If you’re trying to smooth the normals of your geometry then you can use the mergeVertices function in BufferGeometryUtils (link) and then call computeVertexNormals to generate smooth normals. Here’s a rough example of what that might look like:

const mergedGeometry = THREE.BufferGeometryUtils.mergeVertices(geometry);
mergedGeometry.computeVertexNormals();
mesh.geometry = mergedGeometry;

Let me know how it goes!

Thanks for your guidance @gkjohnson !

Unfortunately the edges are still rendering very hard.

I note I had edges softened in maya (mesh display->soften edges) before import. I can’t dispute it’s not the most uniform of meshes but it’s clean and Maya’s Clean-up tool also says it’s clean.

Unity and Sketchfab don’t render edges markedly, I am trying to find what may help three.js engine render similarly.

I replaced the code with these lines as suggested:
myObjectLoader.load( “Photog_Vase1/LowPoly_repos.obj”, function ( group ) {
var geometry = group.children[ 0 ].geometry;
geometry.attributes.uv2 = geometry.attributes.uv;
geometry.center();
var geo = THREE.BufferGeometryUtils.mergeVertices(geometry);
geo.computeVertexNormals();
vaseMesh = new THREE.Mesh(geo, material);

Here’s snapshot before the smoothing normals in three.js:
hardedges_before

Here’s snapshot after smoothing normals with the above code:
hardedges_after

Here’s a snapshot of sketchfab:
sketch

Here’s Unity’s snapshot:
unitys

Thank you for your help,

Sergio

I think in three.js, for BufferGeometry its not possible to calculate smooth Normals if it dosen’t have indexed faces. You probably will have to write your own method for that, for which you need the information of adjacent faces etc.

@spidersharma
The mergeVertices function in BufferGeomtryUtils should do just that. It indexes your geometry so vertex attributes are shared and then you can calculate smooth normals.

It doesn’t sound like that’s the problem, though. If the model has smooth shading in other applications then it sounds like the geometry should already be smoothed.

@Alright I see you asked a similar question before – can you post your material creation code? Is flatShading enabled? Otherwise providing the model would be helpful.

Thanks @gkjohnson, I wasn’t aware of mergeVertices function. Yeah, I saw the code, and it should generate the indices, after which the computeVertexNormals function should produce smooth Normals.

@Alright, may be you can debug into computeVertexNormals, and see if smooth normals are produced correctly. You can test it with a very simple geometry say, like a cube or so.

Hi @gkjohnson and Three.js community,

Thank you for looking into this.

The hard edges problem in the prior post was solved by @Mugen87 by setting flatShading: false, and I set it to false in this case too, yep!

I attach below links to the files for the asset that is showing quite hard edges compared to other renders.

I hope these help to find a solution and thank you again for your help !

Cheers, Sergio

albedo: https://drive.google.com/open?id=1KEwf_tJHi4eHUYIm7Ol6h6MtZVF55iqp
normal:https://drive.google.com/open?id=149r3n9JGnb9xEJkf9Eh7ELK2bM83bJX_
ao: https://drive.google.com/open?id=15qHf1FjGCPhR9j2djn4Lm1cpjujXaAYE
roughness: https://drive.google.com/open?id=1bgyIsoGpbhlGVnvJTcASOEGni8GQRHsJ
obj:https://drive.google.com/open?id=1TDQ1rG_wKeiHsEbqc7niLH1gYHkNZQeO
mtl (i’m not using this): https://drive.google.com/open?id=1XwIApNnsa47TDkJL7h8Zi_PnV27khDXl
code (wip): https://drive.google.com/open?id=1U0SWIsurnLctEstFBjkqAQuIrdlgGnry

The normals on your model are actually already smoothed, so there’s no need to regenerate new vertex normals. What you’re seeing is an artifact of rendering cast shadows from the spotlight. You’re getting shadow acne on some of the triangles that are at a glancing angle relative to light direction which is exposing the shape of the underlying triangles.

There are some more sophisticated ways to solve this that THREE doesn’t (I don’t think?) support at the moment but you should be able to get it looking good enough by increasing the magnitude of your shadow bias:

spotLight.shadow.bias = -0.001;

image

Changing the bias to -0.001 worked well for me but you’ll have to tune it for your use cases because it will cause some other shadow artifacts if you increase it too much.

2 Likes

I hadn’t thought shadow artifacts was the reason behind, thank you so much @gkjohnson !

My guess is that three.js can’t handle normal maps. If you’re talking about the hard edges and triangulation, i bet it’s that. Three.js can only render normal maps on flat surfaces (walls floors etc).

@Alright Absolutely! Glad I could help.

@pailhead That shouldn’t be the case, right? There are quite a few examples of normal maps being used on different smooth / curved models in THREE. The important thing is that the normal map be generated with the vertex normals of the associated model in mind.

In this case the issue shows up even without normal maps and adjusting the shadow bias fixes it:

image
shadow bias -0.0001 vs -0.01

Supporting a normal bias when sampling the shadow map would be the better way to solve this but from looking at the shader code it doesn’t look like it’s supported at the moment. There’s an issue for it here if anyone wants to track support.

i think i was looking at one of the snapshots above, where even after averaging the normals there are still seams all over the place. So what happens when you apply the normal map and add it next to the last snapshot?

@pailhead The normals of the models are smoothed by default when the file is loaded so there’s no need to make changes. The image I added in my previous post shows the model with the original, unaltered smooth normals and normal map (and albedo map) so it would look like that.

That’s the bit that confused me, yeah the model comes in smooth on your load, no need to compute anything. I didn’t realize the first screenshots even have shadows.

The model is generated with photogrammetry, 1000 shots. It maybe the case that the images are aligned by reality capture paralell to the surface normals, maybe the reason for this curved geometry to have recovered with the shadow bias adjusted by @gkjohnson . Pretty satisfied with the result :smile:

I just had the same problem.
The mergeVertices function in BufferGeomtryUtils didn’t work for me either. Then I saw in the docs that it has a second argument, which fixed the problem at last:
THREE.BufferGeometryUtils.mergeVertices(geometry, 1);
You might have to play around with the second argument’s value to find the right value for your situation.