# How to update normals for correct lighting when transforming vertex buffer instances

**URL:** <https://openrndr.discourse.group/t/how-to-update-normals-for-correct-lighting-when-transforming-vertex-buffer-instances/102>\
**Category:** How to?\
**Created:** [May 5, 2020, 11:42pm UTC](https://openrndr.discourse.group/t/how-to-update-normals-for-correct-lighting-when-transforming-vertex-buffer-instances/102 "2020-05-05T23:42:00Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Yann](https://avatars.discourse-cdn.com/v4/letter/y/bc79bd/32.png) [@Yann](https://openrndr.discourse.group/u/Yann)\
**Post date:** [May 5, 2020, 11:42pm UTC](https://openrndr.discourse.group/t/how-to-update-normals-for-correct-lighting-when-transforming-vertex-buffer-instances/102/1 "2020-05-05T23:42:00Z")

</div>

Hello,  
I am following the guide for drawing [multiple vertex buffer instances](https://guide.openrndr.org/advancedDrawing/customRendering.html#drawing-instances).

In my code below, I am rendering 3 cubes using the same geometry, but each has a different rotation and translation:

```
fun main() = application {

    configure {
        width = 800
        height = 800
    }

    program {

        val boxGeometry = boxMesh(10.0, 10.0, 10.0)
        val transforms = vertexBuffer(vertexFormat {
            attribute("transform", VertexElementType.MATRIX44_FLOAT32)
        }, 3)

        extend(Orbital()) { eye = Vector3(0.0, 5.0, -30.0) }
        extend(Screenshots())

        extend {
            drawer.shadeStyle = shadeStyle {
                vertexTransform ="""
                    x_viewMatrix *= i_transform;
                """.trimIndent()

                fragmentTransform = """
                    float dot_prod = dot(-va_normal, p_light);
                    float normalized = (1 + dot_prod) / 2;
                    float light = clamp(normalized, 0.0, 1.0);
                    x_fill.rgb = vec3(light);
                """.trimIndent()
                parameter("light", Vector3(0.0, -1.0, 1.0))
            }

            transforms.put {
                for (i in 0 until transforms.vertexCount) {
                    val transform = transform {
                        translate(-15.0 + i * 15.0, 0.0, 0.0)
                        rotate(Vector3.UNIT_X, i * seconds * 8)
                    }
                    write(transform)
                }
            }

            drawer.vertexBufferInstances(
                    listOf(boxGeometry),
                    listOf(transforms),
                    DrawPrimitive.TRIANGLES,
                    transforms.vertexCount
            )
        }
    }
}

```

 ![cubes](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/0f59e26e9fc7d6a7665ced2ebb13ab7a82951c74.png)

From the screenshot, the lighting is not applied correctly (it is rotating with the geometry).  
I think I need to update the `x_normal` but I’m not sure how to do this based on [the shader section of the guide](https://guide.openrndr.org/advancedDrawing/shadeStyles.html#the-shade-style-language).  
Thanks for any advice.

EDIT:  
It mostly works as expected if I change the shader code to this:

```
    drawer.shadeStyle = shadeStyle {
        vertexTransform ="""
            x_viewMatrix *= i_transform;
            x_viewNormalMatrix *= i_transform;
        """.trimIndent()

        fragmentTransform = """
            x_fill.rgb *= v_viewNormal.y;
        """.trimIndent()
        parameter("light", Vector3(0.0, -1.0, 1.0))
    }

```

Still not sure if this is the recommended approach.

---

<div class="post-metadata">

**Author:** ![abe](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/abe/32/700_2.png) [@abe](https://openrndr.discourse.group/u/abe)\
**Post date:** [May 6, 2020, 7:13am UTC](https://openrndr.discourse.group/t/how-to-update-normals-for-correct-lighting-when-transforming-vertex-buffer-instances/102/2 "2020-05-06T07:13:01Z")

</div>

Find out “One last thing” at [https://learnopengl.com/Lighting/Basic-Lighting](https://learnopengl.com/Lighting/Basic-Lighting) maybe that helps?

---

<div class="post-metadata">

**Author:** ![edwin](https://avatars.discourse-cdn.com/v4/letter/e/73ab20/32.png) [@edwin](https://openrndr.discourse.group/u/edwin)\
**Post date:** [May 6, 2020, 7:48am UTC](https://openrndr.discourse.group/t/how-to-update-normals-for-correct-lighting-when-transforming-vertex-buffer-instances/102/3 "2020-05-06T07:48:51Z")

</div>

I will write a longer reply when I can find the time. The idea is that you update `x_modelMatrix` and `x_modelNormalMatix` (likely works with the `view` versions too). However, for the normal matrix you need to multiply with a transform matrix that has translation and scale removed. You can calculate this matrix in the vertexTransform, but it requires an inverse (for a general case solution) and may be a bit computationally heavy. I usually add a second matrix to the instance attributes that is set to `normalMatrix(someMatrix44)`

---

<div class="post-metadata">

**Author:** ![Yann](https://avatars.discourse-cdn.com/v4/letter/y/bc79bd/32.png) [@Yann](https://openrndr.discourse.group/u/Yann)\
**Post date:** [May 6, 2020, 10:51pm UTC](https://openrndr.discourse.group/t/how-to-update-normals-for-correct-lighting-when-transforming-vertex-buffer-instances/102/4 "2020-05-06T22:51:46Z")

</div>

@edwin @abe thanks for the tips!  
It works as expected by using the `x_modelNormalMatrix` and `v_worldNormal`:

```
        drawer.shadeStyle = shadeStyle {
            vertexTransform ="""
                x_viewMatrix *= i_transform;
                x_modelNormalMatrix *= i_transform;
            """.trimIndent()

            fragmentTransform = """
                float dot_prod = dot(v_worldNormal, p_light);
                float normalized = (1 + dot_prod) / 2;
                float light = clamp(normalized, 0.0, 1.0);
                x_fill.rgb = vec3(light);
            """.trimIndent()
            parameter("light", Vector3(0.0, 1.0, 0.0).normalized)
        }

```

I am finding a lot of openGL resources online, but everyone seems to use different shader conventions.
