I am trying to animate a flying cloth, which consists of individual rectangles, in Processing. I built the cloth from a nested loop. Now I want to use the noise function to manipulate the height of the individual points. Unfortunately, I can't do that properly - apparently I don't understand the function. I took a detour, drew noise clouds on a PGraphics, then read the brightness value - and use that to control the z-position of each rectangle. This works the way I want it to work!
Only - how can I achieve the same effect without going the detour via PGraphics?
This is my code the way I want it (the detour):
PGraphics pg;
float increment = 0.002;
float xoff;
float yoff;
float zoff = 0.0;
float zincrement = 0.1;
float size;
float pixel = 200;
void setup() {
size(1920, 1080, P3D);
frameRate(30);
size = width/pixel;
rectMode(CENTER);
pg = createGraphics(width, width);
}
void draw() {
//PGraphics
pg.beginDraw();
pg.loadPixels();
xoff = 0.0;
for (int x = 0; x < width; x++) {
xoff += increment;
yoff = 0.0;
for (int y = 0; y < width; y++) {
yoff += increment;
float bright = noise(xoff, yoff, zoff)*255;
pg.pixels[x+y*width] = color(bright, bright, bright);
}
}
pg.updatePixels();
pg.endDraw();
zoff += zincrement;
//SCENE
background(0);
stroke(255,0,0);
line(width/2, 0, width/2, height);
translate(0, 0, mouseX);
pushMatrix();
rotateX(radians(45));
translate(pixel*size/2, -pixel*size, -pixel*size);
rotateZ(radians(mouseX));
translate(-pixel*size/2, -pixel*size/2, -pixel*size/4);
pushMatrix();
for (int y = 0; y < pixel; y++) {
for (int x = 0; x < pixel; x++) {
color c = pg.get(int(size*x), int(size*y));
float zpoint = map(brightness(c), 0, 255, -500, 500);
pushMatrix();
noiseDetail(3, 0.5f);
translate(x*size, y*size, zpoint);
rotate(radians(45));
noStroke();
fill(255);
rect(0, 0, size, size);
popMatrix();
}
}
popMatrix();
popMatrix();
}
And this is how I would like to write it in a simpler way:
float size;
float pixel = 200;
float xoff;
float yoff;
float zoff;
float increment = 0.01;
void setup() {
size(1920, 1080, P3D);
frameRate(30);
size = width/pixel;
rectMode(CENTER);
}
void draw() {
background(0);
stroke(255,0,0);
line(width/2, 0, width/2, height);
translate(0,0,mouseX);
pushMatrix();
rotateX(radians(45));
translate(pixel*size/2,-pixel*size,-pixel*size);
rotateZ(radians(mouseX));
translate(-pixel*size/2,-pixel*size/2,-pixel*size/4);
pushMatrix();
for (int y = 0; y < pixel; y++) {
for (int x = 0; x < pixel; x++) {
pushMatrix();
noiseDetail(1, 0.25f);
float n = noise(x*size + xoff, y*size + yoff, zoff)*255;
translate(x*size, y*size, n);
rotate(radians(45));
noStroke();
fill(255);
rect(0, 0, size, size);
popMatrix();
}
}
popMatrix();
popMatrix();
yoff += 0.11;
xoff += 0.02;
zoff += 0.03;
}
I think this line is the problem - because currently it doesn't create a real cloth like this.
float n = noise(x*size + xoff, y*size + yoff, zoff)*255;
You are correct, the problem is in this line
float n = noise(x*size + xoff, y*size + yoff, zoff)*255;
The changes in the x and y input parameters from one iteration to the other is too large (it is equal to size). If you read about the Perlin noise you will know that with a large step it will just look like random noise. My suggestion to edit this line to something like:
float n = noise(xx + xoff, yy + yoff, zoff)*255;
where xx and yy are other variables that you increment slowly in the for loop
My solution:
void draw() {
background(0);
stroke(255,0,0);
line(width/2, 0, width/2, height);
translate(0,0,mouseX);
pushMatrix();
rotateX(radians(45));
translate(pixel*size/2,-pixel*size,-pixel*size);
rotateZ(radians(mouseX));
translate(-pixel*size/2,-pixel*size/2,-pixel*size/4);
pushMatrix();
float xx = 0;
float yy = 0;
for (int y = 0; y < pixel; y++) {
xx = 0;
for (int x = 0; x < pixel; x++) {
pushMatrix();
noiseDetail(1, 0.25f);
float n = noise(xx + xoff, yy + yoff)*255;
translate(x*size, y*size, n);
rotate(radians(45));
noStroke();
fill(255);
rect(0, 0, size, size);
popMatrix();
xx += 0.1;
}
yy += 0.1;
}
popMatrix();
popMatrix();
yoff += 0.11;
xoff += 0.02;
zoff += 0.03;
}
Changing the increment of xx and yy can make the flag look like its flowing in 1 direction...
Related
I am trying to draw a grid over an image using the underlaying colours of the image to fill the circles. But some pixels are not getting the correct colour.
In this case the circles are drawn white but they should not be drawn white...
See my code below:
import processing.pdf.*;
PImage img;
color background = color(255);
void setup() {
size(1038, 525);
ellipseMode(CORNER);
noStroke();
//img = loadImage("noise2.jpg");
//img = loadImage("air.png");
img = loadImage("accidents.png");
image(img, 0, 0, width, height);
visualGrid(20, 0.4, false);
}
//void draw() {
// fill(noise.get(mouseX, mouseY));
// rect(width - 100, height - 100, 100, 100);
//}
void visualGrid(int circleSize, float fillSmoothing, boolean debug) {
float halfCircle = circleSize / 2.0;
int amountX = floor(width / circleSize);
int amountY = floor(height / circleSize);
amountY += floor(amountY * 0.1);
float offsetX = (width - (amountX * circleSize + halfCircle)) / 2 + halfCircle;
float offsetY = (height - amountY * circleSize + amountY * circleSize * 0.1) / 2;
for (int x = 0; x < amountX; x++) {
for (int y = 0; y < amountY; y++) {
float styledOffsetX = (y % 2 == 0) ? offsetX - halfCircle : offsetX;
float xpos = x * circleSize + styledOffsetX;
float ypos = circleSize * 0.9 * y + offsetY;
int sectionSize = round(circleSize * fillSmoothing);
float sectionOffset = (circleSize - sectionSize) / 2;
color c = getAvgImgColor(img.get(round(xpos + sectionOffset), round(ypos + sectionOffset), sectionSize, sectionSize));
//fill(noise.get(round(xpos), round(ypos)));
if(debug) {
stroke(255, 0, 255);
strokeWeight(1);
}
fill(c);
ellipse(xpos, ypos, circleSize, circleSize);
if(debug) {
noStroke();
fill(255, 0, 255);
rect(round(xpos + sectionOffset), round(ypos + sectionOffset), sectionSize, sectionSize);
}
}
}
}
color getAvgImgColor(PImage section) {
section.loadPixels();
int avgR = 0, avgG = 0, avgB = 0;
int totalPixels = section.pixels.length;
for (int i = 0; i < totalPixels; i++) {
color pixel = section.pixels[i];
//if(pixel == background) continue;
avgR += red(pixel);
avgG += green(pixel);
avgB += blue(pixel);
}
return color(
round(avgR / totalPixels),
round(avgG / totalPixels),
round(avgB / totalPixels)
);
}
This is what i get when drawing my grid on the image in question:
As you can see in the circled area not all circles should be filled with white... This happens in more places than just the circled are just compare this image with the one below.
I will upload the original image below, so you can use it to debug.
There's a mismatch between the dimensions of your sketch (1038 x 525) and the image you're sampling (2076 x 1048) which might explain the misalignment.
If size(2076, 1048) isn't an option try resizing the image once it's loaded in setup():
...
img = loadImage("accidents.png");
img.resize(width, height);
...
I am trying to create some trippy "animation" such as this image; Trippy circles
I can just place another circle into the circle by brute-forcing it. However, I am pretty sure that there is an easier way of doing it by either using "while" or "for". I am pretty new to coding so I have no idea which logic to use.
Here is my brute-forced code below.
int m = millis();
void setup(){
size(1136,936);
}
void draw(){
ellipseMode(CENTER);
frameRate(1.3);
background(255);
if (millis() > m + 1000){
for (int diameter = 0; diameter < 500; diameter = diameter+1) {
float r1 = random(1,1000);
float r2 = random(1,900);
fill(255);
circle(r1, r2, diameter);
fill(0);
circle(r1,r2,diameter/2);
}
}
}
Thanks!
This comes close to what your example looks like (based on your original code):
int m = millis();
void setup(){
size(1136,936);
}
int colors[] = { 0, 255 };
void draw(){
ellipseMode(CENTER);
//frameRate(1.3);
background(255);
if (millis() > m + 1000) {
for (int i = 0; i < 500; i = i+1) {
float x = random(1,1000);
float y = random(1,900);
float radius = 300;
float delta = 30;
int counter = 0;
while (radius >= delta) {
fill(colors[counter % colors.length]);
ellipse(x, y, radius, radius);
counter++;
radius -= delta;
}
}
}
}
When I run the code it generates 16 rectangles with a random size, random position, and a random color. It is then supposed to turn white if it is colliding with another rectangle. Most of the time it works fine but every so often rectangles turn white when they are not colliding with anything.
Main
int boxCount = 16;
Box[] boxes = new Box[boxCount];
void setup(){
size(500, 500);
for(int i = 0; i < boxCount; i++){
boxes[i] = new Box(random(50, width - 50), random(50, height - 50), random(20, 50), random(20, 50), color(random(0, 255), random(0, 255), random(0, 255)));
}
}
void draw(){
for(int i = 0; i < boxCount; i++){
boxes[i].create();
for(int x = 0; x < boxCount; x++){
if(boxes[i] != boxes[x]){
boxes[i].collide(boxes[x]);
}
}
}
}
Class
class Box{
float x;
float y;
float w;
float h;
color c;
Box(float _x, float _y, float _w, float _h, color _c){
x = _x;
y = _y;
w = _w;
h = _h;
c = _c;
}
void create(){
fill(c);
rect(x, y, w, h);
}
void collide(Box o){
float right = x + (w / 2);
float left = x - (w / 2);
float top = y - (h / 2);
float bottom = y + (h / 2);
float oRight = o.x + (o.w / 2);
float oLeft = o.x - (o.w / 2);
float oTop = o.y - (o.h / 2);
float oBottom = o.y + (o.h / 2);
if(right > oLeft && left < oRight && bottom > oTop && top < oBottom){
c = color(255, 255, 255);
}
}
}
rect doesn't draw a rectangle around center point, by default the rectangle is drawn at a top left position (x, y) with a size (with, height).
You've 2 possibilities to solve the issue:
Either change the collision detection method:
class Box{
// [...]
void collide(Box o){
if(x < o.x+o.w && o.x < x+w && y < o.y+o.h && o.y < y+h){
c = color(255, 255, 255);
}
}
}
Or set the CENTER rectMode(), which will cause the rectangle to be drawn as you expect it:
class Box{
// [...]
void create(){
fill(c);
rectMode(CENTER);
rect(x, y, w, h);
}
// [...]
}
I have this code and I should modify it to do 2 things:
draw the surface in solid mode using the basic lighting (lights() and a unique fill()) and
draw the surface with a two color gradient (red for low values of z and yellow for high values, for instance) For that,I was advised use a fill() call before each vertex()
This is my code for the 1st one, the problem is that I do not want the grid to show after I have applied the color.
// Drawing a 3D function
float rotX = 0.0, rotY = 0.0;
int lastX, lastY;
float distX = 0.0, distY = 0.0;
// Function steps
int steps = 50;
// z scale
float scaleZ = 200.0;
// z zoom
float zoomZ = -300.0;
// Graphic size
float gX = 500.0, gY = 500.0;
void setup()
{
size(500, 500, P3D);
noFill();
strokeWeight(0.005);
}
float function(float x, float y)
{
return x*x*x + y*y*y;
}
void draw() {
lights();
background(0);
// We center the results on window
translate(gX/2, gY/2, zoomZ);
// Rotation
rotateY(rotY + distX);
rotateX(rotX + distY);
// Centering around (0, 0);
translate(-gX/2, -gY/2);
// Function covers
// 400 x 400 x scaleZ
scale(gX, gY, scaleZ);
// Drawing the function
fill(167);
drawFunction();
// Drawing axes
stroke(255, 0, 0);
line(0,0,0,2000,0,0);
stroke(0,255,0);
line(0,0,0,0,2000,0);
stroke(0,0,255);
line(0,0,0,0,0,2000);
}
void drawFunction()
{
float x, y, z;
int i = 0, j = 0;
float in_steps = 1.0 / steps;
float[][] matrix = new float[steps+1][steps+1];
for (y = 0.0, j = 0; y <= 1.0; y+=in_steps, j++)
for (x = 0.0, i = 0; x <= 1.0; x+=in_steps, i++)
matrix[i][j] = function(x, y);
stroke(167);
for (j = 0, y = 0.0; j < steps; j++, y+=in_steps) {
beginShape(QUAD_STRIP);
for (i = 0, x = 0.0; i <= steps; i++, x+=in_steps) {
vertex(x, y, matrix[i][j]);
vertex(x, y + in_steps, matrix[i][j+1]);
}
endShape();
}
}
void mousePressed()
{
lastX = mouseX;
lastY = mouseY;
}
void mouseDragged()
{
distX = radians(mouseX - lastX);
distY = radians(lastY - mouseY);
}
void mouseReleased()
{
rotX += distY;
rotY += distX;
distX = distY = 0.0;
}
The lights() are already proper set in your code.
Use noStroke() to get rid of the lines. noStroke disables drawing outlines.
The color of the filled areas can be set by passing RGB (red, green and blue) values to fill().
The values are integral values in the range[0, 255]. The RGB vlaue for red is (255, 0, 0) and the RGB value for yellow is (255, 255, 0).
A gradient color form red to yellow can be achieved by
fill(255, z*255, 0);
where z is in [0.0, 1.0]. If z = 0.0 the result is red (255, 0, 0) and if z = 1.0 the result is yellow (255, 255, 0). All values for z in between 0.0 and 1.0 result in a linear interpolation between read and yellow.
e.g.
for (j = 0, y = 0.0; j < steps; j++, y+=in_steps) {
beginShape(QUAD_STRIP);
noStroke(); // no lines
for (i = 0, x = 0.0; i <= steps; i++, x+=in_steps) {
fill(255, matrix[i][j] * 255, 0); // interpolate between red and yellow
vertex(x, y, matrix[i][j]);
fill(255, matrix[i][j+1] * 255, 0); // interpolate between red and yellow
vertex(x, y + in_steps, matrix[i][j+1]);
}
endShape();
}
Alright, so I'm trying to make a quick and dirty platformer engine, and I am having some problems with my collision detection and moving platforms. for one thing the "player" seems to bounce on top of moving platforms ever so slightly, and when he hits the right side errors happen as well. I'll upload a jnlp demo so you can try to find more errors and see whats happening, but here is the source:
import java.awt.Rectangle;
import java.util.Vector;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
public class Platformer extends BasicGame{
boolean keys[];
int ALL_KEYS = 0xFF;
Player player;
Vector<Vector<Thing> > things;
int level = 0;
public Platformer() {
super("You've met with a terrible fate, haven't you?");
}
public void init(GameContainer gc) throws SlickException {
keys = new boolean[ALL_KEYS];
for(int i = 0; i < ALL_KEYS; i++){
keys[i] = false;
}
player = new Player();
things = new Vector<Vector<Thing> >();
Vector<Thing> temp = new Vector<Thing>();
temp.add(new Thing(0, 440, 640, 40, 1));
temp.add(new Thing(200, 300, 240, 50, 1));
temp.add(new Thing(500, 200, 240, 50, 1));
things.add(temp);
}
public void update(GameContainer gc, int delta) throws SlickException{
if(keys[Input.KEY_UP]){
player.velo = player.maxJump;
keys[Input.KEY_UP] = false;
}
if(keys[Input.KEY_DOWN]){
keys[Input.KEY_DOWN] = false;
}
if(keys[Input.KEY_LEFT]){
player.delta -= player.speed;
if(player.delta < -player.maxSpeed)
player.delta = -player.maxSpeed;
}
else if(keys[Input.KEY_RIGHT]){
player.delta += player.speed;
if(player.delta > player.maxSpeed)
player.delta = player.maxSpeed;
}
else{
if(player.delta < -0.5){
player.delta += player.speed;
}
else if(player.delta > 0.5){
player.delta -= player.speed;
}
else if(player.delta > -0.5 && player.delta < 0.5){
player.delta = 0;
}
}
if(player.delta < 0)
player.moveLeft(things.get(level));
else if(player.delta > 0)
player.moveRight(things.get(level));
if(player.velo < 0)
player.moveUp(things.get(level));
else
player.moveDown(things.get(level));
things.get(level).get(1).moveRight(player, things.get(level));
}
public void render(GameContainer gc, Graphics g) throws SlickException{
g.setColor(new Color(0,55,55));
g.fillRect(0, 0, 640, 480);
g.setColor(new Color(255,0,0));
g.fillRect(player.x, player.y, player.width, player.height);
for(int i = 0; i < things.get(level).size(); i++){
if(things.get(level).get(i).type == 1)
g.setColor(new Color(0,100,100));
g.fillRect(things.get(level).get(i).x, things.get(level).get(i).y,things.get(level).get(i).width, things.get(level).get(i).height);
}
}
public void keyPressed(int key, char c) {
keys[key] = true;
}
public void keyReleased(int key, char c) {
keys[key] = false;
}
public static void main(String[] args) throws SlickException{
AppGameContainer app =
new AppGameContainer( new Platformer() );
app.setShowFPS(false);
app.setAlwaysRender(true);
app.setTargetFrameRate(60);
app.setDisplayMode(640, 480, false);
app.start();
}
class Player{
float x = 50;
float y = 50;
float delta = 0; // x momentum
float velo = 0;
int height = 50;
int width = 30;
float speed = 0.2f;
int maxSpeed = 6;
int maxFallSpeed = 5;
int maxJump = -8;
public void moveLeft(Vector<Thing> things){
x += delta;
if(x < 0)
x = 0;
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x += (things.get(i).x + things.get(i).width) - x;
delta = 0;
}
}
}
public void moveRight(Vector<Thing> things){
x += delta;
if(x + width > 640)
x = (640 - width);
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x -= (x + width) - things.get(i).x;
delta = 0;
}
}
}
public void moveLeftWithThing(Vector<Thing> things, float thingSpeed){
x -= thingSpeed;
if(x < 0)
x = 0;
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x += (things.get(i).x + things.get(i).width) - x;
delta = 0;
}
}
}
public void moveRightWithThing(Vector<Thing> things, float thingSpeed){
x += thingSpeed;
if(x + width > 640)
x = (640 - width);
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
x -= (x + width) - things.get(i).x;
delta = 0;
}
}
}
public void moveUp(Vector<Thing> things){
y += velo;
velo += speed;
if(velo > maxFallSpeed)
velo = maxFallSpeed;
for(int i = 0; i < things.size(); i++){
if(new Rectangle((int) x, (int) y, width, height/2).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
y += (things.get(i).y + things.get(i).height) - y;
velo = 0;
}
}
}
public void moveDown(Vector<Thing> things){
y += velo;
velo += speed;
if(velo > maxFallSpeed)
velo = maxFallSpeed;
boolean b = false;
for(int i = 0; i < things.size(); i++){
if(!b && new Rectangle((int) x, (int) y + (height/2), width, height).intersects(new Rectangle((int) things.get(i).x, (int) things.get(i).y, things.get(i).width, things.get(i).height))){
y -= (y + height) - things.get(i).y;
velo = 0;
}
}
}
}
class Thing{
float x = 50;
float y = 50;
int height = 50;
int width = 30;
int type = -1;
float speed = 0.5f;
public Thing(float x, float y, int width, int height, int type){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
}
public void moveUp(Player player){
y -= 0.5f;
if(new Rectangle((int) x,(int) y, width, height).intersects(new Rectangle((int) player.x, (int) player.y, player.width, player.height))){
player.y -= (player.y + player.height) - y;
player.velo = 0;
}
}
public void moveRight(Player player, Vector<Thing> things){
x += speed;
if(new Rectangle((int) x,(int) y - 1, width, height).intersects(new Rectangle((int) player.x, (int) player.y, player.width, player.height))){
player.moveRightWithThing(things, speed);
}
}
}
}
And here is the demo: http://prime.programming-designs.com/java/platformer_demo/platdemo.jnlp
The reason why you are having trouble finding the error is that the code is ghastly.
Vast amounts of duplication of code: moveLeft, moveRight, moveUp and moveDown are all very similar.
Logic for acceleration due to gravity appears in two places.
Collision logic repeated all over the place.
Desperately poor choice of names. velo for velocity downwards, but delta for velocity rightwards (mislabelled as "momentum"): why not vy and vx? Also maxSpeed for maximum horizontal velocity but maxFallSpeed for maximum vertical velocity.
Acceleration/deceleration called speed.
Wasteful allocation, e.g. calling new Rectangle every time you want to test whether something has hit something else.
Positions are floating-point, but collision is based on integers.
Duplication of code has the effect of introducing bugs, because when functionality is duplicated there's the possibility of getting it wrong in one of the places, and also of hiding bugs, because the volume of code makes it harder to spot them.
Anyway, the bouncing on platforms may be something to do with the fact that in Player:moveDown you are using a rectangle that's offset by half the player's height, whereas in Thing:moveRight you are colliding with a rectangle that's not offset. (But that's just a guess.)