The method in Pierre Baret's link can solve my problem. When the line passes only the vertices of a certain voxel, whether to visit the current voxel is a very vague question, so I made a little changes to the method. When two or more values in tMaxX, tMaxY, and tMaxZ are equal, the voxels generated by the method in the paper are as shown in a. I made a little change to generate the result in b. A more normal condition is shown in c, which compares lines generated by 3D bresenham and this method respectively.

The code implemented by c++:
void line3D(int endX, int endY, int endZ, int startX, int startY, int startZ, void draw){
int x1 = endX, y1 = endY, z1 = endZ, x0 = startX, y0 = startY, z0 = startZ;
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int dz = abs(z1 - z0);
int stepX = x0 < x1 ? 1 : -1;
int stepY = y0 < y1 ? 1 : -1;
int stepZ = z0 < z1 ? 1 : -1;
double hypotenuse = sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2));
double tMaxX = hypotenuse*0.5 / dx;
double tMaxY = hypotenuse*0.5 / dy;
double tMaxZ = hypotenuse*0.5 / dz;
double tDeltaX = hypotenuse / dx;
double tDeltaY = hypotenuse / dy;
double tDeltaZ = hypotenuse / dz;
while (x0 != x1 || y0 != y1 || z0 != z1){
if (tMaxX < tMaxY) {
if (tMaxX < tMaxZ) {
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
}
else if (tMaxX > tMaxZ){
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
else{
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
}
else if (tMaxX > tMaxY){
if (tMaxY < tMaxZ) {
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
}
else if (tMaxY > tMaxZ){
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
else{
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
}
else{
if (tMaxY < tMaxZ) {
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
}
else if (tMaxY > tMaxZ){
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
else{
x0 = x0 + stepX;
tMaxX = tMaxX + tDeltaX;
y0 = y0 + stepY;
tMaxY = tMaxY + tDeltaY;
z0 = z0 + stepZ;
tMaxZ = tMaxZ + tDeltaZ;
}
}
draw(x0, y0, z0);
}
}