Floorcasting not scrolling in raycasting engine? - java

I'm currently working on a raycaster in Java, and so far, I have the floor correctly textured. The problem, however, is that the floor doesn't scroll. In other words, when I move the camera in the projection, the floor stays the same, yet the walls move as expected. I'm really not sure what I'm doing wrong. I took almost all the code from this reference. Note that I took some liberties when pasting the code in that I used some pseudocode.
I tried applying a player offset to the tileX and tileY variables, e.g., tileX += player.x, and all I got was a floor that scrolls far too quickly and incorrectly.
for every ray:
... // other stuff relating to the walls above here.
int start = (int)(wallY + wallHeight + 1);
double directionCos = cos(rad(ray.getAngle()));
double directionSin = sin(rad(ray.getAngle()));
int textureDim = 16;
for (int y = start; y < screenHeight; y++) {
double distance = screenHeight / (2.f * y - screenHeight);
distance /= cos(rad(player.getAngle()) - rad(ray.getAngle()));
// The source I grabbed the code from actually appends the player's x and y to the tileX and tileY variables, but this completely messes up the textures when I try to.
double tileX = distance * directionCos;
double tileY = distance * directionSin;
int textureX = Math.floorMod((int)(tileX * textureDim), textureDim);
int textureY = Math.floorMod((int)(tileY * textureDim), textureDim);
int rgb = floorTexture.getRGB(textureX, textureY);
projectionFloor.setRGB((int)wallX, y, rgb);
}
Below is an image of the floor.
Below is an animation visualizing the problem.
Below is an animation visualizing what happens if I try to apply a player position offset:

Fixed it on my own. Turns out that, yes, you do have to account for the player's position (shocker!); the source I got the code from just didn't do it correctly.
DTPP = distance to projection plane.
for every pixel y from wallY + wallHeight + 1 to projectionHeight:
double r = y - this.getPreferredSize().height / 2.f;
double d = (CAMERA_HEIGHT * DTPP / r) / ANGLE;
double tileX = CAMERA_X + d * RAY_COSANGLE;
double tileY = CAMERA_Y + d * RAY_SINANGLE;
int textureX = Math.floorMod((int) (tileX * TEXTURE_SIZE /
TEXTURE_SCALE), TEXTURE_SIZE);
int textureY = Math.floorMod((int) (tileY * TEXTURE_SIZE /
TEXTURE_SCALE), TEXTURE_SIZE);
... (drawing occurs here)

Related

Bilinear interpolation anomaly

I wrote a function that takes the subpixels of an image for the purpose of upscaling, and the subpixel is generated by bilinear interpolation, but I am having some weird artifacts.
Here is my code:
public static int getSubPixel(BufferedImage bi, double x, double y) {
float[] topleft = new Color(bi.getRGB((int) Math.floor(x), (int) Math.floor(y))).getColorComponents(null);
float[] topright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), (int) Math.floor(y))).getColorComponents(null);
float[] bottomleft = new Color(bi.getRGB((int) Math.floor(x), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
float[] bottomright = new Color(bi.getRGB(Math.min(bi.getWidth() - 1, (int) Math.ceil(x)), Math.min(bi.getHeight() - 1, (int) Math.ceil(y)))).getColorComponents(null);
for (int i = 0; i < 3; i++) {
topleft[i] *= topleft[i];
topright[i] *= topright[i];
bottomleft[i] *= bottomleft[i];
bottomright[i] *= bottomright[i];
}
double decX = x % 1;
double decY = y % 1;
double inv_DecX = 1 - decX;
double inv_DecY = 1 - decY;
float red = (float) Math.sqrt((topleft[0] * inv_DecX + topright[0] * decX) * inv_DecY + (bottomleft[0] * inv_DecX + bottomright[0] * decX) * decY);
float green = (float) Math.sqrt((topleft[1] * inv_DecX + topright[1] * decX) * inv_DecY + (bottomleft[1] * inv_DecX + bottomright[1] * decX) * decY);
float blue = (float) Math.sqrt((topleft[2] * inv_DecX + topright[2] * decX) * inv_DecY + (bottomleft[2] * inv_DecX + bottomright[2] * decX) * decY);
return new Color(red, green, blue).getRGB();
}
This is the result of scaling up a 16x16 image 20 times:
As you can see, there is weird streaking going on. I did go out of my way to square the colors before averaging, then taking the square root of the result, but something does not seem right here. Any insight?
PS: I understand functions already exist to do this. This is an educational exercise. I am trying to understand the process by doing it on my own.
The stripe artifacts that you are seeing are caused by the linear interpolation scheme. Your implementation is correct (except for the squaring, which is unnecessary and causes the stripes to be stronger in darker regions of the image). This is what I'm seeing with a correct linear interpolation (16x instead of 20x as in the OP, I goofed) but without squaring (note less stripes in the dark blue parts):
If you want to get rid of the stripes, use a better interpolation scheme, such as cubic spline interpolation:

Draw an arc in opengl GL10

I want to draw an arc using center point,starting point,ending point on opengl surfaceview.I have tried this given below code so far. This function draws the expected arc if we give the value for start_line_angle and end_line_angle manually (like start_line_angle=0 and end_line_angle=90) in degree.
But I need to draw an arc with the given co-ordinates(center point,starting point,ending point) and calculating the start_line_angle and end_line_angle programatically.
This given function draws an arc with the given parameters but not giving the desire result. I've wasted my 2 days for this. Thanks in advance.
private void drawArc(GL10 gl, float radius, float cx, float cy, float start_point_x, float start_point_y, float end_point_x, float end_point_y) {
gl.glLineWidth(1);
int start_line_angle;
double sLine = Math.toDegrees(Math.atan((cy - start_point_y) / (cx - start_point_x))); //normal trigonometry slope = tan^-1(y2-y1)/(x2-x1) for line first
double eLine = Math.toDegrees(Math.atan((cy - end_point_y) / (cx - end_point_x))); //normal trigonometry slope = tan^-1(y2-y1)/(x2-x1) for line second
//cast from double to int after round
int start_line_Slope = (int) (sLine + 0.5);
/**
* mapping the tiriogonometric angle system to glsurfaceview angle system
* since angle system in trigonometric system starts in anti clockwise
* but in opengl glsurfaceview angle system starts in clock wise and the starting angle is 90 degree of general trigonometric angle system
**/
if (start_line_Slope <= 90) {
start_line_angle = 90 - start_line_Slope;
} else {
start_line_angle = 360 - start_line_Slope + 90;
}
// int start_line_angle = 270;
// int end_line_angle = 36;
//casting from double to int
int end_line_angle = (int) (eLine + 0.5);
if (start_line_angle > end_line_angle) {
start_line_angle = start_line_angle - 360;
}
int nCount = 0;
float[] stVertexArray = new float[2 * (end_line_angle - start_line_angle)];
float[] newStVertextArray;
FloatBuffer sampleBuffer;
// stVertexArray[0] = cx;
// stVertexArray[1] = cy;
for (int nR = start_line_angle; nR < end_line_angle; nR++) {
float fX = (float) (cx + radius * Math.sin((float) nR * (1 * (Math.PI / 180))));
float fY = (float) (cy + radius * Math.cos((float) nR * (1 * (Math.PI / 180))));
stVertexArray[nCount * 2] = fX;
stVertexArray[nCount * 2 + 1] = fY;
nCount++;
}
//taking making the stVertextArray's data in reverse order
reverseArray = new float[stVertexArray.length];//-2 so that no repeatation occurs of first value and end value
int count = 0;
for (int i = (stVertexArray.length) / 2; i > 0; i--) {
reverseArray[count] = stVertexArray[(i - 1) * 2 + 0];
count++;
reverseArray[count] = stVertexArray[(i - 1) * 2 + 1];
count++;
}
//reseting the counter to initial value
count = 0;
int finalArraySize = stVertexArray.length + reverseArray.length;
newStVertextArray = new float[finalArraySize];
/**Now adding all the values to the single newStVertextArray to draw an arc**/
//adding stVertextArray to newStVertextArray
for (float d : stVertexArray) {
newStVertextArray[count++] = d;
}
//adding reverseArray to newStVertextArray
for (float d : reverseArray) {
newStVertextArray[count++] = d;
}
Log.d("stArray", stVertexArray.length + "");
Log.d("reverseArray", reverseArray.length + "");
Log.d("newStArray", newStVertextArray.length + "");
ByteBuffer bBuff = ByteBuffer.allocateDirect(newStVertextArray.length * 4);
bBuff.order(ByteOrder.nativeOrder());
sampleBuffer = bBuff.asFloatBuffer();
sampleBuffer.put(newStVertextArray);
sampleBuffer.position(0);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, sampleBuffer);
gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, nCount * 2);
gl.glLineWidth(1);
}
To begin with the trigonometry you may not simply use the atan to find degrees of the angle. You need to check what quadrant the vector is in and increase or decrease the result you get from atan. Better yet use atan2 which should include both dx and dy and do the job for you.
You seem to create the buffer so that a point is created per degree. This is not the best solution as for large radius that might be too small and for small radius this is way too much. Tessellation should include the radius as well such that number of points N is N = abs((int)(deltaAngle*radius*tessellationFactor)) then use angleFragment = deltaAngle/N but make sure that N is greater then 0 (N = N?N:1). The buffer size is then 2*(N+1) of floats and the iteration if for(int i=0; i<=N; i++) angle = startAngle + angleFragment*i;.
As already pointed out you need to define the radius of the arc. It is quite normal to use an outside source the way you do and simply force it to that value but use the 3 points for center and the two borders. Some other options that usually make sense are:
getting the radius from the start line
getting the radius from the shorter of the two lines
getting the average of the two
interpolate the two to get an elliptic curve (explained below)
To interpolate the radius you need to get the two radiuses startRadius and endRadius. Then you need to find the overall radius which was already used as deltaAngle above (watch out when computing this one, it is more complicated as it seems, for instance drawing from 320 degrees to 10 degrees results in deltaAngle = 50). Anyway the radius for a specific point is then simply radius = startRadius + (endRadius-startRadius)*abs((angleFragment*i)/deltaAngle). This represents a simple linear interpolation in polar coordinate system which is usually used to interpolate vector in matrices and is the core functionality to get nice animations.
There are some other ways of getting the arc points which may be better performance wise but I would not suggest them unless and until you need to optimize your code which should be very late in production. You may simply keep stepping toward the next point and correcting the radius (this is only a concept):
vec2 start, end, center; // input values
float radius; // input value
// making the start and end relative to center
start -= center;
end -= center;
vec2 current = start/length(start) * radius; // current position starts in first vector
vec2 target = end/length(end) * radius; // should be the last point
outputBuffer[0] = current+center; // insert the first point
for(int i=1;; i++) { // "break" will need to exit the loop, we need index only for the buffer
vec2 step = vec2(current.y, -(current.x)); // a tangential vector from current start point according to center
step = step/length(step) / tessellationScale; // normalize and apply tessellation
vec2 next = current + step; // move tangentially
next = next/length(next) * radius; // normalize and set the
if(dot(current-target, next-target) > .0) { // when we passed the target vector
current = next; // set the current point
outputBuffer[i] = current+center; // insert into buffer
}
else {
current = target; // simply use the target now
outputBuffer[i] = current+center; // insert into buffer
break; // exit
}
}

Strange wraping when rotating Bitmaps

I started developing a custom Image class for a game which consists of three basic fields, width, height and a unidimensional array of int's which represent the color in the following order ARGB.
About two days ago i started trying to rotate images, and i was able to do that by converting this to a BufferedImage, rotate using Graphics2D and transforming it back to my own Image class, however setRGB and getRGB seem to be too slow and when i have to rotate about 10-20 images of 64*64 pixels the computer starts to struggle to maintain the fps.
So naturally i started developing my own image rotation function and i found a great post on gamedev.stackexchange.
https://gamedev.stackexchange.com/questions/67613/how-can-i-rotate-a-bitmap-without-d3d-or-opengl
The answer explains clearly what i should do to rotate an image even with different rotation points (which i intend to implement later).
However when following a similar formula to the one he explained (I had to change due to using a different coordinate system)
i find myself getting a strange wrapping at the top
Example (55 degrees): http://i.imgur.com/BBq83wV.png (The Black area represents the image size)
So i tried to distanciate the image from the top, and added
yDstPixel += this.height*sin;
Which sorta worked, but now the image gets clipped in half instead of wrapped
Example (35 degrees):http://i.imgur.com/Ap4aqrn.png
I'm almost sure the solution is very simple, but i cant seem to figure it out, a nudge in the right direction would be appreciated.
public Bitmap getRotatedCopy(double radians){
if(radians==0 || radians==(2*Math.PI)) return this;
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
int newWidth = (int) (this.width * cos + this.height * sin);
int newHeight = (int) (this.width * sin + this.height * cos);
Bitmap returnMap = new Bitmap(newWidth,newHeight); //set size of the returned bitmap to the smallest size possible
returnMap.fill(0xFF000000);
for (int y = 0; y < this.height; y++){
for(int x = 0; x < this.width; x++){
int srcPixel = x + (y * this.width);
int color= this.pixels[srcPixel];
if(color>0) continue;
int xDstPixel = (int) Math.abs((x * cos + y * sin));
int yDstPixel = (int) Math.abs((x * sin - y * cos));
//yDstPixel += this.height*sin;
int dstPixel = xDstPixel + (yDstPixel * newWidth);
returnMap.pixels[dstPixel]=color;
}
}
return returnMap;
}
You'll need to implement what you were planning to do later i.e. set the rotation origin and translation after the rotation.
I have modified your code to add them. (I didn't test running it but hope it works.) Please refer to the code below:
int newWidth = (int) (this.width * cos + this.height * sin);
int newHeight = (int) (this.width * sin + this.height * cos);
// After setting the new width and height...
// set rotation origin
double rox = this.width/2;
double roy = this.height/2;
// set translation center
double tcx = newWidth/2;
double tcy = newHeight/2;
Bitmap returnMap = new Bitmap(newWidth,newHeight);
returnMap.fill(0xFF000000);
for (int y = 0; y < this.height; y++){
double yy = y - roy;
for(int x = 0; x < this.width; x++){
double xx = x - rox;
int srcPixel = x + (y * this.width);
int color= this.pixels[srcPixel];
if(color>0) continue;
// following two lines are modified
int xDstPixel = (int) (xx * cos + yy * sin) + tcx;
int yDstPixel = (int) (xx * sin - yy * cos) + tcy;
// prevent negative index : maybe it is not needed at all
if (xDstPixel<0 || yDstPixel<0)
continue;
int dstPixel = xDstPixel + (yDstPixel * newWidth);
returnMap.pixels[dstPixel]=color;
}
}

Blocking light on a tiled level

I'm making a tiled(tiles size is 16px) level scrolling game in Java.
Right now I'm dealing with the lighting system.
I calculated the light gradient(as shown on the picture) with this code for each light(yellow blocks and tiles):
visMap = new int[level.getWidth() * level.getHeight()];
int lighted = 0;
for (int x = 0; x < level.getWidth(); x++) {
for (int y = 0; y < level.getHeight(); y++) {
double xd = (this.x >> 4) - x;
double yd = (this.y >> 4) - y;
double distance = Math.sqrt(xd * xd + yd * yd);
double p = power * 1.0;
double bright = p - distance;
visMap[x + y * level.getWidth()] = (int) (bright * power);
}
}
And now I'm trying to make the block somehow block the light(like in real life).
Is there a good method for this?
Thank's in advance,
Zaplik
The Picture: click
Spread light recursively. Decrease with each level of recursion the light intensity with the appropriated amount. Keep also track of the direction light is moving. Once you hit an obstacle, stop that branch of the recursion.

Implementation of Projectile Motion

I have created a projectile motion simulation in Java with a user interface.
The program allows the user to enter in initial values to calculate the projectile of the object. I don't have anything currently set up to draw the projectile onto the screen.
I have a separate spring worker thread handling the simulation code in the background.
I also have added in collision detection so that when the object hits the ground it will bounce and continue doing so until the loop exits.
The equations that I have in place are not correct for what I am trying to achieve.
With the following initial conditions, here is what a plot of the outputted data yields:
Initial Conditions:
Angle: 30 degrees;
Initial Speed 8.66 m/s;
Height: 50 m;
Elasticity of object: .5 coefficient of restitution in the y direction;
Acceleration: -9.8 m/s^2;
No acceleration in the x direction
It appears that once the simulation begins, y just gets bigger and bigger, so the loop will never exit by itself.
Here is the code:
//This class will handle all time consuming activities
class Simulation extends SwingWorker<Void, Void>
{
//Execute time consuming task
protected Void doInBackground() throws Exception
{
FileWriter fstream = new FileWriter("output.txt");
BufferedWriter out = new BufferedWriter(fstream);
double angle = Double.valueOf(angleText.getText());
double radians = angle * (Math.PI/180);
double vel = Double.valueOf(speedText.getText());
double mass = Double.valueOf(massText.getText());
double y = Double.valueOf(heightText.getText());
double x = 0;
double epX = Double.valueOf(epxText.getText());
double epY = Double.valueOf(epyText.getText());
double ax = Double.valueOf(accxText.getText());
double ay = Double.valueOf(accyText.getText());
int numBounces = 0;
double deltaTime = .00000001;
double total_velocity = 0.0;
double time = 0.0;
String fs;
angle = angle * Math.PI / 180;
while(numBounces < 10)
{
//Increment Time
time = time + deltaTime;
//Calculate new values for velocity[x] and velocity[y]
double vx = (vel*Math.cos(angle)) + ax*time;;
double vy = (vel*Math.sin(angle)) + ay*time;
//Calculate new values for x and y
x = x + vx*time;
y = y + vy*time + .5*ay*(time*time);
System.out.format("%.3f\n", y);
fs = String.format("%f\t %f\t %f\t %f\t %f\t %f\t %f\t\n", ax, ay, x, y, vx, vy, time);
out.write(fs);
//If ball hits ground: y < 0
if(y < 0)
{
numBounces++;
System.out.println("Number of Bounces: " + numBounces);
//Why is this statement needed if the velocity in the y direction is already being reversed?
vy = -vy - ay*time; // vy = -vy - ay*time;
//Calculate angle
angle = Math.atan(vy/vx);
angle = angle * Math.PI / 180;
//Calculate total velocity
total_velocity = Math.sqrt((vy*vy) + (vx*vx));
//Velocity with elasticity factored in
total_velocity = Math.sqrt((epY) * total_velocity);
//New velocities for when ball makes next trip
vy = total_velocity*Math.sin(angle);
vx = total_velocity*Math.cos(angle);
out.write(fs);
}
//Draw projectile
//Thread.sleep(.00001); //Sleep for deltaTime - 10 nanoseconds or draw after n number of points
}
out.close();
return null;
}
//SwingWorker lets you execute code on the event dispatching thread. Also allows you to update the GUI
public void done()
{
try
{
/*
rangeText.setText(" " + x);
heightTText.setText(" " + y);
timeText.setText(" " + time);
*/
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
What could be the possible problem?
My guess is that it might have something to do with the angle. In a previous version of the code, where I did not factor in an angle, it worked fine. Also, I am not sure if bounds on the GUI have to be set up so that y won't go on forever.
I also have a NullPointerException.
The first problem I see is here:
//Calculate angle
angle = Math.atan(vy/vx);
angle = angle * Math.PI / 180;
Math.atan returns a value in radians already:
Returns the arc tangent of a value; the returned angle is in the range -pi/2 through pi/2.
So the * Math.PI / 180 is not going to do you any favors.
The second problem is here:
//Calculate new values for velocity[x] and velocity[y]
double vx = (vel*Math.cos(angle)) + ax*time;;
double vy = (vel*Math.sin(angle)) + ay*time;
Every pass through the loop, these values are reinitialized. Because angle, ax, ay, and time cannot change during the loop, that means you always end up with the same vx and (positive) vy. vy should be getting smaller with each loop pass, something more like:
//Calculate initial values for velocity[x] and velocity[y]
double vx = (vel*Math.cos(angle)) + ax*time;
double vy = (vel*Math.sin(angle)) + ay*time;
while(numBounces < 10) {
//Increment Time
time = time + deltaTime;
//Calculate new values for x and y
x = x + vx*time;
y = y + vy*time + .5*ay*(time*time);
//Calculate new values for velocity[x] and velocity[y]
vx += ax * time;
vy += ay * time;
You need to learn to use a debugger - in Eclipse, for instance. Then you can stop wherever you want and examine variables until you figure out exactly where you're taking a wrong turn (or not taking a right one, in this case). You'll be able to figure this out in a minute or so.
If that's not an option, start putting in console printlns of key data.
Code always has errors, and you often can't figure them out just by looking at it - no matter how hard and how long.

Categories