Ray-tracer loop ordering - raytracing

Tracer and found an unexpected problem. If I write the two main loops of the ray-tracer, the ones responsible for the image pixels, that way:
for (int y=0; y<image.getWidth(); y++) {
for (int x=0; x<image.getHeight(); x++) {
I get this distorted image. (actually, facebook screws the image, somehow, even more than the real one, but the point is that the code generates multiple mirrored spheres with some kind of scanlines (that are actually smaller)
http://s72.photobucket.com/user/john_smith140/media/zz_zps907cb287.jpeg.html?filters[user]=139318132&filters[recent]=1&sort=1&o=0
However if, if I make a small change, to:
for (int y=0; y<image.getHeight(); y++) {
for (int x=0; x<image.getWidth(); x++) {
It works as a charm, as can be seen below:
http://s72.photobucket.com/user/john_smith140/media/s_zps4e50e49f.jpeg.html?filters[user]=139318132&filters[recent]=1&sort=1&o=1
The getHeight, getWidth gives me the height and width of the image.
Here is some more code that I believe might be helpful:
Ray viewRay = { {float(x), float(y), -1000.0f}, { 0.0f, 0.0f, 1.0f}};
The first part is the camera location, the second it's direction
I don't know why this is happening and would appreciate any input. If any more code is necessary to evaluates the problem, just ask.

The problem is that although you're changing the order of the for-loop, you aren't changing the indices. You should try:
for (int x=0; x<image.getWidth(); x++) {
for (int y=0; y<image.getHeight(); y++) {
Compare that with the two snippets you posted.

Related

Using Processing for image visualization: pixel color thresholds

Image to be manipulated, hoping to identify each white dot on each picture with a counter
PImage blk;
void setup() {
size(640, 480);
blk=loadImage("img.png");
}
void draw () {
loadPixels();
blk.loadPixels();
int i = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int loc = x+y*width;
pixels [loc] = blk.pixels[loc];
if (blk.pixels[loc] == 0) {
if (blk.pixels [loc]+1 != 0) {
i++;
}
}
float r = red(blk.pixels[loc]);
float g = green(blk.pixels[loc]);
float b = blue(blk.pixels[loc]);
pixels [loc] = color(r, g, b);
}
}
System.out.println (i);
updatePixels();
}
The main problem is within my if statement, not sure to approach it logically.
I'm unsure where this is exactly going, but I can help you find the white pixels. Here, I just counted 7457 "white" pixels (then I turned them red so you can see where they are and adjust the threshold if you want to get more or less of them):
Of course, this is just a proof of concept which you should be able to adapt to your needs.
PImage blk;
void setup() {
size(640, 480);
blk=loadImage("img.png");
blk.loadPixels();
int whitePixelsCount = 0;
// I'm doing this in the 'setup()' method because I don't need to do it 60 times per second
// Once it's done once I can just use the image as modified unless you want several
// different versions (which you can calculate once anyway then store in different PImages)
for (int i = 0; i < blk.width * blk.height; i++) {
float r = red(blk.pixels[i]);
float g = green(blk.pixels[i]);
float b = blue(blk.pixels[i]);
// In RGB, the brightness of each color is represented by it's intensity
// So here I'm checking the "average intensity" of the color to see how bright it is
// And I compare it to 100 since 255 is the max and I wanted this simple, but you can
// play with this threshold as much as you like
if ((r+g+b)/3 > 100) {
whitePixelsCount++;
// Here I'm making those pixels red so you can see where they are.
// It's easier to adjust the threshold if you can see what you're doing
blk.pixels[i] = color(255, 0, 0);
}
}
println(whitePixelsCount);
updatePixels();
}
void draw () {
image(blk, 0, 0);
}
In short (you'll read this in the comments too), we count the pixels according to a threshold we can adjust. To make things more obvious for you, I colored the "white" pixels red. You can lower or raise the threshold according to what you see this way, and once you know what you want you can get rid of the color.
There is a difficulty here, which is that the image isn't "black and white", but more greyscale - which is totally normal, but makes things harder for what you seem to be trying to do. You'll probably have to tinker a lot to get to the exact ratio which interests you. It could help a lot if you edited the original image in GiMP or another image software which lets you adjust contrast and brightness. It's kinda cheating, but it it doesn't work right off the bat this strategy could save you some work.
Have fun!

How to make randomly placed ellipses loop in p5.js?

I'm trying to make a loop in p5.js that will draw small ellipses across the canvas. I've done something like this before, but the code was different.
There, when I wanted to try a loop, all I had to type was:
for (var i = 0; i < 200; i++) {}
The manual I'm using (Make: Getting Started with p5.js) tells me that the code to do this is similiar. This was an example it gave for drawing a bunch of lines:
for (var i = 20; i < 400; i += 8) {
line(i,40,i+60,80)
}
However, when I enter this code to even test it, it doesn't work. Can someone explain how to draw multiple small ellipses on the screen (I have variables set in place for the x and y coordinates of the ellipses so that they will be random)?
EDIT: This is a more full version of the code:
function draw() {
noStroke();
fill(fishCr,fishCg,fishCb);
arc(ellX,ellY,ellW,ellH,0,180);
arc(ellX+5,ellY-10,ellW/1.5,ellH/1.5,arcEl,50);
arc(ellX-45,ellY+20,ellW/1.5,ellH*1.5,340,110);
arc(ellX-60,ellY-10,ellW/1.5,ellH*2,arcT,40);
fill(0,200,255,0.5); //this is the start of the code in
//question
for (var i = 0; i < 200; i++) {
ellipse(bubX,bubY,5,5);
}
}
Please try to be more specific than saying it doesn't work. What exactly happens? What do you see in the JavaScript console?
You should also read up on a tutorial on for loops. Here is one I wrote for Processing, but the basic ideas are the same.
Your first for loop starts at 0 and increases by 1 until it reaches 200. Your second for loop starts at 20 and increases by 8 until it reaches 400.
Also note that you have an extra opening curly brace { in your second for loop.
If you still can't get it figured out, please post a MCVE that shows the problem. Good luck.
Edit: Take a look at your for loop:
for (var i = 0; i < 200; i++) {
ellipse(bubX,bubY,5,5);
}
Here you're drawing 200 circles, but you're drawing all of them at the same location, based on the bubX and bubY variables. You probably want to pass in random values here instead of the same variables every time.
createCanvas(500, 500);
function setup() {
for (var i = 0; i < 200; i++) {
ellipse(random(0, width), random(0, height), 5);
}
}
This creates a Canvas and draws 200 small circles at random locations.
Is this waht you are looking for?

Processing Particle Sprites

I am trying to copy particles from an image onto a sprite square that falls to the bottom of the screen for a homework assignment. The part I am having the most trouble with is copying the pixels from my background image to my sprite. I'm not really sure how to start but I know I should include things like
for (int x=0; x< img.width; x++)
{
for (int y=0; x< img.height; y++)
{
int loc = x + y*img.width;
...
}
}
and
PImage.pixel[index]
Shameless self-promotion: I've written a tutorial on images in Processing available here.
Using a nested for loop to iterate over the pixels in the image is a good start. From there you need to use the get() function in the PImage class to get the color at a particular pixel. Then you can use the set() function to set the pixels of the target image or PGraphics.
More info is available in the Processing reference.

How do only update pixels once

My pixels are updating every frame causing the effect to be re-applied to the previous frame. How can i make this effect only happen once and without using noLoop(). I just want there to be a large circle around the triangle. Please help. Thanks.
Here is the whole program. I set the frameRate to 1 so you can see the problem easier:
boolean up;
int x =-300;
int y =-300;
void setup()
{
size(600, 600);
frameRate(1);
}
void draw()
{
pushMatrix();
translate(300, 300);
float a = atan2(mouseY-300, mouseX-300);
rotate(a);
for (int i = x; i < x+width; i+=40)
for (int j = y; j < y+height; j+=40)
rect(i, j, 40, 40);
loadPixels();
for (int i = 0; i < pixels.length; i++)
{
x = i%width;
y = i/width;
color c = pixels[x+y*width];
float d = dist(x, y, width/2, height/2);
pixels[x+y*width] = color(brightness(c) - d);
}
updatePixels();
popMatrix();
fill(255, 0, 0);
triangle(280, 300, 300, 200, 320, 300);
if (up)
{
x += sin(a)*5;
y += cos(a)*5;
}
}
void keyPressed()
{
if (key=='w')up=true;
}
void keyReleased()
{
if (key=='w')up=false;
}
Re-draw everything in one frame.
Remember before you use your filter, you must undo the filter effects of the last time.
The usual ordering in your draw() function goes as follows:
Add a background / clear all the objects you added in the last frame & clearing the filter of your last frame.
Add your objects.
Lay your filter on top.
Try to refrain from doing any graphic related stuff in setup, hence it will be destroyed by this draw() function - paradigma.
This should already suffice as your answer. Quick note:
When you work with for e.g. a 3D - Shadow filter, applying the filter can take a very long time. Instead we try to store as many calculations we did on the previous frame, so we don't need to calculate everything over again. The same goes for the objects-layer. You don't want to calculate the shortest-path for a minion every frame, instead you calculate the shortest path once and only recalculate it, when something changes: Position of a box, player position, etc..
If you want just use your filter and move fluently around update your effect like this:
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
color c = pixels[x+y*width];
float d = dist(x, y, width/2, height/2);
pixels[x+y*width] = color(brightness(c) - d);
}
}
You had unnecessary calculation that consume lot of CPU resources. Redrawing background also helps to make clearer animation.
If you want generate this effect only once and then apply it. PGraphics could achieve something similar.

XNA changing 200 or so tiles pixels

Hey guys i thought this was going to be a 1second thing to do, currently i have a tileset for a 2d game and depending on the terrain it calls these tile sets. and the tile sets are colour coded pink is the material and blue is the material adjacent to the tile.
so far when terrain changes or on load up i draw the tiles on the screen and any new tiles as i move. this is all fine and works very well, but when i have like 50 grass tiles that need to be changed from pink to green and 75 dirt tiles which need to be changed from pink to grey i have a issue.
it only appears the first tile is changed then every other tile infront or before that tile is the same colour as the first colour.
ill give you an example in code what im doing
Color[] storePixels = new Color[50 * 50];
for(int y = 0; y < 100; y ++)
{
for(int x = 0; x < 100; x++)
{
tileTexture[y,x].GetData(storePixels);
for(int i = 0; i < storePixels.Length; i ++)
{
if(tileMaterial[y,x] == "DIRT")
{
storePixels[i] = new Color(100,100,100);
}
if(tileMaterial[y,x] == "GRASS")
{
storePixels[i] = new Color(0,255,0);
}
}
tileTexture[y,x].SetData(storePixels);
}
}
To me i cant see why this wont work. i assume maybe i need to reset the storePixels which i have tried but still it does not create green if its grass or grey if its dirt.
Please let me know if you know why this is not working thank you for your time and thank you in advance :)
OK! i figured it out im calling the same Image in my content folder
for(int y = 0; y < 100; y ++)
{
for(int x = 0; x < 100; x ++)
{
tileTexture[y,x] = Content.Load<Texture2D>("tile");
}
}
so now we are getting somewere we know why the problem is being cuassed as i change the Texture2D through SetData() it actually changes this tile texture2D directly and everything else that calls it will always be changed.
i cannot call it in a loop, i only call it at startup i could try store a copy of the texture2D and then change it.
i dunno does anyone have any further solutions to help solve this problem? thanks for you time :)
for(int y = 0; y < 100; y++)
{
for(int x = 0; x < 100; x++)
{
spriteBatch.Draw(tileTexture[y,x],rectangle,Color.White);
}
}
this is how i am drawing my grid
That code is a bad idea...
you can work with only one white texture...
WhiteTex = new Texture2D(GraphicsDevice,1,1);
WhiteTex.SetData<Color>(new Color[] {Color.White };
you can draw tiles this way...
Enum MaterialTypes { Dirt, Grass }
static readonly Dictionary<int, Color> MaterialTypeToColor = new Dictionary() { {0, new Color(100,100,100)}, {1, new Color(0,255,0) }};
for(int y = 0; y < 100; y ++)
{
for(int x = 0; x < 100; x++)
{
batch.Draw(whiteTex, new Rectangle(x*50,y*50, 50,50), null, (MaterialTypeToColor[ (int) tileMaterial[y,x]]);
}
}

Resources