This site requires JavaScript, please enable it in your browser!
Greenfoot back
wabuilderman
wabuilderman wrote ...

2014/12/8

3d z-sorting

wabuilderman wabuilderman

2014/12/8

#
Ok, I know I asked a while back, but I am still stuck on what to do in the else bit in the code:
public GreenfootImage DrawSolid(GreenfootImage ImageToRender, ArrayList<Face> faces)
    {
        int i = 0;
        boolean shouldContinue = true;
        world3d myWorld;
        myWorld = (world3d) getWorld();
        Camera Cam = myWorld.getCam();
        while (shouldContinue && i < faces.size() - 1)
        {
            //shouldContinue is used so that I can force a stop of the loop, without changing the value of i
            Face face1 = faces.get(i + 1);
            Face face2 = faces.get(i);
            boolean v1Closer = false;
            boolean v2Closer = false;
            boolean v3Closer = false;
            if(
            hypot3d(face1.getV1().getX(), face1.getV1().getY(), face1.getV1().getZ(), Cam.camX, Cam.camY, Cam.camZ) >
            hypot3d(face2.getV1().getX(), face2.getV1().getY(), face2.getV1().getZ(), Cam.camX, Cam.camY, Cam.camZ)
            )
            {
                v1Closer = true;
            }
            
            if(
            hypot3d(face1.getV2().getX(), face2.getV2().getY(), face1.getV2().getZ(), Cam.camX, Cam.camY, Cam.camZ) >
            hypot3d(face2.getV2().getX(), face2.getV2().getY(), face2.getV2().getZ(), Cam.camX, Cam.camY, Cam.camZ))
            {
                v2Closer = true;
            }
            
            if(
            hypot3d(face1.getV3().getX(), face1.getV3().getY(), face1.getV3().getZ(), Cam.camX, Cam.camY, Cam.camZ) >
            hypot3d(face2.getV3().getX(), face2.getV3().getY(), face2.getV3().getZ(), Cam.camX, Cam.camY, Cam.camZ))
            {
                v3Closer = true;
            }
            
            if(!v1Closer && !v2Closer && !v3Closer) //face1 is in front, so everything should be left in place
            {
                //no positions are changed.
            } 
            else if(v1Closer && v2Closer && v3Closer) //face2 is in front of face1 and should be moved down
            {
                faces.set(i, face1);
                faces.set(i + 1, face2);
            }
            else //mixed results
            {
                
            }
            i++;
        }
        i = 0;
        while(i<faces.size())
        {
            drawFace(faces.get(i).getV1(),faces.get(i).getV2(),faces.get(i).getV3(),ImageToRender, faces.get(i).getCol());
            i++;;
        }
        return ImageToRender;
    }
Super_Hippo Super_Hippo

2014/12/8

#
Hm, line 10. You never change the value of "shouldContinue", how should it ever force the loop to break?
davmac davmac

2014/12/8

#
wabuilderman wrote...
Ok, I know I asked a while back
You did, and I gave you a detailed response, but you seem to be ignoring it :( Your code is attempting to determine whether one face is closer than another based on whether all of the vertices from one face are closer to the camera than those of the other face. This will work (except for the overlapping case that your comment calls 'mixed results') but is unnecessary. (It might at best be a slight optimisation). I outlined the procedure for comparing the depth of two faces in my last post (linked above). This procedure is what would need to be implemented in the 'else bit in the code'. If you implement it correctly then you no longer need the original 'if' statement at all, so your 'else bit' could just become the entire loop body.
wabuilderman wabuilderman

2014/12/8

#
Super_Hippo, I have that there mostly in case I ever am fiddling with my code and want to break out of the loop early. Davmac, yes, I did read the response earlier, but I wasn't quite sure what you meant by doing it in reverse.
davmac davmac

2014/12/8

#
I did read the response earlier, but I wasn't quite sure what you meant by doing it in reverse
I never said 'in reverse'. I guess you mean this:
davmac wrote...
you need to perform the comparison the other way around (i.e. treat face 2 as a plane and check where face 1 points lie in relation to it)
To be honest I'm not sure how I can explain this any other way. You need to do the same procedure that I detailed in the preceeding dot points, but use the first face wherever you would have used the second, and use the second wherever you would have used the first. However, you haven't implemented the procedure at all in your code above. You don't consider the face as a plane and you do not check which side of the plane the vertices in the other face lie on. Instead, you have code which just checks whether each vertex from one face is closer to the camera than the corresponding vertex in the other face.
davmac davmac

2014/12/10

#
Hmm, that tutorial you linked earlier isn't much help, is it? You realise your camera is defined as three points. Does it also have an orientation?
davmac davmac

2014/12/10

#
Anyway, a compiling, but untested and incomplete sample:
/**
 * 3D sample code.
 */
public class ThreeD
{
    public static final int FACES_ALIGN = 0;
    public static final int IN_FRONT = 1;
    public static final int BEHIND = 2;
    public static final int INTERSECTS = 3;
    
    /**
     * Compare depth of two faces.
     * 
     * For this to work, the faces must first be transformed according to
     * the rotation and position of the camera, so that:
     *   (0,0,0) is the relative camera position
     *   +z is "in front" of the camera
     *   -z is behind the camera
     *   
     * Returns true if f1 is in front of f2, or false otherwise.
     * 
     */
    public boolean isInFront(Face f1, Face f2)
    {
        int r = compareFaces(f1, f2);
        if (r == IN_FRONT) {
            return false;
        }
        if (r == BEHIND) {
            return true;
        }
        if (r == FACES_ALIGN) {
            // don't care
            return true;
        }
        return isInFront(f2, f1); // reverse the faces and try again
    }
    
    /**
     * Compare two faces in terms of depth from camera.
     * 
     * For this to work, the faces must first be transformed according to
     * the rotation and position of the camera, so that:
     *   (0,0,0) is the relative camera position
     *   +z is "in front" of the camera
     *   -z is behind the camera
     *   
     * returns:
     *   FACES_ALIGN - if neither face is in front of the other
     *   IN_FRONT - if the second face (f2) is in front of the first
     *   BEHIND - if the second face is behind the first
     *   INTERSECTS - if some points of the second face are in front and some are behind,
     *                in this case, call again with f1=f2 and f2=v1
     */
    public int compareFaces(Face f1, Face f2)
    {
        // First we need to consider the first face as a plane. We create
        // two vectors from two of the vertices (note that I'm re-using the
        // Vertex class to hold vectors). These vectors will define the plane:
        Vertex f1a = vectorSub(f1.getV2(), f1.getV1());
        Vertex f2a = vectorSub(f1.getV3(), f1.getV1());
        
        // get cross product:
        Vertex cpv = vectorCP(f1a, f2a);
        
        // if the cross product is zero-magnitude, it's useless. However we
        // would only get that if the face is a line or point (i.e. if two
        // of the vertices are the same), so I'll ignore that possibility for
        // now.
        
        // Now we want the cross product vector to point towards the camera,
        // i.e. negative z.
        if (cpv.getZ() > 0) {
            cpv = new Vertex(-cpv.getX(), -cpv.getY(), -cpv.getZ());
        }
        
        // get the dot product for each of the vertices in the second face
        // to see whether the are behind or in front of the first face:
        
        double v1dp = vectorDP(cpv, vectorSub(f2.getV1(), f1.getV1()));
        double v2dp = vectorDP(cpv, vectorSub(f2.getV2(), f1.getV1()));
        double v3dp = vectorDP(cpv, vectorSub(f2.getV3(), f1.getV1()));
        
        if (v1dp == 0 && v2dp == 0 && v3dp == 0) {
            return FACES_ALIGN;
        }
        
        if (v1dp >= 0 && v2dp >= 0 && v3dp >=0) {
            return IN_FRONT;
        }
        
        if (v1dp <= 0 && v2dp <= 0 && v3dp <= 0) {
            return BEHIND;
        }
        
        return INTERSECTS;
    }
    
    /**
     * Subtract one vector/vertex from another, return a vector result
     */
    public Vertex vectorSub(Vertex v1, Vertex v2)
    {
        double dx = v1.getX() - v2.getX();
        double dy = v1.getY() - v2.getY();
        double dz = v1.getZ() - v2.getZ();
        return new Vertex(dx,dy,dz);
    }
    
    /**
     * Cross-product of two vectors, returns a vector orthogonal to
     * both the original vectors (or a zero-magnitude vector if the
     * original vectors are parallel, or if either of them are zero
     * magnitude).
     */
    public Vertex vectorCP(Vertex v1, Vertex v2)
    {
        double dx = v1.getY() * v2.getZ() - v1.getZ() * v2.getY();
        double dy = v1.getZ() * v2.getX() - v1.getX() * v2.getZ();
        double dz = v1.getX() * v2.getY() - v1.getY() * v2.getX();
        return new Vertex(dx,dy,dz);
    }
    
    public double vectorDP(Vertex v1, Vertex v2)
    {
        return v1.getX() * v2.getX()
            + v1.getY() * v2.getY()
            + v1.getZ() * v2.getZ();
    }
}
davmac davmac

2014/12/10

#
If you want to make the above code work for an arbitrary camera orientation, you'd modify lines 73-75 so that the cpv vector was pointing whichever of the two directions was towards the camera. If your camera direction is represented as a vector then you'd just take the dot product of that with cpv, and negate cpv if the dot product is positive. I'll leave that as an exercise. (Alternatively, you could rotate all faces according to camera orientation before you do the depth sort, and rotate them back afterwards).
davmac davmac

2014/12/10

#
btw in case it's not clear, you would essentially replace lines 13 through 50 of the code you posted earlier with a call to my 'isInFront' method. :)
wabuilderman wabuilderman

2014/12/10

#
Wow! Ok, It might be a little bit before I can tell you how well it works, but Thanks!
wabuilderman wabuilderman

2014/12/10

#
Also, the anotation is very much appreciated. and so is your patience with me.
You need to login to post a reply.