I want to construct TRIANGLE_STRIP shape with different texture in each sector.
Is it possible to use TRIANGLE_STRIP shape in this case?
I can't understand how to set horizontal and vertical coordinate for the texture mapping in this shape mode because each triangle shares vertex points with each other and because of that I can set horizontal and vertical coordinate for the texture mapping only for one image.
PImage img1, img2, img3, img4, img5;
void setup() {
size(800, 300, P3D);
img1 = loadImage("img1.png");
img2 = loadImage("img2.png");
....
textureMode(NORMAL);
// textureWrap(REPEAT);
}
void draw(){
background(0);
stroke(255);
beginShape(TRIANGLE_STRIP);
texture(img1);
vertex(30, 286,0,1);
vertex(158, 30, 0.5, 0);
vertex(286, 286,1,1);
texture(img2);
vertex(414, 30, ?, ?);
texture(img3);
vertex(542, 286, ?, ?);
texture(img4);
vertex(670, 30,?,?);
texture(img4);
vertex(798, 286,?,?);
endShape();
}
UPD
I wand to acheive the result similar to that animation:
https://mir-s3-cdn-cf.behance.net/project_modules/disp/7d7bf511219015.560f42336f0bd.gif
First of all I want to construct complicated object based on TRIANGLE_STRIP or QUAD_STRIP shape mode and after that just change z coordinate of vertexes.
So I just took image with such inscription and cut it on different images for each sector of shape.
If someone knows how to make it in more easy way I will be very thankful for help.
Step 1: Create a small sketch that simply displays a triangle strip (without any texturing) over the entire space you want to take up. Here's an example that fills the whole screen:
void setup() {
size(300, 200);
}
void draw() {
background(0);
stroke(0);
beginShape(TRIANGLE_STRIP);
vertex(0, 200);
vertex(0, 0);
vertex(50, 200);
vertex(100, 0);
vertex(150, 200);
vertex(200, 0);
vertex(250, 200);
vertex(300, 0);
vertex(300, 200);
endShape();
}
The goal is to make sure your vertexes cover the area you want your image to cover. You want something that looks like this:
This will also make it easier to map the vertex coordinates to image texture coordinates.
Step 2: Create an image that you want to use as a texture. I'll use this one:
Step 3: For each vertex you're drawing on the screen, figure out where in the image that point is. If a point is in the middle of the screen, then you need to figure out the position of the middle of the image. That's your values for u and v.
Alternatively, you can use textureMode(NORMAL) so you can specify u and v as normalized values between 0 and 1. The middle of the image becomes point (.5, .5).
Which approach you take is up to you, but in either case you have to map the screen vertex positions to the image u, v positions. I'll use the normalized values here:
PImage img;
void setup() {
size(300, 200, P3D);
img = loadImage("test.png");
textureMode(NORMAL);
}
void draw() {
background(0);
stroke(0);
beginShape(TRIANGLE_STRIP);
texture(img);
vertex(0, 200, 0, 1);
vertex(0, 0, 0, 0);
vertex(50, 200, .16, 1);
vertex(100, 0, .33, 0);
vertex(150, 200, .5, 1);
vertex(200, 0, .66, 0);
vertex(250, 200, .83, 1);
vertex(300, 0, 1, 0);
vertex(300, 200, 1, 1);
endShape();
}
Step 4: Now you can modify the position of one of the vertexes, and you'll morph the image drawn on screen:
PImage img;
void setup() {
size(300, 200, P3D);
img = loadImage("test.png");
textureMode(NORMAL);
}
void draw() {
background(0);
stroke(0);
beginShape(TRIANGLE_STRIP);
texture(img);
vertex(0, 200, 0, 1);
vertex(0, 0, 0, 0);
vertex(50, 200, .16, 1);
vertex(100, 0, .33, 0);
vertex(mouseX, mouseY, .5, 1);
vertex(200, 0, .66, 0);
vertex(250, 200, .83, 1);
vertex(300, 0, 1, 0);
vertex(300, 200, 1, 1);
endShape();
}
You can play around with it to get the exact effect you're looking for, but following these steps should be your general approach. Note that you only need to use a single image, and you need to figure out the u and v values for every vertex you draw on screen. Start with a triangle mesh that displays the image normally, and then modify that to morph your image.
Also note that I could have done a lot of this calculation programatically. For example, instead of hard-coding the value 150, I could have used width/2.0. But first you need to understand the relationship between the x,y on screen and the u,v in the texture. Once you understand that relationship, you can calculate them programatically if you want.
Related
I am currently trying to add a day/night cycle to my game, and I am having trouble with lighting. If there is a light source, I want it to create a circle of light around its area. I've made night time by drawing a black rectangle over the screen that becomes less transparent when its night time. That makes the whole screen darker. The code that I have works for one light source, but if I have a light source that overlaps another light source, it makes a strange darker ring. I understand what is causing that ring, but nothing I have tried is removing the ring.
public void render(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(20, 20, 20, transparency));
float[] dist = { 0.5f, 1.0f };
Color[] color = { new Color(230, 230, 180, 150), new Color(20, 20, 20, transparency) };
//Color[] color = { new Color(230, 230, 180, 150), new Color(0, 0, 0, 0) }; //Old unused color for the gradient
Area a = new Area(new Rectangle(0, 0, Main_Game.WIDTH, Main_Game.HEIGHT));
for (int i = 0; i < lightList.size(); i++) {
RadialGradientPaint p = new RadialGradientPaint(lightList.get(i).center, lightList.get(i).size, dist, color);
g2d.setPaint(p);
g2d.fillOval(lightList.get(i).center.x - lightList.get(i).size, lightList.get(i).center.y - lightList.get(i).size, lightList.get(i).size*2, lightList.get(i).size*2);
a.subtract(new Area(new Ellipse2D.Double(lightList.get(i).center.x - lightList.get(i).size, lightList.get(i).center.y - lightList.get(i).size, lightList.get(i).size*2, lightList.get(i).size*2)));
}
g2d.setColor(new Color(20, 20, 20, transparency));
g2d.fill(a);
}
That code has a linked list that holds all the light sources. And the transparency variable stores the transparency the box that darkens the screen when it's night time.
The ideal way to fix this would be to combine all the RadialGradientPaint objects for each light into one paint object and that way, the lights wouldn't overlap weirdly.
Here is what it looks like when it works with only one light source:
Here is a picture of the weirdness of lighting that I'm getting at night time (there is no issue during the daytime of the game) when there are two light sources close to each other:
Any sort of help or recommendation to setup this lighting would be greatly appreciated :)
I have tried subtracting one lighting circle from another so that they aren't overlapping, but that made the two lights not merge very nicely. I tried drawing the lights as a rectangle instead of an oval but that made a similar issue.
How can I draw a filled oval of color red on a Graphics object created with BufferedImage which is filled with the color black?
What I have tried:
public void draw(){
BufferedImage bufferedImage = new BufferedImage(4, 5, BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.createGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, 4, 5);
g.setColor(Color.RED);
g.fillOval(1, 1, 2, 2);
g.dispose();
}
The result is a filled red rectangle in a filled black rectangle:
But I want that filled red rectangle to be a filled red oval. How can I do that?
I want to use that image as a mouse cursor.
It looks like a red rectangle because it is only 1 pixel tall and 2 pixels wide. Since there isn't enough space to simulate a curve, you won't get one. Try a bigger oval like g.fillOval(100, 100, 200, 200);
I am currently working on a small project where I'm creating a simple boardgame-like spinning wheel. The user will press a button and the spinner will randomly land on one of the four colors (red, green, yellow, or blue). The trouble I'm having is getting the spinner to rotate in a circle (or clockwise) and randomly land in a random position in one of the four squares.
Screenshot of game thus far
And source code:
void setup() { // this is run once
size(800, 800);
}
void draw() { // this is run repeatedly
background(255);
strokeWeight(2);
fill(255,0,0);
rect(100,100,300,300);
fill(0,96,255);
rect(100, 400, 300, 300);
fill(255,240,0);
rect(400, 100, 300, 300);
fill(0,255,0);
rect(400, 400, 300, 300);
// how to rotate this part like a spinner?
strokeWeight(20);
line(400, 400, 400, 600);
}
I then need to figure out how to determine which color the spinner landed on, and print out text that says "You have landed on [the color the spinner lands on]". I am having difficulty understanding the Matrix aspect of determining the coordinates after the rotation.
I am coding in Java in the Processing development platform.
Unfortunately, working with both circles and coordinates can be a little tricky in programming. You're going to have to do some conversion between Polar and Cartesian coordinates.
Here's a great reference to the difference between the two.
So you'll need to first generate a random number between 0 and 2 PI (Radians), this is done easily in processing:
float rnd = random(0, TWO_PI);
Next need let's convert it to normal coordinates:
float x = 200 * cos(rnd);
float y = 200 * sin(rnd);
Lastly draw the line: line(400, 400, x + 400, y + 400);
Edit: Forgot processing had rotate(), that'd be a much better solution than this mess
Your first step will be to learn about rotations that are isolated to one shape without rotating the entire sketch. There's a code pattern involving pushMatrix, popMatrix, translate, and rotate - all in conjunction with one another.
// inside draw
pushMatrix();
translate(400, 400);
rotate(radians(rotation));
line(0, 0, 100, 100);
popMatrix();
rotation += 5;
The translate function moves the origin to a new position, in this case 400, 400. Any shapes drawn after the origin moves are relative to it. That is the reason line is drawn at 0, 0 on the new origin which is actually 400, 400. The functions pushMatrix and popMatrix isolate this code so as not to affect the rest of your sketch. It's a nice trick to create independent rotations (and anything else really) in your sketch without having to come up with math formulas to counteract all your movements. Imagine five spinners going different speeds and directions.
For a gradually slowing spinner, I introduce a stepSize variable and slowly decrease it and subtract it from rotation until rotation hits zero and the spinner stops.
// still inside draw
if (stepSize > 0) {
rotation += stepSize;
stepSize -= 0.05; // play around with this value
}
Here's a demo program putting all the pieces together to achieve a spinner that will move for a while then stop.
float rotation = 1, stepSize = 10;
void setup() {
size(800, 800);
}
void draw() {
background(255);
strokeWeight(2);
fill(255, 0, 0);
rect(100, 100, 300, 300);
fill(0, 96, 255);
rect(100, 400, 300, 300);
fill(255, 240, 0);
rect(400, 100, 300, 300);
fill(0, 255, 0);
rect(400, 400, 300, 300);
strokeWeight(20);
pushMatrix();
translate(400, 400);
rotate(radians(rotation));
line(0, 0, 100, 100);
popMatrix();
if (stepSize > 0) {
rotation += stepSize;
stepSize -= 0.05; // play around with this value
}
}
void mousePressed() {
stepSize = random(5,15); // try adjusting these values
}
I'm currently working on a project with the theme of earth hour, and we are only allowed to use rectangles, circles and triangles. Here's the image i'm tring to create (not exactly, mine will be much more simplified!):
https://www.google.com/search?q=earth+hour&biw=1366&bih=586&source=lnms&tbm=isch&sa=X&ved=0ahUKEwj__5H0vtvQAhXLrlQKHTi8BagQ_AUIBygC#imgrc=fQkBxn0a8LnwbM%3A
(not sure if you could see the link)
But when i'm coding it, i'm running into trouble to rotate those rectangles to stand on the tangent line of the circle. I'm a student just learnt some basics of java, like loops and arrays. So my quesiton is that if there's some understandable way that doesn't involve some complex and exotic methods that could rotate those rectangles? I know it will probably involve some complicated solutions that is beyond my knowledge. But any help is much appreciated.
this is part of the code that i build the building standing perpendicularly to the circle(earth):
// create mid buildings
Color blc = new Color(0, 0, 0);
Rectangle midBld = new Rectangle(240, 220, 20, 40, blc);
midBld.draw(g);
Rectangle midBld1 = new Rectangle(242, 190, 16, 30, blc);
midBld1.draw(g);
Triangle midBld2 = new Triangle(250, 160, 8, 30, blc);
midBld2.draw(g);
Triangle midBld3 = new Triangle(250, 160, -8, 30, blc);
midBld3.draw(g);
A Rectangle cannot be rotated, its edges are always in parallel to the axis. But you can rotate and translate the coordinate system in witch you draw the shapes. From Graphics2D API doc.
All coordinates passed to a Graphics2D object are specified in a device-independent coordinate system called User Space, which is used by applications. The Graphics2D object contains an AffineTransform object as part of its rendering state that defines how to convert coordinates from user space to device-dependent coordinates in Device Space.
Graphics2D also provide two methods that are useful in this task: translate that moves the origin of the coordinates and rotate that, well, rotates the system.
package graphics;
import javax.swing.*;
import java.awt.*;
/**
* Earth Hour
*/
public class RotateRect extends JFrame {
private static final int WIDTH = 400;
private static final int HEIGHT = 400;
public RotateRect() {
this.setSize(WIDTH, HEIGHT);
this.setTitle("Rotate Rectangles");
this.setContentPane(new JPanel() {
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Background: White
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
// Draw "Earth": Center(200, 400), Radius=200
g2.setColor(Color.BLACK);
g2.fillOval(0, 200, 400, 400);
// Move origin to center of the canvas (surface of earth)
g2.translate(200, 200);
// Rotate the coordinate system, relative to the center of earth.
// note x, y are in the translated system
// Transforms are accumulative
g2.rotate(-Math.PI/6, 0, 200);
// Fill a rectangle with top-left corner at (-20, 80) in the rotated system
// It's important to make the rectangle symmetrical to the y-axis, otherwise the building looks
// funny.
// Also, make the building "sunk" a little, so that it's fully on the ground.
g2.fillRect(-20, -80, 40, 100);
g2.rotate(Math.PI/3, 0, 200);
g2.fillRect(-20, -80, 40, 100);
g2.rotate(-Math.PI/6, 0, 200);
g2.fill(new Rectangle(-20, -80, 40, 100));
}
});
}
public static void main(String [] args) {
RotateRect rr = new RotateRect();
rr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
EventQueue.invokeLater(()->rr.setVisible(true));
}
}
I have one problem with openGL frame buffer.
I want to achieve:
Bind FBO1. Draw image1 to FBO1. Unbind FBO1.
Bind FBO2. Draw FBO1 to FBO2. Unbind FBO2.
Bind FBO1. Draw image2 to FBO1. Unbind FBO1.
Draw FBO2 to the screen
What I expect to see:
I expect to see only image1 on the screen, because it is drawn in the first FBO and then the first FBO is drawn onto the second FBO
What is the problem:
I am seeing both image1 and image2 on drawn, which should be imposible, because only the first image is drawn in FBO1 when FBO1 is drawn in FBO2 and I only draw FBO2 to the screen.
Here is the code to reproduce the problem:
// --- in show() method
this.img = new Texture(Gdx.files.internal("shaders/image.jpg"));
this.img2 = new Texture(Gdx.files.internal("shaders/image2.jpg"));
this.fbo = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
this.fbo2 = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
// --- in render() method
// start frame buffer 1 and draw image 1
this.fbo.begin();
{
this.batch.begin();
this.batch.draw(this.img, 0, 0, 400, 400, 0, 0, this.img.getWidth(), this.img.getHeight(), false, true);
this.batch.end();
}
this.fbo.end();
// start frame buffer 2 and frame buffer 1 output
this.fbo2.begin();
{
this.batch.begin();
this.batch.draw(this.fbo.getColorBufferTexture(), 500, 0, this.fbo.getColorBufferTexture().getWidth(), this.fbo.getColorBufferTexture().getHeight(), 0, 0, this.fbo.getColorBufferTexture()
.getWidth(), this.fbo.getColorBufferTexture().getHeight(), false, true);
this.batch.end();
}
this.fbo2.end();
// start frame buffer 1 again and draw image 2
this.fbo.begin();
{
this.batch.begin();
this.batch.draw(this.img2, 150, 150, 400, 400, 0, 0, this.img2.getWidth(), this.img2.getHeight(), false, true);
this.batch.end();
}
this.fbo.end();
// draw frame buffer 2 to the batch
this.batch.begin();
this.batch.draw(this.fbo2.getColorBufferTexture(), 0, 0);
this.batch.end();
The draw() methods are a bit long, because I want to pass flipY = true, because OpenGL draws the frame buffers upside-down.
The parameters of the draw() method that I am using are:
Texture texture, float x, float y, float width, float height, int srcX, int srcY, int srcWidth, int srcHeight, boolean flipX, boolean flipY
What am I missing? Why is this happening?
Each time you begin drawing on another FrameBuffer, you need to clear it if you don't want the old contents.
frameBuffer.begin();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//...
You also need to clear the screen at the beginning of render() if you don't want the contents from the last call to render().
Also, if you are covering the whole background with your image, you might as well disable blending on the SpriteBatch.