[SOLVED] Changing individual triangle's color on a mesh

hi.

I have a for eg. icosphere and I’d like to highlight one of its triangles I’m pointing at with the camera’s front vector. I was able to calculate which triangle is the target I’m pointing at. The question is, that how can I change only those three vertices’ color? I’m doing the rendering instanced, so I send the mesh’s vertex positions in a VBO and the individual objects’ transformation matrices in instanced VBOs.

  • If I send the the colors in a simple VBO, it belongs to all the objects because of instance rendering.
  • If I send the the colors in an instanced VBO, then in the vertex shader I’ll have all colors for all vertices, but the problem is that now how can I decide which is the current vertex…

So, what is the common way to change particular vertices’ color on a single object when I’m instanced rendering everything?

gl_InstanceID

[quote]holds the integer index of the current primitive
[/quote]
Does “current primitive” means triangle? I thought it means one instance meaning one mesh.

Yeah, gl_InstanceID means one particular instance of your instanced draw call. It sounded like the triangles of a mesh were your “instances”. :slight_smile:
To access the vertex index of one particular instance, use: gl_VertexID.

hm. Now the problem is, if I send the colors through instanced attribs, its should be in the vertex shader like:

layout (location = 11) in vec3 perVertexColorInstanced[3000];

and then I can use

perVertexColorInstanced[gl_VertexID]

But the problem is [quote]Implementation limit of 16 MAX_VERTEX_ATTRIBS (e.g., number of generic plus conventional active vec4 attributes) exceeded, shader uses up to vec4 attribute 3011.
[/quote]
Am I misunderstanding something? Or I’m might be too tired… sorry if I am so.

When you use instanced vertex attributes, you do not get a large array with ALL instance’s data, but you only ever get the single value for the currently processed instance. The difference between instanced and non-instanced vertex attributes is, that instanced attributes advance only once per instance (given you did not modify the instance divisor) and non-instanced attributes advance once per vertex.

I still stuck.

I did this:

  • When I store the vertices, I also store those as a triangle (in the same order). Something like this [ [VERT_1,VERT_2,VERT_3], [VERT_4,VERT_5,VERT_6], …]
  • When I calculate the surface hit point, I also calculate the hit triangle’s index
  • I send the currentlz hit triangle’s index to the vertex shader, and try to figure it out if the actual vertex (gl_ VertexID) is part of that triangle

But it does not work. As I read about gl_VertexIndex more and more, I got myself more confused as well. So what is gl_VertexID? If I have a cube (with unique vertices), it can be 0-23 (6*4) OR it can be 0-2 (as an index of the actual triangle)?

So, what I have is this:

  • A hit point
  • The object’s triangles in order

How can I then check in the vertex shader, if the actual vertex is in the hit triangle?

Hit point calculation:


Vector3f pos = gameObject.getTransform().getPosition();
Spheref spheref = new Spheref(pos.x, pos.y, pos.z, gameObject.getRadius());

if (Intersectionf.intersectRaySphere(cameraRay, spheref, nearFar) && nearFar.x < closestDistance) {
    surfaceHitPoint = new Vector3f(Camera.main.getCamPosition()).add(Camera.main.getCameraDirection().mul(nearFar.x));
    int triangleIndex = getTriangleIndex(surfaceHitPoint, gameObject.getMesh().getTriangles(), gameObject.getTransform());
}

Also, I draw this way:

GL31.glDrawElementsInstanced(GL_TRIANGLES, batch.getMesh().getIndices().length, GL_UNSIGNED_INT, 0, gameObjectsCount);

And here is how I check if I hit the triangle (maybe there is the problem):


    private int getTriangleIndex(Vector3f surfaceHitPoint, List<List<Vector3f>> triangles, Transform transform) {
        for (int i = 0; i < triangles.size(); i++) {
            if (isInThisTriangle(surfaceHitPoint, triangles.get(i), transform)) {
                return i;
            }
        }

        return -1;
    }

    private boolean isInThisTriangle(Vector3f hitPoint, List<Vector3f> triangle, Transform transform) {
        Vector3f a = new Vector3f(triangle.get(0));
        Vector3f b = new Vector3f(triangle.get(1));
        Vector3f c = new Vector3f(triangle.get(2));

        transform.notifyDataChanged();
        Vector4f p0 = new Vector4f(a.x, a.y, a.z, 1).mul(transform.getTransformationMatrix());
        Vector4f p1 = new Vector4f(b.x, b.y, b.z, 1).mul(transform.getTransformationMatrix());
        Vector4f p2 = new Vector4f(c.x, c.y, c.z, 1).mul(transform.getTransformationMatrix());

        a.set(p0.x, p0.y, p0.z);
        b.set(p1.x, p1.y, p1.z);
        c.set(p2.x, p2.y, p2.z);

        // 1. the unit normal of triange (A, B, P)  - call it N1
        // 2. the unit normal of triangle (B, C, P) - call it N2
        // 3. the unit normal (C,A,P) called N3
        Vector3f n1 = b.sub(a).cross(new Vector3f(hitPoint).sub(a)).normalize();
        Vector3f n2 = c.sub(b).cross(new Vector3f(hitPoint).sub(b)).normalize();
        Vector3f n3 = a.sub(c).cross(new Vector3f(hitPoint).sub(c)).normalize();

        float res1 = new Vector3f(n1).dot(n2);
        float res2 = new Vector3f(n2).dot(n3);

        if (res1 > 0.99 && res2 > 0.99) {
            return true;
        }
        return false;
    }

UPDATE: as I continue debugging, it seems that the problem is might be around the correct triangle selection. I tested it with a cube. When my vector hit a point on the sphere, I put a cube there, and cubes appear correctly. I also debugged through what I send to the shader and how I use gl_VertexID, and it also looks good, I tested it with manual parameters and colored the right triangle.

So in conclusion, now I think the triangle index, where the hit has happened is the bad guy…

[quote]So in conclusion, now I think the triangle index, where the hit has happened is the bad guy…
[/quote]
If you suspect this to be the case, you can use Intersectionf.testRayTriangleFront().

Side-note. I had no idea joml had these intersection tests included in it. Is there are speed test comparisons to other library approaches?

Finally I did it!

The problem was that I load the object from .obj file, and I collected the vertices into triangles in a wrong order. Before joml, I used this, I dont know if it faster or not:


        // 1. the unit normal of triange (A, B, P)  - call it N1
        // 2. the unit normal of triangle (B, C, P) - call it N2
        // 3. the unit normal (C,A,P) called N3
        Vector3f n1 = b.sub(a).cross(new Vector3f(hitPoint).sub(a)).normalize();
        Vector3f n2 = c.sub(b).cross(new Vector3f(hitPoint).sub(b)).normalize();
        Vector3f n3 = a.sub(c).cross(new Vector3f(hitPoint).sub(c)).normalize();

        float res1 = new Vector3f(n1).dot(n2);
        float res2 = new Vector3f(n2).dot(n3);

        //LOGGER.debug("TRI: {}",triangle);

        if (res1 > 0.99 && res2 > 0.99) {
            return true;
        }
        return false;