How to switch from normal mode to smooth mode?

Hi.
Here is minimal code:

function Modal(props: { stlBuffer: ArrayBuffer }) {
  const vtkContext = useRef<any>({});
  const vtkContainerRef = useRef(null);

  useEffect(() => {
    const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ rootContainer: vtkContainerRef.current });
    const renderer = fullScreenRenderer.getRenderer();
    const renderWindow = fullScreenRenderer.getRenderWindow();
    const actor = vtkActor.newInstance();
    const mapper = vtkMapper.newInstance({ scalarVisibility: false });
    const smoothFilter = vtkWindowedSincPolyDataFilter.newInstance();
    const normals = vtkPolyDataNormals.newInstance();
    actor.setMapper(mapper);
    renderer.addActor(actor);

    const stlReader = vtkSTLReader.newInstance();
    stlReader.setRemoveDuplicateVertices(1);
    stlReader.parseAsArrayBuffer(props.stlBuffer);
    const originalPolyData = stlReader.getOutputData()

    vtkContext.current = { originalPolyData, fullScreenRenderer, renderer, renderWindow, actor, mapper, smoothFilter, normals };
  }, []);

  function makeNormalMode() {
    const { mapper, renderWindow, renderer, originalPolyData } = vtkContext.current;
    mapper.setInputData(originalPolyData);
    renderer.resetCamera();
    renderWindow.render();
  }

  function makeSmoothMode() {
    const { smoothFilter, normals, mapper, renderWindow, renderer, originalPolyData } = vtkContext.current;
    smoothFilter.setInputData(originalPolyData);
    normals.setInputData(smoothFilter.getOutputData());
    mapper.setInputData(normals.getOutputData());
    renderer.resetCamera();
    renderWindow.render();
  }

  return (
    <div>
      <Button onClick={makeNormalMode}>normal mode</Button>
      <Button onClick={makeSmoothMode}>smooth mode</Button>
      <div className="relative"><div ref={vtkContainerRef} className="relative h-[400px]"</div>
      </div>
    </div>
  );
}

i clicked on “normal mode” button:

then clicked on “smooth mode” button and there is some issue:

But if i click on “smooth mode” button first it works good:

How to switch properly between them?
Thanks

If you call setInputData() that means you must update() filters manually.

It is preferable to use setInputConnection() instead.

Here is updated code:

function StlModal2(props: { stlBuffer: ArrayBuffer }) {
  const vtkContext = useRef<any>({});
  const vtkContainerRef = useRef(null);

  useEffect(() => {
    const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ rootContainer: vtkContainerRef.current });
    const renderer = fullScreenRenderer.getRenderer();
    const renderWindow = fullScreenRenderer.getRenderWindow();
    const actor = vtkActor.newInstance();
    const mapper = vtkMapper.newInstance({ scalarVisibility: false });
    const smoothFilter = vtkWindowedSincPolyDataFilter.newInstance();
    const normals = vtkPolyDataNormals.newInstance();
    actor.setMapper(mapper);
    renderer.addActor(actor);

    const stlReader = vtkSTLReader.newInstance();
    stlReader.setRemoveDuplicateVertices(1);
    stlReader.parseAsArrayBuffer(props.stlBuffer);
    const originalPolyData = stlReader.getOutputPort()

    vtkContext.current = { originalPolyData, fullScreenRenderer, renderer, renderWindow, actor, mapper, smoothFilter, normals };
  }, []);

  function makeNormalMode() {
    const { mapper, renderWindow, renderer, originalPolyData } = vtkContext.current;
    mapper.setInputConnection(originalPolyData);
    renderer.resetCamera();
    renderWindow.render();
  }

  function makeSmoothMode() {
    const { smoothFilter, normals, mapper, renderWindow, renderer, originalPolyData } = vtkContext.current;
    smoothFilter.setInputConnection(originalPolyData);
    normals.setInputConnection(smoothFilter.getOutputPort());
    mapper.setInputConnection(normals.getOutputPort());
    normals.update() 

    renderer.resetCamera();
    renderWindow.render();
  }

  return (
    <div>
      <Button onClick={makeNormalMode}>normal mode</Button>
      <Button onClick={makeSmoothMode}>smooth mode</Button>
      <div className="relative">
        <div ref={vtkContainerRef} className="relative h-[400px]"></div>
      </div>
    </div>
  );
}

i’ve used setInputConnection everywhere and it did not help. The only thing that changed is that when switching to smooth mode it gets laggy (normals.update() from your previous answer has no effect for some reason )

the following is incorrect:
mapper.setInputConnection(originalPolyData);

You can only do:
mapper.setInputConnection(reader.getOutputPort());
or
mapper.setInputData(originalPolyData);

You can’t use a polydata in place of an output port.

originalPolyData is getOutputPort, i just forgot to rename it in my code.

const originalPolyData = stlReader.getOutputPort()

Or i misunderstood you?

My bad, I did not read carefully.
Not sure why it is laggy…

Can you share your code ?

I open the component above like this:

 <DropdownMenuItem
              onClick={async e => {
                const stlRequest = await fetch(`http://localhost:3004/pacs/get-stl/regular`, {
                  method: 'POST',
                  body: OhifDicomSegblob,
                });
                const stlBlob = await stlRequest.blob();
                const arrayBuffer = await stlBlob.arrayBuffer();

                uiModalService.show({
                  content: Modal,
                  contentProps: { stlBuffer: arrayBuffer },
                });
              }}
            >
              STL
            </DropdownMenuItem>

Thats it. Just get some stl blob, convert to array buffer and show modal. Should i share something else?
Being laggy is not the main problem. It would be great to have solution to issue of rendering when switching

I meant code without React nor Ohif. Something in 100% VTK.js (with CodeSandBox for example).

Here is full index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://unpkg.com/vtk.js"></script>
</head>

<body>
    <div>
        <section>
            <label for="stlFile">Select STL File:</label>
            <input type="file" id="stlFile" accept=".stl">
        </section>

        <section>
            <button id="normalModeBtn">Normal Mode</button>
            <button id="smoothModeBtn">Smooth Mode</button>
        </section>

        <div id="vtkContainer" style="width: 500px; height: 400px; position: relative;"></div>
    </div>

    <script>
        let originalPortData = null;
        let fullScreenRenderer = null;
        let renderer = null;
        let renderWindow = null;
        let actor = null;
        let mapper = null;
        let smoothFilter = null;
        let normals = null;
        let stlReader = null;
        let interactor = null;

        const fileInput = document.getElementById('stlFile');
        const normalModeBtn = document.getElementById('normalModeBtn');
        const smoothModeBtn = document.getElementById('smoothModeBtn');
        const vtkContainer = document.getElementById('vtkContainer');

        fullScreenRenderer = vtk.Rendering.Misc.vtkFullScreenRenderWindow.newInstance({
            rootContainer: vtkContainer,
        });

        renderer = fullScreenRenderer.getRenderer();
        renderWindow = fullScreenRenderer.getRenderWindow();
        interactor = renderWindow.getInteractor();

        actor = vtk.Rendering.Core.vtkActor.newInstance();
        mapper = vtk.Rendering.Core.vtkMapper.newInstance({ scalarVisibility: false });
        smoothFilter = vtk.Filters.General.vtkWindowedSincPolyDataFilter.newInstance();
        normals = vtk.Filters.Core.vtkPolyDataNormals.newInstance();

        actor.setMapper(mapper);
        renderer.addActor(actor);

        stlReader = vtk.IO.Geometry.vtkSTLReader.newInstance();
        stlReader.setRemoveDuplicateVertices(1);

        fileInput.addEventListener('change', (event) => {
            const file = event.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = function (e) {
                const fileBuffer = e.target.result;
                stlReader.parseAsArrayBuffer(fileBuffer);
                originalPortData = stlReader.getOutputPort();
            };
            reader.readAsArrayBuffer(file);
        });

        function makeNormalMode() {
            if (!originalPortData) return;
            mapper.setInputConnection(originalPortData);
            renderer.resetCamera();
            renderWindow.render();
        }

        function makeSmoothMode() {
            if (!originalPortData) return;
            smoothFilter.setInputConnection(originalPortData);
            normals.setInputConnection(smoothFilter.getOutputPort());
            mapper.setInputConnection(normals.getOutputPort());
            renderer.resetCamera();
            renderWindow.render();
        }

        normalModeBtn.addEventListener('click', makeNormalMode);
        smoothModeBtn.addEventListener('click', makeSmoothMode);
    </script>
</body>

</html>

also, here is STL for testing - https://drive.google.com/file/d/1wbOWwy2U4FiHTY9HlLP8YC0OIQQJSZOx/view?usp=sharing

I fixed the slowness (due to infinite pipeline execution)

Regarding the rendering glitch, it seems to be an issue from the WebGL rendering.
The vtkMapper does not seem to support changing the “input”.
It works fine when visualizing your application in WebGPU though (add ?viewAPI=WebGPU in your url).

One quick solution is to use a different mapper when you change your mode.

FYI @sankhesh