r3dvisualization

How to add a transparent reference plane to 3D persp() plot without covering the surface beneath it?


I am trying to add a horizontal reference plane to a 3D surface plot using R's persp() function, but the plane acts as an opaque layer that cover the surface beneath it.

I want the plane to be transparent so that parts of the surface above the plane are clearly above it, and parts below are visibly below it.

Here's a minimal reproducible example:

# Create a simple 3D surface
x <- seq(-2, 2, length.out = 30)
y <- seq(-2, 2, length.out = 30)
z <- outer(x, y, function(x, y) { 
  exp(-(x^2 + y^2)) + 0.5 * sin(2 * x) * cos(2 * y) 
})

# Create perspective plot
p <- persp(x, y, z, 
           xlab = "X", ylab = "Y", zlab = "Z",
           theta = 35, phi = 25,
           col = "lightblue", shade = 0.5,
           main = "Surface with reference plane at z=0.5")

# Add horizontal plane at z = 0.5
z_plane <- 0.5
x_corners <- c(min(x), max(x), max(x), min(x))
y_corners <- c(min(y), min(y), max(y), max(y))
z_corners <- rep(z_plane, 4)

# Convert to 2D projection and draw polygon
corners_2d <- trans3d(x_corners, y_corners, z_corners, pmat = p)
polygon(corners_2d, col = rgb(1, 0, 0, 0.3), border = "red")

The problem: the red plane covers the entire blue surface beneath it.

surface

I want the surface to be visible both above and below the plane, with the plane acting as a transparent reference. In other words, the 3D surface should appear to pass through the reference plane, with portions above z=0.5 clearly above the plane and portions below clearly below it.

Is there a way to achieve this?


Solution

  • Use rgl. For example,

    # Create a simple 3D surface
    x <- seq(-2, 2, length.out = 30)
    y <- seq(-2, 2, length.out = 30)
    z <- outer(x, y, function(x, y) { 
      exp(-(x^2 + y^2)) + 0.5 * sin(2 * x) * cos(2 * y) 
    })
    
    library(rgl)
    # Create perspective plot
    p <- persp3d(x, y, z, 
               xlab = "X", ylab = "Y", zlab = "Z",
               theta = 35, phi = 25,
               col = "lightblue", shade = 0.5,
               main = "Surface with reference plane at z=0.5")
    
    # Add horizontal plane at z = 0.5
    planes3d(0, 0, 1, -0.5, col = rgb(1, 0, 0), alpha = 0.3)
    

    Created on 2025-10-24 with reprex v2.1.1