0

I am trying to get back and export the mesh that is being displaced by a displacementMap.

The shader is transforming vertexes according to this line (from three.js/src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl):

transformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );

This is displacing a vertex according to the displacementMap, mixed with the uv coordinates for that vertex.

I am trying to create this mesh/geometry so that I can then later export it.

I have created a "demo" of the problem here: Github Page I would like the displaced mesh, as seen in the viewport, up on pressing exportSTL. However I am only getting the undisplaced plane.

I understand why this happens, the displacement only happens in the shader and is not really displacing the geometry of the plane directly.

I have not found a method provided by three.js and so far have not found any way in getting the changes from the shader. So I am trying to do it with a function in the "demo.js". However, I am a WebGL/three.js newbie and have problems re-creating what the shader does.

I have found exporters handling morphTargets, but these are of no help. After reading this question I tried PlaneBufferGeometry, as this is closer to the shader - but this produces the same results for me. I think this question originally tried to produce something similar, but accepted an unrelated question.

In the end I would like to draw on a HTML-canvas which then updates the texture in real time (I have this part working). The user can then export the mesh for 3d printing.

Is there a way three.js can give me the modified geometry of the shader? Or can someone help me translate the shader line in to a "conventional" Three.js function? Maybe this is totally the wrong approach to get a displaced mesh?

Update - Example is working

Thanks to the example from DeeFisher I can now calculate the displacement in CPU, as originally suggested by imerso. If you click on the Github Page now, you will get a working example. At the moment I do not fully understand why I have to mirror the canvas to get the correct displacement in the end, but this is at worst a minor nuissance.

Deadolus
  • 372
  • 3
  • 17

2 Answers2

2

To do that while still using a shader for the displacement, you will need to switch to WebGL2 and use Transform-Feedback (Google search: WebGL2 Transform-Feedback).

An alternative would be to read the texture back to CPU, and scan it while displacing the vertices using CPU only (Google search: WebGL readPixels).

Both alternatives will require some effort, so no code sample at this time. =)

imerso
  • 511
  • 4
  • 12
  • Thank you for some pointers. I have started to look in to it, so far without success. I would like to do it in three.js, without switching to the underlying WebGL2. I am however trying to modify three.js GLSL code with your suggestions. If I manage to actually do it I hope to get it merged back at one point. – Deadolus Oct 16 '17 at 19:37
  • If you want to stay with WebGL1, there is no way to recover/save the GPU displaced vertices, so your only bet is reading back the displacement texture and displacing vertices in the CPU -- that is, you would not use GLSL for the displacement, but at least you would have the displaced vertices in CPU to export to disk. In WebGL2 you have transform-feedback, which is a way to read back the displaced vertices, so you could still use GLSL for that, then get the results using transform-feedback and finally export to disk. – imerso Oct 16 '17 at 21:50
  • Accepted as there seems to be no other way than what you suggested. Three.js dev branch has WebGL2 renderer in development, but it seems to be not ready for prime-time yet. Looking at https://ibiblio.org/e-notes/webgl/gpu/bounce.htm seems to suggest TransformFeedbacks from WebGl2 would be a good way to solve the problem. Thanks for your help anyways. – Deadolus Oct 25 '17 at 09:47
2

BABYLON.js can be used in conjunction with THREE.js and it allows you to displace the actual mesh vertices when applying displacement maps:

var sphere = BABYLON.Mesh.CreateSphere("Sphere", 64, 10, scene, true);
sphere.applyDisplacementMap(url, minHeight, maxHeight, onSuccess, uvOffset, uvScale)

See an example of the function in use here.

You can then use a for to loop transfer the BABYLON mesh data into a THREE mesh object.

DeeFisher
  • 408
  • 4
  • 9
  • 1
    I finally had time to test this. It seems the Babylon.js (or at least your example) is doing it in CPU, as imerso suggested. However: the example code helped me to implement the same functionality for THREE.js! I updated the github code and it is now working, with the STLBinaryExporter I get the correctly displaced mesh. The "normal" STLExporter does somehow not export the mesh correctly. So I want to thank you for pointing me to a very good example how to calculate the displacement in CPU. I really appreciated it! Thank you very much for this! – Deadolus Nov 02 '17 at 20:17
  • awesome @Deadolus ! Thanks very much. – DeeFisher Oct 31 '18 at 14:16