I'm writing a rather complex webgl application in three.js and in order to have more control on my mesh materials I'm defining them through shaders.
However, I'm facing a serious problem for which I could not find any truly satisfying answer. Let's assume the following strong pre-requisites:
- my geometry is indexed, i.e. the vertices are NOT duplicated among faces and I don't want to change this
- the geometry is stored in a
THREE.BufferGeometry
object, again I don't want to switch toTHREE.Geometry
- I don't want to duplicate faces and/or create new geometries
- I don't want any two-ways rendering that would drop my framerate
Given the above, let's say I click on a triangle (i.e., shoot a ray and get the closest face intersecting the ray) of my geometry and I want such triangle to be highlighted with a different color.
I'm already performing this in a quite efficient way by assigning a custom vertex attribute, say 1.0
, to each vertex belonging to a face to be highlighted.
In the vertex shader I define a varying with such vertex attribute and within the fragment shader I just execute the following (pseudocode):
vec4 frag_color=mix(default_color,highlight_color,(vert_attribute>1-eps));
where eps
is a small value (say 1.0e-4).
The idea is that each fragment interpolates its corresponding vertex attributes, say Vatt_1
, Vatt_2
and Vatt_3
, and if all the three attributes get the value 1.0
thus their interpolation is still nearly 1.0 (not precisely because of some roundoff error, that's why I use a small tolerance eps) and the test is true.
If the test is true
I have frag_color=highlight_color
.
On the other hand, if at least one Vatt_i
(i=1,2,3
) is not 1.0
but the default 0.0
, the interpolation at the current fragment is <1-eps
and the test is false
(giving frag_color=default_color
).
This seems to work perfectly, but now I have the following problem that looks truly challenging (given the constraints 1 and 2 above):
I don't have any simple way in the fragment shader to know whether or not the current fragment belongs to a specific face (or stays within three specific vertices, which is the same). So, if I select two triangles T1
and T2
, and by chance a third triangle T3
has one (or two) vertices shared with T1
and two (or one) vertices shared with T2
I get that T3
gets highlighted too because its three vertices get the attribute 1.0
.
Of course, seen from a human perspective this shouldn't happen because the three "highlighted" vertices of T3
should "logically" refer to two different highlighted faces but for obvious reasons the fragment shader highlights also T3
.
This is a quite general problem I guess, I read a lot of forums without finding any satisfying possible solution. I understand that "this is how it works" and that the fragment shader does not have any knowledge of the background triangle nor its vertices, but here I'm looking for some clever idea or trick.
Does anybody have any suggestion to face this issue? Sorry for bothering but just to prevent some possible arguments: I consider the four points 1-4 above as strong requirements because otherwise I'd have other problems related to the overall performance and I don't want to pay this price.
Thanks in advance
fract(vert_attribute) > 1e-5
for the test? EDIT: well, forget about that. I missed the obvious point that you'd need to have different values for the same vertex :/ – Martin Schuhfuß1.0
if a face shares the vertex,0.0
if not), if the face ids have been smartly set a "reasonable" triangular mesh should require a rather small vector, I'd say 8 vec4 (i.e. 32 floats), maybe less, which is normally allowed byMAX_VARYING_VECTORS
. So the frag shader would interpolate 3 vectors of, say, 32 floats that are0.0
or1.0
, and only one face would have all1.0
. – Luca Detomi