# Colors off at different viewing angles (e.g. rear side)

**URL:** <https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215>\
**Category:** Using Cinder\
**Created:** [July 9, 2018, 10:53pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215 "2018-07-09T22:53:25Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![CarlJalal](https://avatars.discourse-cdn.com/v4/letter/c/77aa72/32.png) [@CarlJalal](https://discourse.libcinder.org/u/CarlJalal)\
**Post date:** [July 9, 2018, 10:53pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/1 "2018-07-09T22:53:25Z")

</div>

Here’s from the starting camera perspective:  
 ![image](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/6db06f6b4136da052814a8dac3fb14653318f027.jpg)

And from behind:  
 ![image](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/350dd65094bd818f2b1f6803036d151ed2766cfe.jpg)

Wondering why the color shading appears incorrect from the rear side?  
Thanks!

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [July 10, 2018, 6:42am UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/2 "2018-07-10T06:42:34Z")

</div>

I assume you have enabled the depth buffer and are using lambert shading?

When rendering transparent objects, make sure to disable writing to the depth buffer. If the scene also contains opaque objects, render them first (with depth testing and writing enabled), then disable depth writing (but keep depth testing enabled) and render your transparent objects.

For best results, sort the transparent objects from back to front. This is important if the objects have different colors, because rendering a yellow object over a red one is not the same as rendering a red object over a yellow one.

Rendering transparent objects is an advanced topic for which there is still no satisfactory solution in computer graphics world.

-Paul

[http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-10-transparency/](http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-10-transparency/)

[https://learnopengl.com/Advanced-OpenGL/Blending](https://learnopengl.com/Advanced-OpenGL/Blending)

---

<div class="post-metadata">

**Author:** ![felixfaire](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/felixfaire/32/168_2.png) [@felixfaire](https://discourse.libcinder.org/u/felixfaire)\
**Post date:** [July 10, 2018, 8:57am UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/3 "2018-07-10T08:57:30Z")

</div>

Just to add to this, if you hadnt seen this post already there is some more advice for the same “problem”.

> [@Inconsistent blending depending on cam angle](https://discourse.libcinder.org/t/inconsistent-blending-depending-on-cam-angle/1124):
>
> Hello! I’m stuck with a blending issue, hope someone can give me a clue! I’m trying to render a simulation of row of arches with light beams coming out of them. For the light beams I just render cylinder-shaped meshes. The problem is that the blending seems inconsistent based on the angle from which the camera points at the structure. In the below image #1 (actual image of the current state of my app) the top left view is pretty close to what I want, but the top right view (where the camera fa…

Good luck with the 3D CA! I dont want to derail this topic but on a separate note your current method of a Batch per cube will suffice for the first couple of hundred cubes however when you are ready to take it up a notch it could be a great exercise to learn about instanced rendering. This basically involves 1 cube Batch and you send a list of positions and colours to the GPU separately which will draw them all in one draw call. Have a look at the InstancedTeapots example if this is of interest to you (though this method also requires more knowledge about the shader pipeline).

F

---

<div class="post-metadata">

**Author:** ![CarlJalal](https://avatars.discourse-cdn.com/v4/letter/c/77aa72/32.png) [@CarlJalal](https://discourse.libcinder.org/u/CarlJalal)\
**Post date:** [July 10, 2018, 1:53pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/4 "2018-07-10T13:53:28Z")

</div>

Thanks guys. Sorry for so many questions. Seems transparency is pretty complicated, so I’m considering avoiding it for now maybe.

1. Enabling additive blending causes nothing to be drawn (pure white screen) regardless if objects are opaque or transparent.

2. Disabling depth test causes interesting shadowing from different angles  
front:  

3. I turned off all transparency, and I’m now very confused about the lighting here with lambert shading – seems inconsistent, or I haven’t set the correct lighting directions? If possible, I’d like to read up on how lighting might work.  
front:  
 ![image](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/e970b7f5f16c09f5d173832981db04ba00c3ca7a.png)  
angle1:  
 ![image](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/48fce38bc4a4bc64cd7162f412bf4f6b8b240683.png)  
angle2:  
 ![image](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/63fa7653479b531f2f931c150ea03134974835d8.png)

---

<div class="post-metadata">

**Author:** ![felixfaire](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/felixfaire/32/168_2.png) [@felixfaire](https://discourse.libcinder.org/u/felixfaire)\
**Post date:** [July 10, 2018, 2:28pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/5 "2018-07-10T14:28:06Z")

</div>

If you have a white background you wont see anything with additive blending as you cant add anything to white to make it any other colour (its already at the peak brightness for all 3 colour channels). Try setting your background to black and using additive blending again.

I made a similar 3D cellular automata several years ago with additive blending in processing. You can see it in the first 30s of this video. [https://vimeo.com/105969968](https://vimeo.com/105969968) NB. Additive blending can peak out to white quite quickly if you dont use darker colours to draw your cubes with.

---

<div class="post-metadata">

**Author:** ![CarlJalal](https://avatars.discourse-cdn.com/v4/letter/c/77aa72/32.png) [@CarlJalal](https://discourse.libcinder.org/u/CarlJalal)\
**Post date:** [July 10, 2018, 3:25pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/6 "2018-07-10T15:25:26Z")

</div>

Thanks Felix. I see what you’re saying. I think additive blending has a unique look.  
 ![image](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/addac9331bd69ad2a42a3e2248dda0df539f49f2.jpg)

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [July 10, 2018, 7:36pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/7 "2018-07-10T19:36:52Z")

</div>

I’m confused about the lighting as well. It should work.

For my understanding, could you check that:

- You created the cube using a `geom::Cube` fed into a `Vbo`?
- You created the `GlslProg` using:  
`gl::getStockShader( gl::ShaderDef().color().lambert() )`?
- You’ve created a `Batch` from the `Vbo` and the `GlslProg`?
- You’re drawing the cubes by calling `mBatch->draw()` in a loop?

If you did all that, the `geom::Cube` should make sure that vertices _and normals_ are generated for the `Vbo` and the `GlslProg` will take care of the lighting. I’ll describe what the shader does at the end of this post in case you’re interested.

If you did things differently, could you explain what you did or share some code maybe?

-Paul

* * *

**How the Lambert shader works**

The shader comes in two parts: a vertex shader and a fragment shader.

The vertex shader takes the 24 vertices of every cube (6 sides, 4 corners per side), as well as their normals and [transforms](https://learnopengl.com/Getting-started/Transformations) them from _model space_ (the [coordinates](https://learnopengl.com/Getting-started/Coordinate-Systems) as defined by the cube) to _world space_ (the cube is translated and maybe scaled, depending on your calls to `gl::translate()` and so on) to _view space_ (the coordinates relative to the [camera](https://learnopengl.com/Getting-started/Camera), where the camera position is (0,0,0) and we’re looking down the negative z-axis). The _normals_ are also transformed to view space, using a special matrix that prevents scaling so they remain unit length. Finally, the vertex shader passes the transformed vertex positions and normals, as well as the drawing color, to the fragment shader. And to fulfill OpenGL’s requirements, it also transforms the vertices to _clip space_, which is the second to last step of the 3D-to-2D projection.

```auto
#version 150

uniform mat4 ciModelView; // Provided by Cinder to convert from model space to view space in one go.
uniform mat4 ciProjectionMatrix; // Provided by Cinder to convert from view space to clip space.
uniform mat3 ciNormalMatrix; // Provided by Cinder to convert normals to view space.

in vec4 ciPosition; // Vertex position in model space provided by Cinder.
in vec3 ciNormal; // Normal in model space provided by Cinder.
in vec4 ciColor; // Vertex color (or current draw color) provided by Cinder.

out vec4 vertPosition; // Our own view space vertex position being sent to the fragment shader.
out vec3 vertNormal; // Our own view space normal being sent to the fragment shader.
out vec4 vertColor; // Our own vertex color being sent to the fragment shader.

void main(void)
{
    vertPosition = ciModelView * ciPosition; // Convert from model to view space.
    vertNormal = ciNormalMatrix * ciNormal; // Convert from model to view space without scaling.
    vertColor = ciColor;

    gl_Position = ciProjectionMatrix * vertPosition; // Mandatory: convert from view space to clip space.
}

```

The fragment shader runs for every pixel of your image. It receives the vertex positions and normals, automatically interpolated for the pixel. It then calculates the direction from the vertex to the light source. For the default Lambert shader, the light source position is hard-coded to be the same as the camera position. It then calculates so-called [Lambert’s Diffuse Lighting](https://learnopengl.com/Lighting/Basic-Lighting), which is a fancy term for the simplest form of lighting you can imagine. If the vertex normal points directly at the camera, the [dotproduct](http://learnwebgl.brown37.net/09_lights/lights_diffuse.html) between the normal and the light direction will be `1`, resulting in the brightest color. If the vertex normal is perpendicular to the light direction, the result will be `0` or completely dark. If it points away from the light, we probably can’t see the vertex anyway because it will be at the rear side of the cube, but the result would be `-1` and for good measure we clamp it to zero. The fragment shader then multiplies the result of the dotproduct with the input color and outputs the final color.

```auto
#version 150

in vec4 vertPosition; // Our inputs from the vertex shader.
in vec3 vertNormal;
in vec4 vertColor;

out vec4 fragColor; // Our output from the fragment shader: RGBA.

void main(void)
{
    // Calculate direction to light source.
    const vec3 kLightPosition = vec3( 0.0 ); // In view space, this is same as camera position.
    vec3 L = normalize( kLightPosition - vertPosition.xyz );

    // Normalize normal ('vertNormal' may be slightly longer or shorter than 1 after interpolation). 
    vec3 N = normalize( vertNormal );

    // Take the dotproduct of N and L to find out if our polygon is facing the light.
    float NdotL = max( 0.0, dot( N, L ) );

    // Output the final color. Don't modify transparency.
    fragColor.rgb = vertColor.rgb * NdotL;
    fragColor.a = vertColor.a;
}

```

As an exercise, see if you can add [specular](https://learnopengl.com/Lighting/Basic-Lighting) lighting by writing your first shader!

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [July 10, 2018, 8:04pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/8 "2018-07-10T20:04:14Z")

</div>

To answer myself…

could it be that your top image, where the cubes are solid green, is caused by the fact that we’re looking dead-on the cube’s corner vertex? In theory, the 3 front facing planes could then be turned away from the light source at precisely the same angle and the lighting would therefor be exactly the same.

---

<div class="post-metadata">

**Author:** ![CarlJalal](https://avatars.discourse-cdn.com/v4/letter/c/77aa72/32.png) [@CarlJalal](https://discourse.libcinder.org/u/CarlJalal)\
**Post date:** [July 10, 2018, 8:48pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/9 "2018-07-10T20:48:49Z")

</div>

Hm, interesting. Yes, that makes sense. The original starting position (which causes a solid green color) is directly and perfectly aligned with the corner of the first cube vertex, but I assumed that some of the cubes to the left or right would get a different shading due to their offset. If I change the camera perspective even a tiny bit, the sides become visible.

> [@paul.houx](#):
>
> - You created the cube using a `geom::Cube` fed into a `Vbo` ? No
> - You created the `GlslProg` using:  
> `gl::getStockShader( gl::ShaderDef().color().lambert() )` ? Yes
> - You’ve created a `Batch` from the `Vbo` and the `GlslProg` ? Yes
> - You’re drawing the cubes by calling `mBatch->draw()` in a loop? Yes

Thanks. I found this article  
[https://mottosso.gitbooks.io/cinder/content/book/guide\_to\_meshes.html](https://mottosso.gitbooks.io/cinder/content/book/guide_to_meshes.html)  
I’ll be reading on VboMeshes, plus I need to start using drawInstanced() for performance  
checking drawInstanced() in this:

> <https://github.com/paulhoux/Cinder-Samples/blob/master/HexagonMirror/src/HexagonMirrorApp.cpp>

Wondering if there’s an easy way to generate a VboMesh from geom::Cube(), but I still need to figure out how to make custom meshes for the future

```auto
on setup...
	auto lambert = gl::ShaderDef().lambert().color();
	gl::GlslProgRef	shader = gl::getStockShader(lambert);
	for (int x = 0; x < xdim; ++x) {
		for (int y = 0; y < ydim; ++y) {
			for (int z = 0; z < zdim; ++z) {
				auto slice = geom::Cube().size(xsize, xsize, xsize);
				auto trans = geom::Translate(x, y, z);
				int point = x*zdim*ydim + y*zdim + z;
				mSlices[point] = gl::Batch::create(slice >> trans, shader);
			}
		}
	}

on draw...
	gl::ScopedModelMatrix scpModelMtx;
	for (int x = 0; x < xdim; ++x) {
		for (int y = 0; y < ydim; ++y) {
			for (int z = 0; z < zdim; ++z) {
				int point = x*zdim*ydim + y * zdim + z;
				gl::color(ColorA(CM_HSV, 0.5, float(status[point]), .1, 0.05 + 0.8 * float(status[point])));
				mSlices[point]->draw();
			}
		}
	}

```

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [July 10, 2018, 9:57pm UTC](https://discourse.libcinder.org/t/colors-off-at-different-viewing-angles-e-g-rear-side/1215/10 "2018-07-10T21:57:19Z")

</div>

There is:

```auto
auto mesh = gl::VboMesh::create( slice );
auto shader = gl::getStockShader(lambert);
mBatch = gl::Batch::create( mesh, shader );

```

_(note: when you use `mBatch = gl::Batch::create( slice, shader )`, a `VboMesh` is created under the hood for you)._

And to use instanced rendering, try:

```auto
std::vector<vec3> positions;
for (int x = 0; x < xdim; ++x) {
  for (int y = 0; y < ydim; ++y) {
    for (int z = 0; z < zdim; ++z) {
      positions.emplace_back( x, y, z );
    }
  }
}

// Create a buffer containing all positions. 
auto instances = gl::Vbo::create( GL_ARRAY_BUFFER, positions.size() * sizeof( vec3 ), positions.data(), GL_STATIC_DRAW );

// Describe the contents of the buffer in a way Cinder will understand.
geom::BufferLayout layout;
layout.append( geom::CUSTOM_0, sizeof( vec3 ) / sizeof( float ), 0, 0, 1 /* per instance */ );

// Append this data to our VboMesh:
mesh->appendVbo( layout, instances );

// When creating the batch, tell Cinder the name of our custom attribute.
mBatch = gl::Batch::create( mesh, shader, { { geom::CUSTOM_0, "iPosition" } } );

```

Note that you will now have to use a custom shader, instead of a stock one. You could begin by copying the shader code from my previous post to two separate files: `cubes.vert` and `cubes.frag`. Then load it using:

```auto
auto shader = gl::GlslProg::create( loadAsset("cubes.vert"), loadAsset("cubes.frag") );

```

You will then have to add our custom attribute to the shader…

```auto
in vec3 iPosition; // per instance

```

_(note: also keep the line `in vec4 ciPosition;`, as we will need both)_

…and adjust the vertex position accordingly:

```auto
vertPosition = ciModelView * vec4( ciPosition.xyz + iPosition.xyz, 1.0 );

```

Don’t forget to call `mBatch->drawInstanced( positions.size() );` instead of `mBatch->draw();` 🙂

**Caveat: I wrote this code in Google Chrome, so it might contain errors.**

Edit: the cool thing is: you can now sort your positions easily to render the cubes from back to front. Store the positions and the instances Vbo as member variables (e.g. `std::vector<vec3> mPositions` and `gl::VboRef mInstances`) and then do this:

```auto
void MyApp::update()
{
    const auto camera = mCamera.getEyePoint();

    // Sort by distance from camera, furthest first.
    std::sort( std::begin( mPositions ), std::end( mPositions ),
            [camera]( const vec3 &a, const vec3 &b ) {
        return glm::distance2( a, camera ) > glm::distance2( b, camera );
    } );

    // Update positions.
    auto ptr = (vec3 *)mInstances->mapReplace();
    for( auto &position : mPositions ) {
        *ptr = position;
        ptr++;
    }
    mInstances->unmap();
}

```
