strange opacity behaviour

71 views
Skip to first unread message

Michael Hecht

unread,
Jan 3, 2014, 11:02:25 AM1/3/14
to vpytho...@googlegroups.com
Hello,

I'm new to vpython. I tried some basic applications and got a behaviour of opacity, which I cannot understand. the code is:

from visual import *
import math

floor = box (pos=(0,0,0), length=120, height=20, width=20, color=color.blue, opacity = 0.1)
ball  = sphere (pos=(0,4,0), radius=1, color=color.red)

dt = 0.01

x0 = 0.0
y0 = 0.0
z0 = -60.0
r0 = 10

t0   = 0.0
tmax = 120
dt   = 1.

dalpha0 = 2.*3.14/(tmax/3.0)

for ti in xrange(int(t0),int(tmax/dt)):
  t = t0 + ti*dt
  rate (20)
  print "t = %.1f s" % t 
  alpha = t * dalpha0 % 360.
  y = x0 + r0 * math.sin(alpha) * float(tmax-t)/tmax
  z = y0 + r0 * math.cos(alpha) * float(tmax-t)/tmax
  x = z0 + t
   
  ball.pos = (x,y,z)
  ball1 = sphere(pos=(x,y,z),radius=0.5,color=color.red,opacity=0.5)
  ball2 = sphere(pos=(x,y,z),radius=0.1,color=color.green)
 

I expected to get the smaller red transparent sphere everywhere, but some of the spheres are missing. If I rotate the view the occurency changes in a reproducible way.

Can someone explain, what happens?

Thank You in advance!


vpython-opacity.png

Bruce Sherwood

unread,
Jan 3, 2014, 2:13:02 PM1/3/14
to vpytho...@googlegroups.com
The problem goes away if you comment out the low-opacity box named floor. (It's easier to see the box if the opacity is increased from 0.1 to 0.5.) 

This is an example of a general limitation on opacity in VPython, which is implemented by CPU code, using the OpenGL 3D graphics library, that sorts transparent and opaque objects from back to fron, based on the z coordinates of their centers, which is a crude scheme that necessarily fails in various circumstances. For example, if there are two intersecting long boxes, transparency is determined not by where pixels of the arms are located but by the crude measure of where are the centers of the two boxes. I notice that if I look down one end of the "floor" box the red spheres in front of the box center are missing, and from the other end again it is the red spheres in front of the box center that are missing.

The way to handle opacity correctly is to base it on the z-depth of individual pixels, not the centers of large objects. This can be done in real time in GPUs (the graphical processing units found on modern graphics cards) using the algorithm called "depth peeling". I've implemented this in GlowScript (glowscript.org), which uses the WebGL 3D library included in current browsers and which unlike OpenGL requires graphics cards with GPUs. Here is a technical description of the scheme:


And here is a runnable version of your program in GlowScript (click Edit this program to see the code, which is in CoffeeScript, which looks similar to Python):


If the program doesn't run, see the Help at glowscript.org for information on system requirements for running GlowScript programs.

Also, in the Example programs at glowscript.org, see the program Transparency, which correctly displays intersecting transparent boxes.

Currently VPython does not use GPUs, with the minor exception of materials and textures, which are disabled on computers whose graphics cards don't have GPUs. Eventually VPython should be updated to use GPUs, at which point the GlowScript pixel-based depth-peeling scheme would replace VPython's object-based sorting scheme.

Minor comments: When you say "from visual import *", that automatically also imports all of math and all of numpy. It's good practice to start with the statement "from __future__ import division, print_function" to ensure that your program runs correctly in both Python 2.x and Python 3.x; this also makes it unnecessary to add decimal points to force floating point, because 3/2 is interpreted as 1.5, not 1. Note that "pi" is present (due to the import of math):

from __future__ import division, print_function
from visual import *

floor = box (pos=(0,0,0), length=120, height=20, width=20, color=color.blue, opacity = 0.5)
ball  = sphere (pos=(0,4,0), radius=1, color=color.red)

dt = 0.01

x0 = 0.0
y0 = 0.0
z0 = -60
r0 = 10

t0   = 0
tmax = 120
dt   = 1

dalpha0 = 2*pi/(tmax/3)

for ti in xrange(int(t0),int(tmax/dt)):
  t = t0 + ti*dt
  rate (20)
  print("t = %.1f s" % t)
  alpha = t * dalpha0 % 360
  y = x0 + r0 * sin(alpha) * (tmax-t)/tmax
  z = y0 + r0 * cos(alpha) * (tmax-t)/tmax
  x = z0 + t
    
  ball.pos = (x,y,z)
  ball1 = sphere(pos=(x,y,z),radius=0.5,color=color.red,opacity=0.5)
  ball2 = sphere(pos=(x,y,z),radius=0.1,color=color.green)

Here is an excerpt from the first page of the VPython Help concerning imports:

For experienced programmers

As a convenience to novice programmers to provide everything that is needed to get started, the statement "from visual import *" imports all of the VPython features and executes "from math import *" and "from numpy import *". It also arranges that for routines common to both math and numpy such as sqrt, the much faster math routine is used when possible (when the argument is a scalar rather than an array).

If you want to import the VPython objects selectively, import them from the vis module. Two simple examples:

import vis
vis.box(color=vis.color.orange,material=vis.materials.wood)

from vis import (box, color, materials)
box(color=color.orange, material=materials.wood)

There are clean modules vis.controls, vis.filedialog, and vis.graph equivalent to the modules visual.controls, visual.filedialog, and visual.graph.

-------------------------------------------------------------------




Reply all
Reply to author
Forward
0 new messages