The walls are oriented in such a way, that their local Z axis points outwards. Then I measure the angle between the Z axis of a wall and the Z axis of the camera – if the angle is less than 90 ° then the wall is visible. Of course, instead of calculating the angle, it is faster to calculate the dot product and check the sign.
The hard version is implemented as:
wall.getWorldDirection( v );
camera.getWorldDirection( u );
wall.visible = v.dot(u) > 0;
while the soft version is:
wall.getWorldDirection( v );
camera.getWorldDirection( u );
wall.material.opacity = 2*v.dot(u);
Here is the code: https://codepen.io/boytchev/pen/xxMZzJx
Toggle lines 131/132 to switch between hard and soft versions.