# Unexpected behavior of instancing

**URL:** <https://openrndr.discourse.group/t/unexpected-behavior-of-instancing/450>\
**Category:** GLSL Shaders\
**Created:** [November 3, 2022, 12:58pm UTC](https://openrndr.discourse.group/t/unexpected-behavior-of-instancing/450 "2022-11-03T12:58:16Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alessandro](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/alessandro/32/412_2.png) [@Alessandro](https://openrndr.discourse.group/u/Alessandro)\
**Post date:** [November 3, 2022, 12:58pm UTC](https://openrndr.discourse.group/t/unexpected-behavior-of-instancing/450/1 "2022-11-03T12:58:16Z")

</div>

I was trying to understand a bit better how instancing works, in particular how to use instances ids in shaders, and I encountered something which I consider an idiosyncratic behavior.  
Here’s the code

```kotlin
  import org.openrndr.application
  import org.openrndr.color.ColorRGBa
  import org.openrndr.draw.*
  import org.openrndr.extensions.Screenshots
  import org.openrndr.extra.noise.uniform
  import org.openrndr.math.Vector2
  import org.openrndr.shape.Circle
  import kotlin.math.*
  
  
  fun main() = application {
      configure {
          width = 1000
          height = 1000
      }
  
      program {
          val nContours = 20
  
          val circles = List(nContours){ Circle(Vector2.uniform(drawer.bounds), Double.uniform(100.0, 200.0)) }
  
          val bufferLengths = shaderStorageBuffer( shaderStorageFormat {
              member("length", BufferMemberType.FLOAT, nContours)
          })
  
          bufferLengths.put {
              for (i in 0 until nContours) {
                          write((exp( 0.05 * circles[i].radius)).toFloat())
                      }
              }
          val rt = renderTarget(width, height){
              colorBuffer()
              depthBuffer()
          }
  
          val buffer = colorBuffer(width, height)
  
          backgroundColor = ColorRGBa.BLACK
          extend(Screenshots())
          extend {
  
              drawer.fill = null
              drawer.stroke = ColorRGBa.WHITE
              drawer.strokeWeight = 2.0
  
              drawer.isolatedWithTarget(rt) {
                  drawer.clear(ColorRGBa.BLACK)
                  drawer.shadeStyle = shadeStyle {
                      fragmentTransform = """ 
                      x_stroke.rgb = vec3(1000.0/b_l.length[c_instance], 0.0, 1.0);
                  """.trimIndent()
                      buffer("l", bufferLengths)
                  }
  
  
                  drawer.circles(circles)
              }
  
              rt.colorBuffer(0).copyTo(buffer)
  
              drawer.isolatedWithTarget(rt) {
                  drawer.clear(ColorRGBa.BLACK)
                  drawer.shadeStyle = shadeStyle {
                      fragmentTransform = """      
                      x_stroke.rgb = vec3(100.0/b_l.length[c_instance], 0.0, 1.0);
                  """.trimIndent()
                      buffer("l", bufferLengths)
                  }
  
                  drawer.contours(circles.map { it.contour })
              }
  
              if (mouse.position.x < width * 0.5){
                  drawer.image(buffer)
              }
              else {
                  drawer.image(rt.colorBuffer(0))
              }
  
          }
      }
  }

```

In the first isolated render, I basically batch draw a list of circles via .circles, and access the buffer with the c\_instance id, getting this (expected) result

 ![test1](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/30e24cd854ab9732548dcfdaece94a0adf459108.jpeg)

On the other hand, in the second isolated render, I batch draw the circles’ contours via .contours, but it in this case it seems the c\_instance id is always 0, hence all the circles have the same color

 ![test2](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/5d367c527e63277465c63551b8e71736f8699d26.png)

Notice that the same behavior appears if one batch draws the circles’ shapes via .shapes.  
Is there something I’m missing on how c\_instance behaves?

---

<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:** [November 3, 2022, 3:38pm UTC](https://openrndr.discourse.group/t/unexpected-behavior-of-instancing/450/2 "2022-11-03T15:38:16Z")

</div>

After simplifying the program to this

```auto
import org.openrndr.application
import org.openrndr.draw.shadeStyle
import org.openrndr.extra.noise.uniform
import org.openrndr.math.Vector2
import org.openrndr.shape.Circle

fun main() = application {
    program {
        val circles = List(20) { Circle(Vector2.uniform(drawer.bounds), 40.0) }

        val style = shadeStyle {
            fragmentTransform = "x_fill.rgb = vec3(c_instance / 20.0, 0.0, 1.0);"
        }

        extend {
            drawer.shadeStyle = style
            drawer.stroke = null

            if (mouse.position.x < width * 0.5) {
                drawer.circles(circles)
            } else {
                drawer.contours(circles.map { it.contour })
            }
        }
    }
}

```

I control+clicked `drawer.circles` and `drawer.contours` and I was reminded that the first one uses [batched mode](https://guide.openrndr.org/drawingBasics/drawingPrimitivesBatched.html), while the second method just iterates and draws the contours one by one, without setting any instance ID. I’ll ask if it would be possible to set the instance ID in the second case. It would be useful (and maybe more predictable 🙂 ).

---

<div class="post-metadata">

**Author:** ![Alessandro](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/alessandro/32/412_2.png) [@Alessandro](https://openrndr.discourse.group/u/Alessandro)\
**Post date:** [November 3, 2022, 4:16pm UTC](https://openrndr.discourse.group/t/unexpected-behavior-of-instancing/450/3 "2022-11-03T16:16:24Z")

</div>

Oooh, I see. Yeah, setting the instance ID would make sense. On the other hand, if .contours doesn’t use batched mode, then I would say that my approach using an SBBO is an overkill from the performance point of view, since one can pass the given parameter in an ad hoc loop, which is what I wanted to avoid. I guess that also .shapes just draws the shapes in the list one by one rather than batching.

---

<div class="post-metadata">

**Author:** ![Alessandro](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/alessandro/32/412_2.png) [@Alessandro](https://openrndr.discourse.group/u/Alessandro)\
**Post date:** [November 5, 2022, 6:35pm UTC](https://openrndr.discourse.group/t/unexpected-behavior-of-instancing/450/4 "2022-11-05T18:35:23Z")

</div>

I just realized that also .lineSegments seems not to set c\_instance…
