I am trying to get into creative coding mainly for creating live visuals. I have recently stumbled upon this great website called https://www.openprocessing.org/ where people can share their creations.
I have attached code below for creating two moving circles but I am having trouble understanding how the creator went about doing so, If anyone could explain to me how the for loop is working as well as how the x += 0.006; y += 0.006; if (x > TWO_PI) {x = 0;} section works, it would be greatly appreciated. The use of sin, cos and the Two_PI functions has me puzzled. Here is a link to the original code:
https://www.openprocessing.org/sketch/467333
//comment
float x = 0;
float xx = 0;
float y = 0;
float yy = 0;
float sizecircle = 250;
void setup() {
size (800, 650);
frameRate (60);
strokeWeight (1);
stroke (223, 170, 22);
}
void draw() {
background (51, 51, 51);
for (float i = 0; i < TWO_PI; i += TWO_PI/100) {
line (350 + sin(x+i) * sizecircle, 275 + cos(y+i) * sizecircle, 450 + cos(xx+i) * sizecircle, 375 + sin(yy+i) * sizecircle);
}
x += 0.006;
y += 0.006;
if (x > TWO_PI) {
x = 0;
}
if (y > TWO_PI) {
y = 0;
}
xx += 0.002;
yy += 0.002;
if (xx > TWO_PI) {
xx = 0;
}
if (yy > TWO_PI) {
yy = 0;
}
}
The unit of the angle for sin and cos is Radian. 360° are 2*PI, this is the reason for TWO_PI.
The variables x, y, xx and yy are incremented for 0.0 to 2*PI. If they reach 2*PI, they start form 0.0 again.
With the following code will draw lines from a center point (cx, cy) to 100 points around a circle with radius r.
for (float i = 0; i < TWO_PI; i += TWO_PI/100) {
line(cx, cy, cx + cos(i)*r, cy + sin(i)*r);
}
The trick in the code of the question is that the lines are connection the points around 2 circles, which are rotating opposite direction:
line(cx1 + sin(i)*r, cy1 + cos(i)*r,
cx2 + cos(i)*r, cy2 + sin(i)*r);
Note, that the order of sin and cos is swapped for the start point in compare to the end point, this causes that the circles are rotating opposite directions.
The different rotation speed is caused by the different constants 0.006 respectively 0.002.
By the way, the code can be simplified, because x == y and xx == yy. It is sufficient to use 2 angles in the range [0, TWO_PI]:
float a1 = 0;
float a2 = 0;
float sizecircle = 250;
void draw() {
background (51, 51, 51);
for (float i = 0; i < TWO_PI; i += TWO_PI/100) {
line (350 + sin(a1+i)*sizecircle, 275 + cos(a1+i)*sizecircle,
450 + cos(a2+i)*sizecircle, 375 + sin(a2+i)*sizecircle);
}
a1 += 0.006;
a2 += 0.002;
}
Since sin(x) == sin(x + TWO_PI*n) and cos(x) == cos(x + TWO_PI*n) (n is an integral number), it is not necessary to "reset" the angles.
It's more about math than about programming (well, both these things goes hand in hand).
He's doing the same thing twice, once for each circle, but one of the two will "move" faster than the other, hence the difference in x += 0.006; and xx += 0.002;.
There are 2 PI radians in a full circle (so 2 PI radians == 360 degrees). That's why he's using this measure.
This line
line (350 + sin(x+i) * sizecircle, 275 + cos(y+i) * sizecircle, 450 + cos(xx+i) * sizecircle, 375 + sin(yy+i) * sizecircle);
defines how each circle is "attached" to the other one by drawing a bunch of lines between them. The idea is that the author created a loop that updated the beginning point and the end point of a line, and this loop runs as long as there are lines to draw (it goes around the circle using the 2 PI number).
So in the for (float i = 0; i < TWO_PI; i += TWO_PI/100) loop he draws every line for this position of the circles.
Than he changes the "starting point" where he'll draw the first line by increasing variables x, y, xx, yy a little bit. As they are used in the context of radians, they "circle" around the circles.
Then the draw() loop start over again and he re-draws the whole thing, but a little different as the starting points changed. This makes the drawing look like it moves.
When the "starting points" variables x, y, xx, yy are finished doing a complete turn (so when they are over 2 PI radians), he resets them. As it's a full turn, it's not a huge reset. It's like rounding the time when the clock is one minute past the hour.
Hope it helps.
Related
I'm making a game with libGDX in Java. I'm trying to make a collision detection. As you can see in the image, I have a line which is a wall and a player with specified radius. The desired position is the next location which the player is trying to be in. But because there is a wall, he's placed in the Actual Position which is on the Velocity vector, but more closer to the prev location. I'm trying to figure out how can I detect that closer position?
My attempt:
private void move(float deltaTime) {
float step;
beginMovementAltitude();
if (playerComponent.isWalking())
step = handleAcceleration(playerComponent.getSpeed() + playerComponent.getAcceleration());
else step = handleDeacceleration(playerComponent.getSpeed(), playerComponent.getAcceleration());
playerComponent.setSpeed(step);
if (step == 0) return;
takeStep(deltaTime, step, 0);
}
private void takeStep(float deltaTime, float step, int rotate) {
Vector3 position = playerComponent.getCamera().position;
float x = position.x;
float y = position.y;
int radius = playerComponent.getRadius();
auxEnvelope.init(x, x + radius, y, y + radius);
List<Line> nearbyLines = lines.query(auxEnvelope);
float theta;
int numberOfIntersections = 0;
float angleToMove = 0;
Gdx.app.log(step + "", "");
for (Line line : nearbyLines) {
VertexElement src = line.getSrc();
VertexElement dst = line.getDst();
auxVector3.set(playerComponent.getCamera().direction);
auxVector3.rotate(Vector3.Z, rotate);
float nextX = x + (step * deltaTime) * (auxVector3.x);
float nextY = y + (step * deltaTime) * playerComponent.getCamera().direction.y;
float dis = Intersector.distanceLinePoint(src.getX(), src.getY(), dst.getX(), dst.getY(), nextX, nextY);
boolean bodyIntersection = dis <= 0.5f;
auxVector21.set(src.getX(), src.getY());
auxVector22.set(dst.getX(), dst.getY());
auxVector23.set(nextX, nextY);
if (bodyIntersection) {
numberOfIntersections++;
if (numberOfIntersections > 1) {
return;
}
theta = auxVector22.sub(auxVector21).nor().angle();
float angle = (float) (180.0 / MathUtils.PI * MathUtils.atan2(auxVector23.y - position.y, auxVector23.x - position.x));
if (angle < 0) angle += 360;
float diff = (theta > angle) ? theta - angle : angle - theta;
if (step < 0) step *=-1;
angleToMove = (diff > 90) ? theta + 180 : theta;
}
}
if (numberOfIntersections == 0) {
moveCameraByWalking(deltaTime, step, rotate);
} else {
moveCameraInDirection(deltaTime, step, angleToMove);
}
}
The idea is to find intersection of path of object center and the line moved by radius of the circle, see that picture.
At first, you need to find a normal to the line. How to do it, depends on how the line is defined, if it's defined by two points, the formula is
nx = ay - by
ny = bx - ax
If the line is defined by canonical equation, then coefficients at x and y define normal, if I remembered correctly.
When normal is found, we need to normalize it - set length to 1 by dividing coordinates by vector length. Let it be n.
Then, we will project starting point, desired point and randomly chosen point on line to n, treating them as radius vectors.
Projection of vector a to vector b is
project (a, b) = scalar_product (a, b) / length (b)**2 * b
but since b is n which length equals 1, we will not apply division, and also we want to only find length of the result, we do not multiply by b. So we only compute scalar product with n for each of three aforementioned points, getting three numbers, let s be the result for starting point, d for desired point, l for chosen point on the line.
Then we should modify l by radius of the circle:
if (s < d) l -= r;
else if (s > d) l += r;
If s = d, your object moves in parallel along the line, so line can't obstruct its movement. It's highly improbable case but should be dealt with.
Also, that's important, if l was initially between s and d but after modifying is no longer between then, it's a special case you may want to handle (restrict object movement for example)
Ather that, you should compute (d - s) / (l - s).
If the result is greater or equals 1, the object will not reach the line.
If the result is between 0 and 1, the line obstructs movement and the result indicates part of the path the object will complete. 0.5 means that object will stop halfway.
If the result is negative, it means the line is behind the object and will not obstruct movement.
Note that when using floating point numbers the result will not be perfectly precise, that's why we handle that special case. If you want to prevent this from happening at all, organize loop and try approximations until needed precision is reached.
public class SimpleHarmonic {
public static void main(String[] args) {
StdDraw.setXscale(0,900);
StdDraw.setYscale(0,700);
while (true) {
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.line(0,350,900,350); // x-axis
StdDraw.line(450,0,450,900); // y-axis
StdDraw.setPenColor(StdDraw.RED);
for (double x = -450; x <= 450; x += 0.5) {
double y = 50 * Math.sin(x * (Math.PI / 180));
int Y = (int) y;
int X = (int) x;
StdDraw.line(450 + X, 350 - Y, 450 + X, 350 - Y);
}
StdDraw.clear();
}
}
}
In this code I am attempting to simulate simple harmonic motion. However, I have only been able to draw a static graph, but I need it to move continously.
I believe I need to use a loop to contionusly redraw the points, but I am not sure how to do that.
How can I make my current sine graph move contionusly?
Edit: Voted to close as non-programming? what?
I took a look at the StdDraw class you are using and it looks like what you want is the
StdDRaw.show(int) method, this method comment states:
/**
* Display on screen, pause for t milliseconds, and turn on
* <em>animation mode</em>: subsequent calls to
* drawing methods such as {#code line()}, {#code circle()}, and {#code square()}
* will not be displayed on screen until the next call to {#code show()}.
* This is useful for producing animations (clear the screen, draw a bunch of shapes,
* display on screen for a fixed amount of time, and repeat). It also speeds up
* drawing a huge number of shapes (call {#code show(0)} to defer drawing
* on screen, draw the shapes, and call {#code show(0)} to display them all
* on screen at once).
* #param t number of milliseconds
*/
In this library any time you call a draw method such as line or circle it conditionally repaints the frame. By passing the int param to the draw method it will turn all painting methods into "animation mode" and defer repainting the frame until you call draw() (no params).
To make it animate you must make each iteration of your while loop 1 animation frame, each frame will need to differ from the previous one. You can do this by using a variable outside your loop to offset each frame by a small ammount. Ill call this offset
With this information you can alter your loop to look like:
double offset = 0;
while (true) {
offset+=1; // move the frame slightly
StdDraw.show(10); // defer repainting for 10 milisecoinds
StdDraw.clear(); // clear before painting
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.line(0,350,900,350); // x-axis
StdDraw.line(450,0,450,900); // y-axis
StdDraw.setPenColor(StdDraw.RED);
for (double x = -450; x <= 450; x += 0.5) {
// apply the offset inside of calculation of Y only such that it
// slowly "moves" the sin wave
double y = 50 * Math.sin((offset+x) * (Math.PI / 180));
int Y = (int) y;
int X = (int) x;
StdDraw.line(450 + X, 350 - Y, 450 + X, 350 - Y);
}
StdDraw.show(); // end animation frame. force a repaint
}
A few improvements in your code
1 Inside your loop where you draw each "dot" you are increnting by .5. Because that X value is literally 1 pixel you arent gaining anything by going to .5 instead of 1. 1 is quite literally the smallest you can visually see in this enviroment. I recommend making it at least be x+=1
for (double x = -450; x <= 450; x += 1)
2 You are using the .line method but drawing to the same point. You could significantly speed up your program by only calculating every 3rd pixels Y value and connecting the dots. For instance
double prevX = -450;
double prevY = 50 * Math.sin((prevX+offset) * (Math.PI / 180)); // seed the previous Y to start
for (double x = 0; x <= 450; x += 3) {
double y = 50 * Math.sin((x+offset) * (Math.PI / 180));
StdDraw.line(450 + (int)prevX, 350 - (int)prevY, 450 + (int)x, 350 - (int)y);
prevX = x;
prevY = y;
}
3 This isnt your code but in the StdDraw.init method you can set some rendering hints to allow for cleaner lines. This should make it look alot nicer
offscreen.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
Combining all those things heres what I wrote
public static void main(String[] args) {
StdDraw.setXscale(0,900);
StdDraw.setYscale(0,700);
double offset = 0;
while (true) {
StdDraw.show(10);
StdDraw.clear();
offset-=1;
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.line(0,350,900,350); // x-axis
StdDraw.line(450,0,450,900); // y-axis
StdDraw.setPenColor(StdDraw.RED);
double prevX = 0;
double prevY = 50 * Math.sin((prevX+offset) * (Math.PI / 180)); // seed the previous Y to start
StdDraw.filledCircle(450 + prevX, 350 - prevY, 5);
for (double x = 0; x <= 450; x += 3) {
double y = 50 * Math.sin((x+offset) * (Math.PI / 180));
StdDraw.line(450 + (int)prevX, 350 - (int)prevY, 450 + (int)x, 350 - (int)y);
prevX = x;
prevY = y;
}
StdDraw.show();
}
}
I dont have an animation recorder so heres a picture
I'm writing a program that will rotate a rectangular prism around a point. It handles the rotations via 3 rotation methods that each manage a rotation around a single axis (X, Y, and Z). Here's the code
public void spinZ(Spin spin) {
if (x == 0 && y == 0) {
return;
}
double mag = Math.sqrt(x * x + y * y);
double pxr = Math.atan(y / x);
x = Math.cos(spin.zr + pxr) * mag;
y = Math.sin(spin.zr + pxr) * mag;
}
public void spinY(Spin spin) {
if (z == 0 && x == 0) {
return;
}
double mag = Math.sqrt(x * x + z * z);
double pxr = Math.atan(z / x);
x = Math.cos(spin.yr + pxr) * mag;
z = Math.sin(spin.yr + pxr) * mag;
}
public void spinX(Spin spin) {
if (z == 0 && y == 0) {
return;
}
double mag = Math.sqrt(y * y + z * z);
double pxr = Math.atan(z / y);
y = Math.cos(spin.xr + pxr) * mag;
z = Math.sin(spin.xr + pxr) * mag;
}
public void addSpin(Spin spin) {
spinY(spin);
spinX(spin);
spinZ(spin);
}
Spin is a useless class that stores three doubles (which are rotations). These methods basically convert the rotations into 2D vectors (how I store the points) and rotate them as such. The first if statement makes sure the 2D vectors don't a magnitude of 0. They are allowed to, but in that case it's not necessary to carry out the rotation calculations. The other part just handles the trig. The bottom method just ties everything together and allows me to quickly change the order of the rotations (because order should and does affect the final rotation).
The problem isn't with the individual rotations but when they all come together. I can easily get a single rotation around a single axis to work without distorting the rectangular prism. When I put them all together, like if you were to call addSpin().
When spinY is called first, the prism is distorted when the rotations include a Y rotation (if the y component of the rotation is zero, and no rotation around the y-axis should occur, then no distortion occurs). In fact, if spinY() is called anytime but last a distortion of the cube will occur.
The same is the case with spinZ(). If spinZ() is called last, the cube won't get warped. However spinX() can go anywhere and not cause a distortion.
So the question is: Is there a problem with how I'm going about the rotations? The other question is while all rotations cannot be encompassed by rotations along just the X and Y axes or any other pair of distinct axes (like X and Z, or Y and Z), can those three sets collectively make all rotations? To clarify, can the rotations, which cannot be reached by a set of rotations around the X and Y axes, be reached by a set of rotations around the X and Z axes or the Y and Z axes?
I trust the medium I'm using to display the prisms. It's a ray-tracer I made that works well with rectangular prisms. This is a more math-based question, but it has a fairly comprehensive programming component.
These are some parallel calculations that still yield in distortions.
public void spinZ(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double xp = x*c - y*s;
double yp = y*s + x*c;
x = xp;
y = yp;
}
public void spinY(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;
}
public void spinX(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double yp = y*c - z*s;
double zp = z*c + y*s;
y = yp;
z = zp;
}
Your checks for things like
x == 0
are unnecessary and dangerous as a double almost never will have the precise value 0. The atan when you have a division can lead to catastrophic loss of precision as well.
Why are they unnecessary? Because the following performs your rotation in a cleaner (numerically stable) fashion:
double c = Math.cos(spin.yr);
double s = Math.cos(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;
Of course, my example assumes you treat the y rotation with a right handed orientation, but from your sample code you seem to be treating it as left handed. Anyways, the wikipedia article on the Rotation matrix explains the math.
I'm programming a software renderer in Java, and am trying to use Z-buffering for the depth calculation of each pixel. However, it appears to work inconsistently. For example, with the Utah teapot example model, the handle will draw perhaps half depending on how I rotate it.
My z-buffer algorithm:
for(int i = 0; i < m_triangles.size(); i++)
{
if(triangleIsBackfacing(m_triangles.get(i))) continue; //Backface culling
for(int y = minY(m_triangles.get(i)); y < maxY(m_triangles.get(i)); y++)
{
if((y + getHeight()/2 < 0) || (y + getHeight()/2 >= getHeight())) continue; //getHeight/2 and getWidth/2 is for moving the model to the centre of the screen
for(int x = minX(m_triangles.get(i)); x < maxX(m_triangles.get(i)); x++)
{
if((x + getWidth()/2 < 0) || (x + getWidth()/2 >= getWidth())) continue;
rayOrigin = new Point2D(x, y);
if(pointWithinTriangle(m_triangles.get(i), rayOrigin))
{
zDepth = zValueOfPoint(m_triangles.get(i), rayOrigin);
if(zDepth > zbuffer[x + getWidth()/2][y + getHeight()/2])
{
zbuffer[x + getWidth()/2][y + getHeight()/2] = zDepth;
colour[x + getWidth()/2][y + getHeight()/2] = m_triangles.get(i).getColour();
g2.setColor(m_triangles.get(i).getColour());
drawDot(g2, rayOrigin);
}
}
}
}
}
Method for calculating the z value of a point, given a triangle and the ray origin:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double d = -(A * triangle.getV1().x + B * triangle.getV1().y + C * triangle.getV1().z);
double rayZ = -(A * rayOrigin.x + B * rayOrigin.y + d) / C;
return rayZ;
}
Method for calculating if the ray origin is within a projected triangle:
private boolean pointWithinTriangle(Triangle triangle, Point2D rayOrigin)
{
Vector2D v0 = new Vector2D(triangle.getV3().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v1 = new Vector2D(triangle.getV2().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v2 = new Vector2D(rayOrigin, triangle.getV1().projectPoint(modelViewer));
double d00 = v0.dotProduct(v0);
double d01 = v0.dotProduct(v1);
double d02 = v0.dotProduct(v2);
double d11 = v1.dotProduct(v1);
double d12 = v1.dotProduct(v2);
double invDenom = 1.0 / (d00 * d11 - d01 * d01);
double u = (d11 * d02 - d01 * d12) * invDenom;
double v = (d00 * d12 - d01 * d02) * invDenom;
// Check if point is in triangle
if((u >= 0) && (v >= 0) && ((u + v) <= 1))
{
return true;
}
return false;
}
Method for calculating surface normal of a triangle:
private Vector3D getNormal(Triangle triangle)
{
Vector3D v1 = new Vector3D(triangle.getV1(), triangle.getV2());
Vector3D v2 = new Vector3D(triangle.getV3(), triangle.getV2());
return v1.crossProduct(v2);
}
Example of the incorrectly drawn teapot:
What am I doing wrong? I feel like it must be some small thing. Given that the triangles draw at all, I doubt it's the pointWithinTriangle method. Backface culling also appears to work correctly, so I doubt it's that. The most likely culprit to me is the zValueOfPoint method, but I don't know enough to know what's wrong with it.
My zValueOfPoint method was not working correctly. I'm unsure why :( however, I changed to a slightly different method of calculating the value of a point in a plane, found here: http://forum.devmaster.net/t/interpolation-on-a-3d-triangle-using-normals/20610/5
To make the answer here complete, we have the equation of a plane:
A * x + B * y + C * z + D = 0
Where A, B, and C are the surface normal x/y/z values, and D is -(Ax0 + By0 + Cz0).
x0, y0, and z0 are taken from one of the vertices of the triangle. x, y, and z are the coordinates of the point where the ray intersects the plane. x and y are known values (rayOrigin.x, rayOrigin.y) but z is the depth which we need to calculate. From the above equation we derive:
z = -A / C * x - B / C * y - D
Then, copied from the above link, we do:
"Note that for every step in the x-direction, z increments by -A / C, and likewise it increments by -B / C for every step in the y-direction.
So these are the gradients we're looking for to perform linear interpolation. In the plane equation (A, B, C) is the normal vector of the plane.
It can easily be computed with a cross product.
Now that we have the gradients, let's call them dz/dx (which is -A / C) and dz/dy (which is -B / C), we can easily compute z everywhere on the triangle.
We know the z value in all three vertex positions.
Let's call the one of the first vertex z0, and it's position coordinates (x0, y0). Then a generic z value of a point (x, y) can be computed as:"
z = z0 + dz/dx * (x - x0) + dz/dy * (y - y0)
This found the Z value correctly and fixed my code. The new zValueOfPoint method is:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double dzdx = -A / C;
double dzdy = -B / C;
double rayZ = triangle.getV1().z * modelViewer.getModelScale() + dzdx * (rayOrigin.x - triangle.getV1().projectPoint(modelViewer).x) + dzdy * (rayOrigin.y - triangle.getV1().projectPoint(modelViewer).y);
return rayZ;
}
We can optimize this by only calculating most of it once, and then adding dz/dx to get the z value for the next pixel, or dz/dy for the pixel below (with the y-axis going down). This means that we cut down on calculations per polygon significantly.
this must be really slow
so much redundant computations per iteration/pixel just to iterate its coordinates. You should compute the 3 projected vertexes and iterate between them instead look here:
triangle/convex polygon rasterization
I dislike your zValueOfPoint function
can not find any use of x,y coordinates from the main loops in it so how it can compute the Z value correctly ?
Or it just computes the average Z value per whole triangle ? or am I missing something? (not a JAVA coder myself) in anyway it seems that this is your main problem.
if you Z-value is wrongly computed then Z-Buffer can not work properly. To test that look at the depth buffer as image after rendering if it is not shaded teapot but some incoherent or constant mess instead then it is clear ...
Z buffer implementation
That looks OK
[Hints]
You have too much times terms like x + getWidth()/2 why not compute them just once to some variable? I know modern compilers should do it anyway but the code would be also more readable and shorter... at least for me
Alright, so I got a bit of movement code and I'm thinking I'm going to need to manually input when to go up/down a slope. All I got to work with is the slope's normal, and vector, and My current and previous position, and my yaw.
Is there a better way to rotate whether I go up or down the slope based on my yaw?
Vector3f move = new Vector3f(0,0,0);
move.x = (float)-Math.cos(Math.toRadians(yaw));
move.z = (float)-Math.sin(Math.toRadians(yaw));
System.out.println("slopeNormal.z: " + slopeNormal.z + "move.z: " + move.z);
move.normalise();
float vx = (float) (Math.sqrt(Math.pow(move.y, 2) + Math.pow(move.z, 2)) * move.x);
float vy = (float) (Math.sqrt(Math.pow(move.x, 2) + Math.pow(move.z, 2)) * move.y);
float vz = - vx * slopeNormal.x - vy * slopeNormal.y;
move.scale(movementSpeed * delta);
if(vz < 0)
move.y -= slopeVec.y * 1.5f;
if(vz > 0)
move.y += slopeVec.y * 1.5f;
Vector3f.add(pos, move, pos);
Edit: updated code.
First off, the following is incorrect:
move.x = (float)-Math.toDegrees(Math.cos(Math.toRadians(yaw)));
move.z = (float)-Math.toDegrees(Math.sin(Math.toRadians(yaw)));
Math.toDegrees converts an angle in radians to one in degrees, but the results of Math.cos and Math.sin are not angles.
Assume zero yaw is in the positive x-direction... and define vx, vy, vz = rate of motion along 3 axes, s = speed, and slope normal = nx, ny, nz where nx^2 + ny^2 + nz^2 = 1. So nx = ny = 0, nz = 1 would be flat.
First, I define x', y' = axes relative to the flat ground (motion is constrained to ground). Then (the following is not valid Java, but I'm enclosing it in code format anyway):
vx' = cos(yaw) * s
vy' = sin(yaw) * s
Then I need to rotate from x', y' coordinates to real-world coordinates. That is done using the slope normal:
vx = sqrt(vy^2 + vz^2) vx'
vy = sqrt(vx^2 + vz^2) vy'
vz = - vx' nx - vy' ny
A check on this transformation: vx^2 + vy^2 + vz^2 must equal vx'^2 + vy'^2 = s^2. I think this works out.
So to answer your question: up or down? vz > 0 is up, vz < 0 is down.