Reflections not reflecting properly - java

I am writing a ray tracer.I am currently working on reflections.But the seem not to be reflecting correctly.I keep on getting StackOverflowError.I increased the memory and it runs now but the reflections are not like I thought the would be this.
(source: ageofarmour.com)
I thought it would Reflect the reflections!But it just ends up like this.
Note:This is after moved the normal off the object and changed the color calculations!Check the Cal_Reflection for new color calculation!
Here is my code for my tracer!
public class Tracer {
public boolean Tracing;
public Camera Cam;
public int Width, Height;
public BufferedImage Image;
public Color BackGroundColor;
public int StartX, StartY, EndX, EndY, RowCount, ColCount;
public double AmbientLight;
public double DiffuseLight;
public int MaxReflectionCount;
public ArrayList<GeometricObject> GeoObjects;
public ArrayList<LightObject> LightObjects;
public Tracer(Camera cam, int width, int height, BufferedImage image, Color backGroundColor, int startX, int startY, int endX, int endY, int rowCount, int colCount, double ambientLight, double diffuseLight, int maxReflectionCount, ArrayList<GeometricObject> geoObjects, ArrayList<LightObject> lightObjects) {
super();
Cam = cam;
Width = width;
Height = height;
Image = image;
BackGroundColor = backGroundColor;
StartX = startX;
StartY = startY;
EndX = endX;
EndY = endY;
RowCount = rowCount;
ColCount = colCount;
AmbientLight = ambientLight;
DiffuseLight = diffuseLight;
MaxReflectionCount = maxReflectionCount;
GeoObjects = geoObjects;
LightObjects = lightObjects;
}
public void TracePixelFast(int x, int y) {
Color color = new Color(BackGroundColor.r, BackGroundColor.g, BackGroundColor.b);
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, 1, 1, RowCount, ColCount), Cam.GetRayDir(Width, Height, x, y, 1, 1, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0) {
color = Cal_Pixel(x, y);
Image.setRGB(x, y, color.toInt());
break;
}
}
}
public void TracePixelSmooth(int x, int y) {
Image.setRGB(x, y, Cal_Pixel(x, y).toInt());
}
public Color Cal_Pixel(int x, int y) {
Color color = new Color(BackGroundColor);
Color colorh = new Color(BackGroundColor);
Color bgc = new Color(BackGroundColor);
int HIT = 0;
int MISS = 0;
for (int row = 0; row < RowCount; row++) {
for (int col = 0; col < ColCount; col++) {
double min = Double.MAX_VALUE;
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, row, col, RowCount, ColCount), Cam.GetRayDir(Width, Height, x, y, row, col, RowCount, ColCount));
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
double hit = GO.hit(r);
if (hit != 0.0 && hit < min) {
min = hit;
colorh = ShadePixel(0, GO, r, hit);
HIT++;
} else {
double min2 = Double.MAX_VALUE;
for (int o2 = 0; o2 < GeoObjects.size(); o2++) {
if (o != o2) {
GeometricObject GO2 = GeoObjects.get(o2);
double hit2 = GO2.hit(r);
if (hit2 != 0.0 && hit2 < min2) {
min2 = hit2;
bgc = ShadePixel(0, GO2, r, hit2);
}
}
}
MISS++;
}
}
}
}
for (int h = 0; h < HIT; h++) {
color.Add(colorh);
}
for (int m = 0; m < MISS; m++) {
color.Add(bgc);
}
color.Divide(RowCount * ColCount);
return color;
}
public Color ShadePixel(int ReflectionDepthCount, GeometricObject GO, Ray ray, double t) {
Normal normal = GO.Cal_Normal(ray, t);
if (GO.Reflectivity > 0) {
Color GoColor = new Color(Cal_Reflection(GO, ReflectionDepthCount, ray, normal));
Color finalcolor = new Color(Cal_Light(GoColor, normal));
return finalcolor;
} else {
;
Color finalcolor = new Color(Cal_Light(GO.Color, normal));
return finalcolor;
}
}
public Color Cal_Light(Color color, Normal normal) {
ArrayList<Color> PixelShade = new ArrayList<Color>();
Color Final = new Color();
for (int l = 0; l < LightObjects.size(); l++) {
LightObject light = LightObjects.get(l);
Vector3D r_Dir = light.Pos.Sub(normal.Origin);
r_Dir.normalize();
Ray raytolight = new Ray(normal.Origin, r_Dir);
int WAS_HIT = 0;
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject NGO = GeoObjects.get(o);
double hit = NGO.hit(raytolight);
if (hit != 0.0) {
WAS_HIT = 1;
}
}
PixelShade.add(light.ShadePixel(WAS_HIT, normal, r_Dir, color, AmbientLight, DiffuseLight));
}
for (int s = 0; s < PixelShade.size(); s++) {
Final.Add(PixelShade.get(s));
}
Final.Divide(PixelShade.size());
return Final;
}
public Color Cal_Reflection(GeometricObject OriginalObject, int ReflectionDepthCount, Ray InRay, Normal normal) {
if (ReflectionDepthCount <= MaxReflectionCount) {
GeometricObject LastGO = null;
Ray LastRay = null;
double LastT = 0.0;
double min = Double.MAX_VALUE;
Vector3D Origin = normal.Origin.Add(normal.Direction.Mul(1E-100));
Vector3D Direction = normal.Direction;
Direction.normalize();
Ray r = new Ray(Origin, Direction);
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
double hit = GO.hit(r);
if (hit != 0.0 && hit < min) {
min = hit;
LastGO = GO;
LastRay = r;
LastT = hit;
}
}
if (LastGO != null) {
System.out.println(ReflectionDepthCount);
Color Reflected = new Color(ShadePixel(ReflectionDepthCount++, LastGO, LastRay, LastT));
Color HitColor = new Color(LastGO.Color);
Color FinalColor = new Color(OriginalObject.Color);
Reflected.Mul(OriginalObject.Reflectivity);
HitColor.Mul(OriginalObject.Reflectivity);
FinalColor.Add(HitColor);
FinalColor.Add(Reflected);
FinalColor.Divide(2);
return FinalColor;
}
} else {
return BackGroundColor;
}
return OriginalObject.Color;
}
public void TraceArea(boolean SmoothTracing) {
Tracing = true;
if (SmoothTracing) {
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelSmooth(x, y);
}
}
} else {
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelFast(x, y);
}
}
}
}}
Here is my code for my sphere!
public class Sphere extends GeometricObject{
public Vector3D Center;
public double Radius;
public Sphere(Vector3D Center,Color Color,double Radius,double Reflectivity){
this.Center = Center;
this.Radius = Radius;
this.Color = Color;
this.Reflectivity = Reflectivity;
}
public double hit(Ray ray) {
double a = ray.Direction.Dot(ray.Direction);
double b = 2 * ray.Origin.Sub(Center).Dot(ray.Direction);
double c = ray.Origin.Sub(Center).Dot(ray.Origin.Sub(Center))-Radius*Radius;
double discreminant = b*b-4*a*c;
if(discreminant < 0.0f){
return 0.0;
}else{
double t = (-b - Math.sqrt(discreminant))/(2*a);
if(t > 10E-9){
return t;
}else{
return 0.0;
}
}
}
public Normal Cal_Normal(Ray ray,double t) {
Vector3D NPos = new Vector3D(ray.Origin.x + ray.Direction.x*t,ray.Origin.y + ray.Direction.y*t,ray.Origin.z + ray.Direction.z*t);
Vector3D NDir = NPos.Sub(Center).Div(Radius);
NDir.normalize();
return new Normal(NPos,NDir);
}}
And here is my launcher that controls the scene and tracer!
public class Launcher {
public static int Width = 600;
public static int Height = 600;
public static void main(String[] args) {
Scene scene = new Scene(Width, Height, 8, 8, new Color(0, 0, 0), new Camera(new Vector3D(0, 0, 30), new Vector3D(0.3, 0, -1), 1, true, Width, Height, 40), 0.1, 0.2, 2);
// scene.AddObject(new Sphere(new Vector3D(0,0,0),new
// Color(0,255,0),5,1));
// scene.AddObject(new Sphere(new Vector3D(-30,0,0),new
// Color(0,0,255),10,0.5));
// scene.AddObject(new Sphere(new Vector3D(30,0,0),new
// Color(255,0,0),10,0.5));
scene.AddObject(new Sphere(new Vector3D(15, 0, 0), new Color(255, 0, 0), 15, 1));
scene.AddObject(new Sphere(new Vector3D(-15, 0, 0), new Color(0, 0, 255), 15, 1));
scene.AddLight(new NonColoredLight(new Vector3D(0, 0, 20), 0.1));
long Start = System.currentTimeMillis();
BufferedImage Image = scene.Trace(false, 2);
long End = System.currentTimeMillis();
System.out.println("Milli Seconds To Render " + (End - Start));
File ImageFile = new File("TracedImage.png");
try {
ImageIO.write(Image, "PNG", ImageFile);
} catch (IOException e) {
e.printStackTrace();
}
}}
And here is the scene code!
public Scene(int width, int height, int row, int col, Color backGroundColor, Camera cam, double ambientLight, double diffuseLight, int maxReflectionCount) {
super();
Width = width;
Height = height;
Row = row;
Col = col;
BackGroundColor = backGroundColor;
Cam = cam;
AmbientLight = ambientLight;
DiffuseLight = diffuseLight;
MaxReflectionCount = maxReflectionCount;
GeoObjects = new ArrayList<GeometricObject>();
LightObjects = new ArrayList<LightObject>();
if (ambientLight > 1) {
AmbientLight = 1;
} else if (ambientLight < 0) {
AmbientLight = 0;
} else {
AmbientLight = ambientLight;
}
if (diffuseLight > 1) {
DiffuseLight = 1;
} else if (diffuseLight < 0) {
DiffuseLight = 0;
} else {
DiffuseLight = ambientLight;
}
}
public void AddObject(GeometricObject GO) {
GeoObjects.add(GO);
}
public void AddLight(LightObject Light) {
LightObjects.add(Light);
}
public BufferedImage Trace(boolean SmoothTracing, int ThreadCount) {
Image = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);
Tracer tracer = new Tracer(Cam, Width, Height, Image, BackGroundColor, 0, 0, Width, Height, Row, Col, AmbientLight, DiffuseLight, MaxReflectionCount, GeoObjects, LightObjects);
tracer.TraceArea(SmoothTracing);
return Image;
}}
If you need me to post any more of my code just let me know!
Thanks in advance!
Variables for first reflection!
AmbientLight 0.1
BackGroundColor Color (id=39)
b 0.0
g 0.0
r 0.0
Cam Camera (id=41)
Direction Vector3D (id=104)
x 0.3
y 0.0
z -1.0
Distance 357.526077778263
FOV 40.0
Height 600
Perspective true
PixelSize 1.0
Pos Vector3D (id=115)
x 0.0
y 0.0
z 30.0
u Vector3D (id=116)
x -0.9578262852211514
y 0.0
z -0.28734788556634544
v Vector3D (id=117)
x 0.0
y 1.0
z 0.0
w Vector3D (id=118)
x 0.2873478855663454
y 0.0
z -0.9578262852211513
Width 600
ColCount 8
DiffuseLight 0.1
EndX 600
EndY 600
GeoObjects ArrayList<E> (id=43)
[0] Sphere (id=26)
[1] Sphere (id=34)
Height 600
Image BufferedImage (id=50)
accelerationPriority 0.5
colorModel DirectColorModel (id=120)
imageType 1
osis null
properties null
raster IntegerInterleavedRaster (id=124)
surfaceManager null
LightObjects ArrayList<E> (id=59)
[0] NonColoredLight (id=88)
MaxReflectionCount 2
RowCount 8
StartX 0
StartY 0
Tracing true
Width 600
OriginalObject Sphere (id=26)
Center Vector3D (id=60)
Color Color (id=61)
Radius 15.0
Reflectivity 1.0
ReflectionDepthCount 0
InRay Ray (id=29)
Direction Vector3D (id=62)
Origin Vector3D (id=63)
normal Normal (id=31)
Direction Vector3D (id=38)
Origin Vector3D (id=36)
LastGO Sphere (id=34)
Center Vector3D (id=64)
Color Color (id=65)
Radius 15.0
Reflectivity 1.0
LastRay Ray (id=35)
Direction Vector3D (id=38)
Origin Vector3D (id=36)
LastT 4.2468950498166125
min 4.2468950498166125
Origin Vector3D (id=36)
x 0.5809721247344103
y -0.023188722729640822
z 0.8135930637731328
Direction Vector3D (id=38)
x -0.32494278056317
y -0.02694400302823308
z 0.9453497818589108
r Ray (id=35)
Direction Vector3D (id=38)
Origin Vector3D (id=36)
Project Zip File

You are reflecting your ray exactly on the surface of the object. When checking intersections with the reflected ray, you hit on the same object again. You assume that checking if the distance is equal to 0.0 is enough to avoid this, but FP numbers are trickier than you think...

Related

Draw intersection of two regions in JavaFX

I have a few restrictions type of a ax+by>=c (1) and x>=z and y>=k (2). Restrictions (1) and (2) make a regions. I need to find the intersection of this regions and fill that other color. How can I do it in JavaFX? Can I use Canvas for solve this?
Sure, just fill everything with the polygon color and then for each area fill everything not in the area with the background color.
Note that this way you fill the whole Canvas except for the polygon with the background color.
public class Area {
private final double x;
private final double y;
private final double threshold;
private final int minCorner;
public Area(double x, double y, double threshold, boolean greater) {
if (x == 0 && y == 0) {
throw new IllegalArgumentException();
}
if (greater) {
x *= -1;
y *= -1;
threshold *= -1;
}
this.x = x;
this.y = y;
this.threshold = threshold;
boolean yPos = y > 0;
// find corner with minimum result for evaluate
this.minCorner = x < 0 ? (yPos ? 1 : 2) : (yPos ? 0 : 3);
}
public Area(double x, double y, double threshold) {
this(x, y, threshold, false);
}
private static final int[][] CORNER_FACTORS = {
{0, 0},
{1, 0},
{1, 1},
{0, 1}
};
public boolean contains(double x, double y) {
return evaluate(x, y) <= threshold;
}
public double hLineIntersection(double y) {
if (x == 0) {
return this.y * y == threshold ? Double.POSITIVE_INFINITY : Double.NaN;
} else {
return (threshold - this.y * y) / this.x;
}
}
public double vLineIntersection(double x) {
if (y == 0) {
return this.x * x == threshold ? Double.POSITIVE_INFINITY : Double.NaN;
} else {
return (threshold - this.x * x) / this.y;
}
}
private double evaluate(double x, double y) {
return this.x * x + this.y * y;
}
public void fillCleanArea(GraphicsContext gc, double w, double h) {
double[] xcoords = new double[5];
double[] ycoords = new double[5];
int[] factors = CORNER_FACTORS[minCorner];
boolean inside = contains(factors[0] * w, factors[1] * h);
int ptIndex = 0;
for (int i = minCorner, max = minCorner + 4; i < max; i++) {
factors = CORNER_FACTORS[i % 4];
double x = factors[0] * w;
double y = factors[1] * h;
boolean nowInside = contains(x, y);
if (inside != nowInside) {
// add intersection point with side
if ((i & 1) == 0) {
ycoords[ptIndex] = vLineIntersection(x);
xcoords[ptIndex++] = x;
} else {
xcoords[ptIndex] = hLineIntersection(y);
ycoords[ptIndex++] = y;
}
inside = nowInside;
// stop, if the end point is inside the area again
if (inside) {
break;
}
}
// add corners outside the bounds to polygon
if (!inside) {
xcoords[ptIndex] = x;
ycoords[ptIndex++] = y;
}
}
// draw polygon
if (ptIndex > 0) {
gc.fillPolygon(xcoords, ycoords, ptIndex);
}
}
}
public static void draw(Canvas canvas, Paint fill, Paint background, Area... areas) {
GraphicsContext gc = canvas.getGraphicsContext2D();
double w = canvas.getWidth();
double h = canvas.getHeight();
// fill everything with polygon color
gc.setFill(fill);
gc.fillRect(0, 0, w, h);
// fill everything outside the polygon with background color
gc.setFill(background);
for (Area area : areas) {
area.fillCleanArea(gc, w, h);
}
}
#Override
public void start(Stage primaryStage) {
Canvas canvas = new Canvas(400, 400);
draw(canvas, Color.BLUE, Color.WHITE,
new Area(1, 1, 400), new Area(1, -1, 100), new Area(1, -1, -100, true), new Area(1, 2, 250, true));
StackPane root = new StackPane(canvas);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
This won't give you the polygon's corner points though...

Raytracing: Dark rings appear

I am getting strange rings of black on my spheres when I render with lighting. I just added lighting and I cannot figure out why the black rings are being created.
Here is my code for my tracer.
public class Tracer {
public Camera Cam;
public int Width, Height;
public BufferedImage Image;
public Color BackGroundColor;
public int StartX, StartY, EndX, EndY,RowCount,ColCount;
public ArrayList<GeometricObject> GeoObjects;
public ArrayList<LightObject> LightObjects;
public boolean Tracing;
public double AmbientLight;
public Tracer(Camera cam, int width, int height, BufferedImage image, Color backGroundColor, int startX, int startY, int endX, int endY, int rowCount, int colCount, ArrayList<GeometricObject> Geoobjects,ArrayList<LightObject> Lightobjects,double ambientLight) {
super();
Cam = cam;
Width = width;
Height = height;
Image = image;
BackGroundColor = backGroundColor;
StartX = startX;
StartY = startY;
EndX = endX;
EndY = endY;
RowCount = rowCount;
ColCount = colCount;
GeoObjects = Geoobjects;
LightObjects = Lightobjects;
if(ambientLight > 1){
AmbientLight = 1;
}else if(ambientLight < 0){
AmbientLight = 0;
}else{
AmbientLight = ambientLight;
}
}
public void TracePixelFast(int x, int y) {
Color color = new Color(BackGroundColor.r,BackGroundColor.g,BackGroundColor.b);
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, 1, 1, RowCount, ColCount), Cam.GetRayDir(Width, Height, x, y, 1,1, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0) {
color = Cal_Pixel(x,y);
Image.setRGB(x, y, color.toInt());
break;
}
}
}
public void TracePixelSmooth(int x, int y) {
Image.setRGB(x, y,Cal_Pixel(x,y).toInt());
}
public Color Cal_Pixel(int x,int y){
Color color = new Color(BackGroundColor);
Color colorh = new Color(BackGroundColor);
Color bgc = new Color(BackGroundColor);
int HIT = 0;
int MISS = 0;
for (int row = 0; row < RowCount; row++) {
for (int col = 0; col < ColCount; col++) {
double min = Double.MAX_VALUE;
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, row, col, RowCount, ColCount),Cam.GetRayDir(Width, Height, x, y, row, col, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0 && hit < min) {
min = hit;
colorh = ShadePixel(GO, r, hit);
HIT++;
} else {
double min2 = Double.MAX_VALUE;
for (int o2 = 0; o2 < GeoObjects.size(); o2++) {
if(o!=o2){
GeometricObject GO2 = GeoObjects.get(o2);
double hit2 = GO2.hit(r);
if (hit2 != 0.0 && hit2 < min2) {
min2 = hit2;
bgc = ShadePixel(GO2, r, hit2);
}
}
}
MISS++;
}
}
}
}
for(int h = 0;h < HIT;h++){
color.Add(colorh);
}
for(int m = 0;m < MISS;m++){
color.Add(bgc);
}
color.Divide(RowCount * ColCount);
return color;
}
public Color ShadePixel(GeometricObject GO,Ray ray,double t){
ArrayList<Color> PixelShade = new ArrayList<Color>();
Normal normal = GO.Cal_Normal(ray, t);
for(int l = 0;l < LightObjects.size();l++){
LightObject light = LightObjects.get(l);
Vector3D r_Dir = light.Pos.Sub(normal.Origin);
r_Dir.normalize();
Ray raytolight = new Ray(normal.Origin,r_Dir);
int WAS_HIT = 0;
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject NGO = GeoObjects.get(o);
double hit = NGO.hit(raytolight);
if (hit != 0.0) {
WAS_HIT = 1;
}
}
if(WAS_HIT == 0){
double Dot = normal.Direction.Dot(r_Dir);
if(Dot < 0){
Dot = 0;
}
double Diffuse = 1 - AmbientLight;
Color color = new Color(GO.Color);
double Shade = AmbientLight + Diffuse*Dot;
color.Mul(Shade);
PixelShade.add(color);
}else{
Color color = new Color(GO.Color);
double Shade = AmbientLight;
color.Mul(Shade);
PixelShade.add(color);
}
}
Color Final = new Color();
for(int s = 0;s < PixelShade.size();s++){
Final.Add(PixelShade.get(s));
}
Final.Divide(PixelShade.size());
return Final;
}
public void TraceArea(boolean SmoothTracing) {
Tracing = true;
if(SmoothTracing){
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelSmooth(x,y);
}
}
}else{
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelFast(x,y);
}
}
}
}
}
And here is the code for the sphere.
public class Sphere extends GeometricObject{
public Vector3D Center;
public double Radius;
public Sphere(Vector3D Center,double Radius,Color Color){
this.Center = Center;
this.Radius = Radius;
this.Color = Color;
}
public double hit(Ray ray) {
double a = ray.Direction.Dot(ray.Direction);
double b = 2 * ray.Origin.Sub(Center).Dot(ray.Direction);
double c = ray.Origin.Sub(Center).Dot(ray.Origin.Sub(Center))-Radius*Radius;
double discreminant = b*b-4*a*c;
if(discreminant < 0.0f){
return 0.0;
}else{
double t = (-b - Math.sqrt(discreminant))/(2*a);
if(t > 10E-9){
return t;
}else{
return 0.0;
}
}
}
public Normal Cal_Normal(Ray ray,double t) {
Vector3D NPos = new Vector3D(ray.Origin.x + ray.Direction.x*t,ray.Origin.y + ray.Direction.y*t,ray.Origin.z + ray.Direction.z*t);
Vector3D NDir = NPos.Sub(Center).Div(Radius);
return new Normal(NPos,NDir);
}
}
I am sure the problem is in shadepixel() but I could be wrong.
I just found out that the more objects that I add the more rings there are:
1 object no rings.
2 objects 1 ring.
3 objects 2 rings.
If you need me to post more of my code.Just ask and I will.
When I get back from school I will post my color class and fix the color problem. I still do not understand why the more objects (spheres) I add, the more rings there are. Can anyone explain to me why this is happening?
Here is my Color code.
public class Color {
public float r,g,b;
public Color(){
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
public Color(float fr,float fg,float fb){
r = fr;
g = fg;
b = fb;
}
public Color(Color color){
r = color.r;
g = color.g;
b = color.b;
}
public void Add(Color color){
r += color.r;
g += color.g;
b += color.b;
}
public void Divide(int scalar){
r /= scalar;
g /= scalar;
b /= scalar;
}
public void Mul(double mul){
r *= mul;
g *= mul;
b *= mul;
}
public int toInt(){
return (int) (r*255)<<16 | (int) (g*255)<<8 | (int) (b*255);
}
There are multiple issues with this code, but the direct reason for the rings is that color component values are overflowing 0-255 range. This in turn is caused by incorrect calculations in what I take to be an attempt at antialiasing in Cal_Pixel(), as well as by no control whatsoever of numeric range in ShadePixel().
Think about how you can visually debug this scene.
First are the normals correct? Display them as the colour to see.
Taking the range for each component [-1..1] to the range [0..255]:
r = 255*(n.x + 1)/2;
g = 255*(n.y + 1)/2;
b = 255*(n.z + 1)/2;
Once you think they look correct move on to the next stage and build it up stage by stage.
e.g. you might look at if your dot product is as expected (again [-1..1] because the vectors are supposedly normalised):
r = 255*(dot + 1)/2;
g = 255*(dot + 1)/2;
b = 255*(dot + 1)/2;

Writing a Raytracer, and cant get the image to be centred properly?

I'm writing a Raytracer in Java, I've gotten to the point where I can create objects, rays, test for intersections and then colour pixels. I've also got some basic anti aliasing done. My problem is that if a create a sphere, which should be in the centre of the world (i.e 0.0, 0.0, 0.0) and then draw the image, I end up with a picture like this.
When the red circle should be in the middle of the image.
Main method
public static void main(String[] args) {
System.out.println("Rendering...");
long start = System.nanoTime();
// Setting up the size of the image to be rendered
world = new World(1920, 1080, 1.0);
image = new Image("image.png");
sampler = new SimpleSampler(4);
projector = new OrthographicProjector();
// Main loop of program, goes through each pixel in image and assigns a colour value
for (int y = 0; y < world.viewPlane.height; y++) {
for (int x = 0; x < world.viewPlane.width; x++) {
// Render pixel colour
trace(x, y);
}
}
image.saveImage("PNG");
long end = System.nanoTime();
System.out.print("Loop Time = " + ((end - start)/1000000000.0f));
}
Trace method
public static void trace(int x, int y) {
Colour colour = new Colour();
//int colour = RayTracer.world.backgroundColour.toInteger();
for (int col = 0; col < sampler.samples; col++) {
for (int row = 0; row < sampler.samples; row++) {
Point2D point = sampler.sample(row, col, x, y);
Ray ray = projector.createRay(point);
double min = Double.MAX_VALUE;
Colour tempColour = new Colour();
for (int i = 0; i < world.worldObjects.size(); i++) {
double temp = world.worldObjects.get(i).intersect(ray);
if (temp != 0 && temp < min) {
min = temp;
tempColour = world.worldObjects.get(i).colour;
}
}
colour.add(tempColour);
}
}
colour.divide(sampler.samples*sampler.samples);
image.buffer.setRGB(x, y, colour.toInteger());
}
World.java
public class World {
public ViewPlane viewPlane;
public ArrayList<Renderable> worldObjects;
public Colour backgroundColour;
public World(int width, int height, double size) {
viewPlane = new ViewPlane(width, height, size);
backgroundColour = new Colour(0.0f, 0.0f, 0.0f);
worldObjects = new ArrayList<Renderable>();
worldObjects.add(new Sphere(new Point3D(0.0, 0.0, 0.0), 50, new Colour(1.0f, 0.0f, 0.0f)));
//worldObjects.add(new Sphere(new Point3D(-150.0, 0.0, 0.0), 50, new Colour(1.0f, 0.0f, 0.0f)));
//worldObjects.add(new Sphere(new Point3D(0.0, -540.0, 0.0), 50, new Colour(0.0f, 1.0f, 0.0f)));
}
}
SimpleSampler.java
public class SimpleSampler extends Sampler {
public SimpleSampler(int samples) {
this.samples = samples;
}
public Point2D sample(int row, int col, int x, int y) {
Point2D point = new Point2D(
x - RayTracer.world.viewPlane.width / 2 + (col + 0.5) / samples,
y - RayTracer.world.viewPlane.width / 2 + (row + 0.5) / samples);
return point;
}
}
OrthographicProjector.java
public class OrthographicProjector extends Projector{
public Ray createRay(Point2D point) {
Ray ray = new Ray();
ray.origin = new Point3D(
RayTracer.world.viewPlane.size * point.x,
RayTracer.world.viewPlane.size * point.y,
100);
ray.direction = new Vector3D(0.0, 0.0, -1.0);
return ray;
}
}
I have a feeling that somewhere along the way I've mixed an x with a y and this has rotated the image, but I haven't been able to track down the problem. If you would like to see any more of my code I would be happy to show it.
In SimpleSampler.java:
Point2D point = new Point2D(
x - RayTracer.world.viewPlane.width / 2 + (col + 0.5) / samples,
y - RayTracer.world.viewPlane.width / 2 + (row + 0.5) / samples);
You use width for both coordinates. Maybe you should use width and height.

How to make circle clickable

I am developing game using canvas. I have drawn grid of circles using loop. I want to get x,y coordinates of circles. For that I have to make those circles clickable so that whenever player click on a circle it should return its coordinates. I will pass those coordinates to lineDraw() method for drawing line between those circles.
This loop is defining grid of circles:
for (int y=0;y<rows;y++)
{
for (int x=0;x<cols;x++)
{
canvas.drawCircle((x + 1) * dw, (y + 1) *(3* dh), 20, pDot);
}
}
Here dw is (displayWidth) and dh is (displayHeight). Please suggest how I should make these circles clickable?
I had played with this project a little after your previous questions. I'm sure this isn't the most optimized way to do this, but without knowing how you plan to implement the game logic, I think this is flexible enough to adapt. The following is your custom View class, which I've renamed Board, in keeping with Java naming conventions.
public class Board extends View
{
Paint pBack = new Paint();
Paint pDot = new Paint();
Paint pLine = new Paint();
int cols = 5;
int rows = 6;
// Default initialization = false
boolean[][] dots = new boolean[cols][rows];
int canWidth = 0;
int canHeight = 0;
float xStep = 0;
float yStep = 0;
float[] xCoords = new float[cols];
float[] yCoords = new float[rows];
public Board(Context context)
{
super(context);
pBack.setARGB(255, 255, 102, 0);
pDot.setARGB(255, 255, 255, 255);
pLine.setStrokeWidth(5);
pLine.setARGB(255, 90, 10, 0);
}
public void setDots(boolean[][] dotSelected)
{
this.dots = dotSelected;
}
public boolean[][] getDots()
{
return dots;
}
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
canWidth = w;
canHeight = h;
xStep = canWidth / (cols + 1);
yStep = canHeight / (rows + 1);
for (int y = 0; y < rows; y++)
{
yCoords[y] = (y + 1) * yStep;
}
for (int x = 0; x < cols; x++)
{
xCoords[x] = (x + 1) * xStep;
}
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawPaint(pBack);
// Grid, lines and box markings
for (int y = 0; y < rows; y++)
{
canvas.drawLine(xStep, yCoords[y], cols * xStep, yCoords[y], pDot);
for (int x = 0; x < cols; x++)
{
if (y == 0)
{
canvas.drawLine(xCoords[x], yStep, xCoords[x], rows * yStep, pDot);
}
if (dots[x][y])
{
boolean left = x > 0 && dots[x - 1][y];
boolean up = y > 0 && dots[x][y - 1];
if (left)
{
canvas.drawLine(xCoords[x], yCoords[y], xCoords[x - 1], yCoords[y], pLine);
}
if (up)
{
canvas.drawLine(xCoords[x], yCoords[y], xCoords[x], yCoords[y - 1], pLine);
}
if (left && up && dots[x - 1][y - 1])
{
canvas.drawCircle(xCoords[x] - xStep / 2, yCoords[y] - yStep / 2, 10, pLine);
}
}
}
}
// Dots
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
canvas.drawCircle(xCoords[x], yCoords[y], 20, pDot);
if (dots[x][y])
{
canvas.drawCircle(xCoords[x], yCoords[y], 15, pBack);
}
}
}
}
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
if (event.getAction() != MotionEvent.ACTION_DOWN)
return true;
int xNear = 0;
int yNear = 0;
float xMin = canWidth;
float yMin = canHeight;
for (int x = 0; x < cols; x++)
{
if (Math.abs(xCoords[x] - event.getX()) < xMin)
{
xMin = Math.abs(xCoords[x] - event.getX());
xNear = x;
}
}
for (int y = 0; y < rows; y++)
{
if (Math.abs(yCoords[y] - event.getY()) < yMin)
{
yMin = Math.abs(yCoords[y] - event.getY());
yNear = y;
}
}
dots[xNear][yNear] = !dots[xNear][yNear];
invalidate();
return true;
}
}
Store the data of your circles (for instance the position and the radius) in a list and check each of them for mouse collision(register a mouseeventlistener).
public class Circle
{
private int radius;
private int positionX;
private int positionY;
public Circle(int positionX, int positionY, int radius)
{
this.radius = radius;
this.positionX = positionX;
this.positionY = positionY;
}
public int getPositionX()
{
return this.positionX;
}
public int getPositionY()
{
return this.positionY;
}
public boolean contains(int posX, int posY)
{
int distanceX = this.positionX - posX;
int distanceY = this.positionY - posY;
return Math.sqrt((distanceX * distanceX) + (distanceY * distanceY)) <= this.radius;
}

SVG or Vector base data to Shape

So I am trying to create a tool that can convert a .svg file type to a Java Shape or Some kind of class that will allow me to do .contains(x, y) or .contains(Rectangle2D). However I have been unable to find any methods of doing such. I found this post SVG to Java's Path2d parser this seems to give the answer but doesn’t explicitly describe how. I took a look at the classes and don't see how I would load a file then convert it to a shape. I was originally doing this with any kind of image but it turned out to be impractical and really slow. Code for that:
public static Area toArea(URL url, Color color, int tolerance) {
return toArea(toBufferedImage(url), color, tolerance);
}
public static Area toArea(Image image, Color color, int tolerance) {
return toArea(toBufferedImage(image), color, tolerance);
}
/**
* Creates an Area with PixelPerfect precision
*
* #param image
* #param color The color that is draws the Custom Shape
* #param tolerance The color tolerance
* #return Area
*/
public static Area toArea(BufferedImage image, Color color, int tolerance) {
if (image == null) {
return null;
}
Area area = new Area();
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
Color pixel = new Color(image.getRGB(x, y));
if (isIncluded(color, pixel, tolerance)) {
Rectangle r = new Rectangle(x, y, 1, 1);
area.add(new Area(r));
}
}
}
return area;
}
public static Area toArea(URL url) {
return toArea(toBufferedImage(url));
}
public static Area toArea(Image image) {
return toArea(toBufferedImage(image));
}
public static Area toArea(BufferedImage image) {
//Assumes Black as Shape Color
if (image == null) {
return null;
}
Area area = new Area();
Rectangle r;
int y1, y2;
for (int x = 0; x < image.getWidth(); x++) {
y1 = 99;
y2 = -1;
for (int y = 0; y < image.getHeight(); y++) {
Color pixel = new Color(image.getRGB(x, y));
//-16777216 entspricht RGB(0,0,0)
if (pixel.getRGB() == -16777216) {
if (y1 == 99) {
y1 = y;
y2 = y;
}
if (y > (y2 + 1)) {
r = new Rectangle(x, y1, 1, y2 - y1);
area.add(new Area(r));
y1 = y;
y2 = y;
}
y2 = y;
}
}
if ((y2 - y1) >= 0) {
r = new Rectangle(x, y1, 1, y2 - y1);
area.add(new Area(r));
}
}
return area;
}
private static boolean isIncluded(Color target, Color pixel, int tolerance) {
int rT = target.getRed();
int gT = target.getGreen();
int bT = target.getBlue();
int rP = pixel.getRed();
int gP = pixel.getGreen();
int bP = pixel.getBlue();
return ((rP - tolerance <= rT) && (rT <= rP + tolerance)
&& (gP - tolerance <= gT) && (gT <= gP + tolerance)
&& (bP - tolerance <= bT) && (bT <= bP + tolerance));
}
public static BufferedImage toBufferedImage(Image image) {
BufferedImage buffer = new BufferedImage(image.getHeight(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
buffer.createGraphics().drawImage(image, null, null);
return buffer;
}
public static BufferedImage toBufferedImage(URL url) {
try {
return toBufferedImage(ImageIO.read(url));
} catch (IOException ex) {
return null;
}
}
private ImageShaper() {
}
Basically I am trying to write a function that can load a file that stores an irregular shape like a batman logo and then have it able to run a contains function to see if something hit it.

Categories

Resources