Translucent box with opaque items inside

46 Views Asked by At

I'm trying to draw a translucent box with opaque items inside. Something like this:

Solution

For the translucent box I have also created a texture (whitebg.jpg) I would like to apply:

enter image description here

So far this is what I tried:

Main function

 private static void CreateItems(List<Items> packedItems)
 {
  Glut.glutInit();
  Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
  Glut.glutInitWindowSize(width, height);
  Glut.glutCreateWindow("pack");

  Glut.glutIdleFunc(OnRenderFrame);
  Glut.glutDisplayFunc(OnDisplay);

  Glut.glutKeyboardFunc(OnKeyboardDown);
  Glut.glutKeyboardUpFunc(OnKeyboardUp);
  Glut.glutMouseWheelFunc(OnMouseWheel);

  Glut.glutCloseFunc(OnClose);
  Glut.glutReshapeFunc(OnReshape);

  Gl.Disable(EnableCap.DepthTest);
  Gl.Enable(EnableCap.Blend);
  Gl.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

  program = new ShaderProgram(VertexShader, FragmentShader);

  program.Use();
  program["projection_matrix"].SetValue(Matrix4.CreatePerspectiveFieldOfView(0.45f, (float)width / height, 0.1f, 1000f));
  program["view_matrix"].SetValue(Matrix4.LookAt(new Vector3(0, 0, 10), Vector3.Zero, new Vector3(0, 1, 0)));

  program["light_direction"].SetValue(new Vector3(0, 0, 1));
  program["enable_lighting"].SetValue(lighting);

  bgTexture = new Texture("whitebg.jpg"); 
 }

Glut.glutIdleFunc

private static void OnRenderFrame()
{
 watch.Stop();
 float deltaTime = (float)watch.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency;
 watch.Restart();

 // perform rotation of the cube depending on the keyboard state
 if (autoRotate)
 {
    xangle += deltaTime / 2;
    yangle += deltaTime;
 }
 if (right) yangle += deltaTime;
 if (left) yangle -= deltaTime;
 if (up) xangle -= deltaTime;
 if (down) xangle += deltaTime;

 // set up the viewport and clear the previous depth and color buffers
 Gl.Viewport(0, 0, width, height);
 Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

 // make sure the shader program and texture are being used
 Gl.UseProgram(program);
 Gl.BindTexture(bgTexture);

 // set up the model matrix and draw the cube
 program["model_matrix"].SetValue(Matrix4.CreateRotationY(yangle) * Matrix4.CreateRotationX(xangle));
 program["enable_lighting"].SetValue(lighting);

 for (int i = 0; i < virtual_items.Count; i++)
 {
    Gl.BindBufferToShaderAttribute(virtual_items[i], program, "vertexPosition");
    Gl.BindBufferToShaderAttribute(virtual_items_color[i], program, "vertexColor");
    Gl.BindBuffer(virtual_items_quads[i]);

    Gl.DrawElements(BeginMode.Quads, virtual_items_quads[i].Count, DrawElementsType.UnsignedInt, IntPtr.Zero);
 }

 Gl.BindBufferToShaderAttribute(virtual_container, program, "vertexPosition");
 Gl.BindBufferToShaderAttribute(virtual_container_normals, program, "vertexNormal");
 Gl.BindBufferToShaderAttribute(virtual_container_UV, program, "vertexUV");
 Gl.BindBuffer(virtual_container_Quads);

 Gl.DrawElements(BeginMode.Quads, virtual_container_Quads.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

 Glut.glutSwapBuffers();

}

But the result obtained is not what I'm expecting. Texture is applying at box and also at items inside. Here a sample where I have a box of (2x1x1) and two items of (1x1x1):

enter image description here

Is it possible to apply the texture only on the box and keep the items with their real opaque color just like in the first picture?

1

There are 1 best solutions below

0
woodi On

In your initialization method "CreateItems" you are disabling depth testing and enabling blending:

  Gl.Disable(EnableCap.DepthTest);
  Gl.Enable(EnableCap.Blend);
  Gl.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

These states are not changed in the OnRenderFrame method. But if you want the items to be opaque, then you have to disable blending before drawing them. And of course renable it before drawing the translucent container.

If you want to display the translucent box only in the background, with items not being affected by it. Then you should render it with depth buffering being disabled using the command glDepthMask(false). Afterwards you turn it back on using glDepthMask(true).

Also you need to enable depth testing, because otherwise the items might not be displayed correctly. I.e. faces further away from the camera could overlap closer ones.