three.js: Is it possible to exempt an object from global clipping? - three.js

I have many textured meshes so they must have different materials. It seems like there are only two ways to clip: globally, and per-material.
However, I want some visualizers to not be clipped (e.g. the plane I'm manipulating to define the clip planes), but all of the rest of the meshes are to be clipped. So I want to use global clipping, but to exempt the parts of the 3D UI (specific objects) from clipping. Is this possible?

I'm fairly certain that I can address this at the application level by separating the scenes so that i can issue the render of items i need clipped by using globally clipped functionality, and then clear out the clip planes and render a second scene containing UI elements prior to clearing the renderbuffers.

Related

Is it possible to select multiple objects with box selection?

I know that with QObjectPicker I can mouse pick a single entity. But how can I select multiple objects by drawing a rectangle on the screen?
I think this is actually pretty complicated. But here are my two cents:
If you only need to be able to select unoccluded objects
(i.e. don't need to select occluded ones) you could add a second frame graph branch to your existing one and draw each object with a unique color but to an offscreen texture. Then retrieve this texture, check which colors lie within the drawn rectangle and retrieve the corresponding objects and select them (compare to this question/answer).
I'm not sure how well this works in Qt3D because I've always had some issues with QRenderCapture. It didn't seem to have an impact where I added it in the frame graph, i.e. always captured the last state so maybe even if you have multiple render targets it might capture the wrong one etc. Qt3D is still in a pretty rough state I'd say.
If you need an example of how to render to an offscreen texture check out my example on GitHub.
If you need to be able to select occluded objects too
then it gets pretty complicated. I'm just providing some ideas here. I don't know if they will work.
If you don't have that many objects maybe you could implement the idea from above for each single object. I.e. for each object you have an offscreen frame graph branch that filters out all other objects. Then you could check each rendered texture for the rectangle drawn with the mouse. But again I'm not sure how well this works with Qt3D and if you have many objects (like in a game) it will probably crash because of the many offscreen textures.
You could also implement something like "inverse" frustum culling. In frustum culling, you omit rendering objects that lie outside the view frustum of the camera. You could compute a frustum using the rectangle coordinates drawn with the mouse. Check out the QFrustumCulling code. You would need to compute the planes differently of course, using a modified view matrix. When the user draws the rectangle, compute the frustum and check all objects. Unfortunately, this also selects objects whose bounding sphere intersects with the frustum, even though you might visible not touch any part of the object. If that bothers you, you could directly select all objects whose sphere is completely within the frustum and for all objects which only partly intersect do the intersection computation on a per-triangle basis and exit computation for the current object as soon as a triangle intersects the frustum. Depending on the number of triangles this could be very costly computational-wise.
I'd definitely stick to being able to select only unoccluded objects especially because picking in OpenGL seems to be realized by drawing the ojbects with colors these days.

UI Elements not affected by light

I'm trying to make a menu screen in which all the UI elements (buttons, text...) are completely dark and by touching the screen you create a fire (or just an area light) that makes the UI elements visible.
Sort of like this
I read that the default shader for the UI elements isn't affected by light, but i can't seem to change it.
How do I go about doing this?
The UI elements by default use a unlit shader and are also rendered directly to clip space. so you'll need to do two things, first put a lit shader onto the elements, the unity standard shader should do fine, then you should change the canvas render mode to world space. with the canvas in world space you can move it around like it was a sprite. i would also recommend creating a second higher priority camera for the UI with culling turned off. with the canvas in view of the UI camera, you should be able to place a light source near it and see the resulting lighting on the UI.

Three.js performance with high number of objects

I am working on a project which needs rendering of thousands of unique meshes of building models. My objects need to be selectable and they will have their data (other than geometry) attached to them.
Since number of objects/meshes has a big impact on the rendering performance, I merge my objects into a few huge meshes and create "pseudo meshes" which just hold information about the indexes of the mesh's triangles and the other data attached. I am able to render each mesh with their own color and user is able to pick them separately.
However transparency and render order is making things hard for me. I managed to render my scene with transparent and non-transparent objects by merging them to separate meshes.
My problem is not being able to highlight the picked objects effectively. I want the highlighting to be a non-transparent color. If a transparent object is picked I change the associated triangles' color attribute to match my highlight color with opacity of 1.0. But this does not work as I intend to because, since the merged mesh's material is transparent, the render order for it won't change although I set the opacity of its' triangles as 1.0. Result is poorly ordered objects on the screen.
I know I could use MultiMaterial but then number of drawcalls -may or may not- increase enormously if the user selects high number of objects. So I am looking for a better solution that will keep the same performance whatever happens.
Do you have any suggestions on how to solve this problem?

Adding text in three.js

I am visualizing a graph using Three.js and for each node of the graph I add a label using TextGeometry. It is a pretty small graph but when I add text my application gets really slow. What should I do about it?
TextGeometry is more suitable for cases when you are really interested in rendering the text in 3D. It will create complex geometry that will surely slow your app down specially when there is a lot of text or you use CanvasRenderer.
For labels, it is generally better to use 2D labels, which are way faster to render. There are many different approaches to this. These can go on top of the Three.js rendering canvas, on a separate canvas, or even normal HTML nodes positioned using CSS properties. Alternatively, you can dynamically create small canvases of your label texts, and use them as sprite textures always facing camera - this might be the easiest way as the labels would be part of the 3D scene as your other objects. For a separate layer approach, you need to use unprojectVector or such to figure out screen XY coordinates to match your 3D scene positions.
See these SO posts for example:
- Dynamically create 2D text in three.js
- Canvas and SpriteMaterial
- How do I add a tag/label to appear on top of several objects so that the tag always faces the camera when the user clicks the object?

OpenGL ES. Hide layers in 2D?

For example I have 2 layers: background and image. In my case I must show or hide an image on zoom value changed (simply float variable).
The only solution I know is to keep 2 various frame buffers for both background and image and not to draw the image when it is not necessary.
But is it possible to do this in an easier way?
Just don't pass the geometry to glDrawArrays() for the layer you want to hide when the zoom occurs. OpenGL ES completely re-renders everything every frame. You should have a glClear() call at the start of your frame render loop. So, removing something is done by just not sending its triangles. You might need to divide your geometry into separate lists for each layer.

Resources