Skip to content

fix: render mirrored block reference fills (DoubleSide)#206

Open
pauloricardoma wants to merge 1 commit intomainfrom
fix/issue-183-mirrored-block-fills
Open

fix: render mirrored block reference fills (DoubleSide)#206
pauloricardoma wants to merge 1 commit intomainfrom
fix/issue-183-mirrored-block-fills

Conversation

@pauloricardoma
Copy link
Copy Markdown
Collaborator

Summary

  • Block references (INSERTs) with negative scale factors (e.g. Scale X = -1, mirror) were invisible because the negative-determinant transform flips
    triangle winding order, and THREE.js default FrontSide culling discards back-facing geometry.
  • Applies side: THREE.DoubleSide to both MeshBasicMaterial (solid fills) and ShaderMaterial (hatch patterns) in the three-renderer.

Partial fix for #183.

Test plan

  • Open arquivo-test-defpoints.dwg (AC1015/R_2000 architectural DWG)
  • Verify all 4 red cube INSERTs (PISO TATIL ALERTA) render — including the 2 with Scale X = -1
  • Verify other mirrored INSERTs with negative Scale Z also render

…ences

Block references (INSERTs) with negative scale factors (mirrored) were
invisible because the transform matrix flips triangle winding order.
THREE.js default FrontSide culling then discards the back-facing geometry.

Applies DoubleSide to both MeshBasicMaterial (solid fills) and
ShaderMaterial (hatch patterns). Fixes #183 (partial).
@pauloricardoma pauloricardoma self-assigned this Apr 10, 2026
@pauloricardoma pauloricardoma added the fix A direct fix for a known issue or regression. label Apr 10, 2026
@mlightcad
Copy link
Copy Markdown
Owner

@pauloricardoma I sent one invitation to you on adding you as collaborator of libredwg-web so that it is more convienent for you to fix issue.

@mlightcad
Copy link
Copy Markdown
Owner

mlightcad commented Apr 11, 2026

@pauloricardoma By the way, it takes a long time to parse one large dwg file. Issue #127 also reported it. I guess that the current implementation of javascript api has some performance issues. It takes too much time on convert C++ data to javascirpt data.

So I am thinking adding one function to convert dwg to dxf in libredwg-web and then use dxf-json to parse dxf file and convert it to realdwg data model. Maybe it is faster and has less bugs.

@mlightcad
Copy link
Copy Markdown
Owner

mlightcad commented Apr 11, 2026

Summary

  • Block references (INSERTs) with negative scale factors (e.g. Scale X = -1, mirror) were invisible because the negative-determinant transform flips
    triangle winding order, and THREE.js default FrontSide culling discards back-facing geometry.
  • Applies side: THREE.DoubleSide to both MeshBasicMaterial (solid fills) and ShaderMaterial (hatch patterns) in the three-renderer.

Partial fix for #183.

Test plan

  • Open arquivo-test-defpoints.dwg (AC1015/R_2000 architectural DWG)
  • Verify all 4 red cube INSERTs (PISO TATIL ALERTA) render — including the 2 with Scale X = -1
  • Verify other mirrored INSERTs with negative Scale Z also render

@pauloricardoma Are there any better ways to handle it. I remember I removed it on purpose to improve performance. Moreover, if it is really needed, it looks like the similar changes are needed in mtext-renderer too.

@pauloricardoma
Copy link
Copy Markdown
Collaborator Author

@pauloricardoma By the way, it takes a long time to parse one large dwg file. Issue #127 also reported it. I guess that the current implementation of javascript api has some performance issues. It takes too much time on convert C++ data to javascirpt data.

So I am thinking adding one function to convert dwg to dxf in libredwg-web and then use dxf-json to parse dxf file and convert it to realdwg data model. Maybe it is faster and has less bugs.

@mlightcad About the DWG→DXF idea: it makes a lot of sense for reducing the C++↔JS marshalling cost. One question before diving in: could this path have any silent data loss? Thinking about things like dynamic blocks, some proprietary object types, or anything that DXF doesn't represent 1:1 compared to DWG — is the round-trip reliable in all cases, or are there scenarios where some information would be lost?

A related thought: would it make sense to keep both approaches side-by-side, behind a flag/option chosen when loading the file? That way, depending on file size and fidelity needs, the user could pick the right path — performance (via DXF) or completeness (via the current path). Just a question, curious to hear what you think.

@mlightcad
Copy link
Copy Markdown
Owner

@pauloricardoma By the way, it takes a long time to parse one large dwg file. Issue #127 also reported it. I guess that the current implementation of javascript api has some performance issues. It takes too much time on convert C++ data to javascirpt data.
So I am thinking adding one function to convert dwg to dxf in libredwg-web and then use dxf-json to parse dxf file and convert it to realdwg data model. Maybe it is faster and has less bugs.

@mlightcad About the DWG→DXF idea: it makes a lot of sense for reducing the C++↔JS marshalling cost. One question before diving in: could this path have any silent data loss? Thinking about things like dynamic blocks, some proprietary object types, or anything that DXF doesn't represent 1:1 compared to DWG — is the round-trip reliable in all cases, or are there scenarios where some information would be lost?

A related thought: would it make sense to keep both approaches side-by-side, behind a flag/option chosen when loading the file? That way, depending on file size and fidelity needs, the user could pick the right path — performance (via DXF) or completeness (via the current path). Just a question, curious to hear what you think.

Based on my understanding on AutoCAD, there is no data loss if it is one standard AutoCAD dwg file without custom entities. If there are some custom entities implemented by other companies, it will results in data loss. However, libredwg can't read data in custom entities too.

The real issue is that dxf-json doesn't support all types of AutoCAD entities and object yet. We need to enhance dxf-json.

You suggestions are correct. I am going to create another converter in realdwg-web. One converter isn't use only if it is registered. So users can select which converter to use.

@pauloricardoma
Copy link
Copy Markdown
Collaborator Author

Summary

  • Block references (INSERTs) with negative scale factors (e.g. Scale X = -1, mirror) were invisible because the negative-determinant transform flips
    triangle winding order, and THREE.js default FrontSide culling discards back-facing geometry.
  • Applies side: THREE.DoubleSide to both MeshBasicMaterial (solid fills) and ShaderMaterial (hatch patterns) in the three-renderer.

Partial fix for #183.

Test plan

  • Open arquivo-test-defpoints.dwg (AC1015/R_2000 architectural DWG)
  • Verify all 4 red cube INSERTs (PISO TATIL ALERTA) render — including the 2 with Scale X = -1
  • Verify other mirrored INSERTs with negative Scale Z also render

@pauloricardoma Are there any better ways to handle it. I remember I removed it on purpose to improve performance. Moreover, if it is really needed, it looks like the similar changes are needed in mtext-renderer too.

Thanks for the feedback, @mlightcad — you're right, DoubleSide pays fillrate on every frame for every geometry, even when most INSERTs aren't mirrored. I undid a real optimization without realizing it.

I'd like to propose an alternative:

Pre-flip the triangle index order at batch construction time, only for instances with a negative-determinant transform matrix. So:

  • Normal instances keep FrontSide + culling enabled (zero extra cost)
  • Mirrored instances get their indices reversed during merge, and also keep FrontSide + culling enabled
  • Cost paid once at construction, not per frame; fillrate doesn't increase in any case

In practice this probably means grouping mirrored instances into a separate sub-batch (to avoid sacrificing merging for normal instances).

About mtext-renderer: I confirmed it uses MeshBasicMaterial with default FrontSide (in defaultStyleManager.ts), so the same class of bug exists there. Since mtext-renderer doesn't batch (one mesh per MTEXT), the flip could happen at the point where the mesh receives its parent block's transform — on the
cad-viewer/three-renderer side, I believe, not inside mtext-renderer itself.

Before I dig into implementation, do you agree with this direction, or do you have another approach in mind? If you agree, I can convert this PR into that (or close and open a new one, whichever you prefer), and mtext-renderer would be a separate PR in that repo afterwards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix A direct fix for a known issue or regression.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants