I have created an audio visualizer using the default renderer in Processing 3, now I want to implement an independent spinning 3D cube (that uses P3D) within the audio visualizer (which was created in the default renderer). Here is the code for the 3D cube:
import processing.opengl.*;
float y = 0.1;
float x = 0.1;
float z = 0.1;
void setup()
{
size(800,600,P3D);
smooth();
}
void draw()
{
translate(400,300,0);
rotateX(x);
rotateY(y);
rotateZ(z);
background(255);
fill(255,228,225);
box(200);
x += random(.1);
y += random(.1);
z += random(.1);
}
Here's a snippet from the visualizer that pertains to 3D cube:
void setup()
{
size(800, 600);
//fullScreen(2);
minim = new Minim(this);
player = minim.loadFile("/Users/samuel/Desktop/GT.mp3");
meta = player.getMetaData();
beat = new BeatDetect();
player.loop();
fft = new FFT(player.bufferSize(), player.sampleRate());
fft.logAverages(60, 7);
noStroke();
w = width/fft.avgSize();
player.play();
background(0);
smooth();
}
Ultimately, I'm just curious if I can integrate a 3D object without changing the size() of the visualizer to P3D.
You can use the createGraphics() function to create a renderer, and you can pass P3D into that renderer to allow drawing in 3D.
However, you can't do that if your sketch is using the default renderer. You have to use either P2D or P3D in your main renderer to be able to use P3D in any createGraphics() renderers. From the reference:
It's important to consider the renderer used with createGraphics() in relation to the main renderer specified in size(). For example, it's only possible to use P2D or P3D with createGraphics() when one of them is defined in size(). Unlike Processing 1.0, P2D and P3D use OpenGL for drawing, and when using an OpenGL renderer it's necessary for the main drawing surface to be OpenGL-based. If P2D or P3D are used as the renderer in size(), then any of the options can be used with createGraphics(). If the default renderer is used in size(), then only the default or PDF can be used with createGraphics().
Here's a little example that uses a P2D renderer as the main renderer and P3D as a sub-renderer:
PGraphics pg;
void setup() {
size(200, 200, P2D);
pg = createGraphics(100, 100, P3D);
}
void draw() {
pg.beginDraw();
pg.background(0);
pg.noStroke();
pg.translate(pg.width*0.5, pg.height*0.5);
pg.lights();
pg.sphere(25);
pg.endDraw();
background(0, 0, 255);
image(pg, 50, 50);
}
Related
I'm a total beginner so forgive me if this is probably silly or improper of me to ask.
I'm trying to make my own virtual oscillograph in processing. I don't really know how to explain it, but I want to "zoom out" from where I am getting the peaks in waveforms, which is the window size. I'm not sure what I'm doing wrong here or what's wrong with my code. I've tried changing the buffer size, and changing the multiplier for x/y. My sketch is adapted from a minim example Sketch.
All Help is greatly appreciated.
import ddf.minim.*;
Minim minim;
AudioInput in;
int frames;
int refresh = 7;
float fade = 32;
void setup()
{
size(800, 800, P3D);
minim = new Minim(this);
ellipseMode(RADIUS);
// use the getLineIn method of the Minim object to get an AudioInput
in = minim.getLineIn(Minim.STEREO);
println (in.bufferSize());
//in.enableMonitoring();
frameRate(1000);
background(0);
}
void draw()
{
frames++; //same saying frames = frames+1
if (frames%refresh == 0){
fill (0, 32, 0, fade);
rect (0, 0, width, height);
}
float x;
float y;
stroke (0, 0);
fill (0,255,0);
// draw the waveforms so we can see what we are monitoring
for(int i = 0; i < in.bufferSize() - 1; i++)
{
x = width/2 + in.left.get(i) * height/2;
y = height/2- in.right.get(i) * height/2;
ellipse(x, y, .5, .5);
}
}
Thanks
Edit: you don't need push and pop matrix here. Guess my understanding of it is lacking too. You can just use translate.
You can use matrices to create a camera object, there is tons of material out there that you can read up on to understand the math behind this and implement it anywhere.
However, there might be an easier solution here. You can use pushMatrix and popMatrix in combination with translate. Push and popping the matrix will manipulate the matrix stack - you create a new "frame" where you can play around with translations, then pop back the original frame (so you don't get lost by applying new translations on each frame).
push the matrix, translate the z coordinate once before drawing everything you want zoomed out, pop the matrix. You can set up a variable for the translation so that you can control this with your mouse.
Here's a crude example (I don't have all those libraries so couldn't add it to your code):
float scroll = 0;
float scroll_multiplier = 10;
void setup()
{
size(800, 800, P3D);
frameRate(1000);
background(0);
}
void draw()
{
background(0);
//draw HUD - things that don't zoom.
fill(255,0,0);
rect(400,300,100,100);
//We don't want to mess up our coordinate system, we push a new "frame" on the matrix stack
pushMatrix();
//We can now safely translate the Y axis, creating a zoom effect. In reality, whatever we pass to translate gets added to the coordinates of draw calls.
translate(0,0,scroll);
//Draw zoomed elements
fill(0,255,0);
rect(400,400,100,100);
//Pop the matrix - if we don't push and pop around our translation, the translation will be applied every frame, making our drawables dissapear in the distance.
popMatrix();
}
void mouseWheel(MouseEvent event) {
scroll += scroll_multiplier * event.getCount();
}
I've imported an object into Processing that I created in Blender.
The code below works and the object appears but seemingly very small (or distant).
If I try to move close to the object with PeasyCamm it disappears completely before it gets close enough to see properly. The only thing I could figure is that the object itself is very close to the camera but is in fact tiny...
I attempted to scale the object but a call to
myshape.getVertexCount()
indicates my object has no vertices and nothing I do seems to change anything. I have a tiny rendered object that disappears at about a quarter of the screen height.
PShape myshape;
import peasy.test.*;
import peasy.org.apache.commons.math.*;
import peasy.*;
import peasy.org.apache.commons.math.geometry.*;
PeasyCam camera;
void setup(){
size( 640, 480, P3D);
camera = new PeasyCam(this, 0, 0, 0, 50);
frameRate(10);
myshape = loadShape("test.obj");
for (int i = 0; i < myshape.getVertexCount(); i++){
PVector v = myshape.getVertex(i);
println("Inside");
v.x *= 45;
v.y *= 45;
v.z *= 45;
myshape.setVertex(i, v);
}
}
void draw(){
background(0);
shape(myshape);
}
The getVertexCount() and getVertex() functions only work with shapes that you create in the code, using the vertex() function. More info can be found in the reference.
If all you want to do is scale your shape, then you can simply use the scale() function. Here is some example code that scaled your object by a factor of 20:
PShape myshape;
void setup() {
size(500, 500, P3D);
myshape = loadShape("test.obj");
}
void draw() {
background(0);
translate(width/2, height/2, 100);
scale(20);
shape(myshape);
}
Edit: Apparently you can still get to the vertexes inside an object file, it just isn't as straightforward as calling the getVertex() function. First you have to loop through the shape's children and then call getVertex() on the children. More info in this forum post (see jeremydouglass's answer).
I have met some problem for integration the JPCT-AE with ARNative of ARToolkit's Project.
Purpose:
using jpct-ae to rendering model basic on ARToolkit;
Status :
i can render a model on the screen behind the preview data;
however, the model could no shown in correct position;
i do not know how the using the ProjectionMatrix from ARToolkit for JPCT-AE.
My code was shown belown:
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
ARNativeActivity.nativeSurfaceCreated();
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
ARNativeActivity.nativeSurfaceChanged(width, height);
glViewport(0, 0, width, height);
fb = new FrameBuffer( width, height); // OpenGL ES 1.x constructor
world = new World();
world.setAmbientLight(20, 20, 20);
sun = new Light(world);
sun.setIntensity(250, 250, 250);
loadOBJ("cube.obj" , "cube.mtl" , "cube");
world.addObject(cubeColor);
cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cubeColor.getTransformedCenter());
SimpleVector sv = new SimpleVector();
sv.set(cubeColor.getTransformedCenter());
sv.y -= 100;
sv.z -= 100;
sun.setPosition(sv);
MemoryHelper.compact();
}
public void onDrawFrame(GL10 unused) {
glClear(GL_COLOR_BUFFER_BIT);
ARNativeActivity.nativeDrawFrame();
float[] projection = ARNativeActivity.getProjectMatrix();
Matrix projMatrix = new Matrix();
projMatrix.setDump(projection);
projMatrix.transformToGL();
SimpleVector translation = projMatrix.getTranslation();
SimpleVector dir = projMatrix.getZAxis();
SimpleVector up = projMatrix.getYAxis();
cam.setPosition(translation);
cam.setOrientation(dir, up);
world.renderScene(fb);
world.draw(fb);
fb.display();
}
I think this question is pretty similar to a newer one you made: Rendering a model basic on JPCT-AE with ARToolkit in Android. It will most likely be duplicated. Anyway, I have still not enough privileges to mark it as duplicated, so I reference to the other and try to answer the slight differences. The only difference I can see is that here you still are not using the transformation matrix given by the artoolkit. You must get it by calling
ARNativeActivity.getTransformationM()
and put it in a JPCT matrix:
transformM.setIdentity();
transformM .setDump(ARNativeActivity.getTransformationM());
transformM .transformToGL();
As told, is already on the other question, so I suggest all users going there for a more complete answer and external references.
I made a dial chart Using JFreeChart. I was wondering if it was possible to make the indicators thicker. The code I am using to make them now are:
StandardDialRange standarddialrange;
StandardDialRange standarddialrange2;
StandardDialRange standarddialrange3;
if(isPercentageIV==true){
standarddialrange = new StandardDialRange(90D, 100D, Color.GREEN);
standarddialrange2 = new StandardDialRange(60D, 90D, Color.orange);
standarddialrange3 = new StandardDialRange(0D, 60D, Color.RED);
}
else{
standarddialrange = new StandardDialRange(.9*goal*dialScale, goal*dialScale, Color.GREEN);
standarddialrange2 = new StandardDialRange(.6*goal*dialScale, .9*goal*dialScale, Color.orange);
standarddialrange3 = new StandardDialRange(0, .6*goal*dialScale, Color.RED);
}
// Sets the scale/radius of all the indicators.
standarddialrange.setScaleIndex(0);
standarddialrange.setInnerRadius(0.58999999999999997D);
standarddialrange.setOuterRadius(0.58999999999999997D);
dialplot.addLayer(standarddialrange);
standarddialrange2.setScaleIndex(0);
standarddialrange2.setInnerRadius(0.58999999999999997D);
standarddialrange2.setOuterRadius(0.58999999999999997D);
dialplot.addLayer(standarddialrange2);
standarddialrange3.setScaleIndex(0);
standarddialrange3.setInnerRadius(0.58999999999999997D);
standarddialrange3.setOuterRadius(0.58999999999999997D);
dialplot.addLayer(standarddialrange3);
I tried looking online and I could not figure out how to make it thicker. The way they are now makes them kind of hard to see on a display from far away. I tried changing the outer radius but it just made it so their were two thin lines, instead of one big thick one.
Override the draw() method of StandardDialRange and specify your preferred Stroke; I've used 4.0f in the example below. You'll need to recapitulate the existing code, using the public accessors as required.
plot.addLayer(new StandardDialRange(3 * maximumValue / 4, maximumValue, Color.red) {
#Override
public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame, Rectangle2D view) {
…
g2.setPaint(this.getPaint());
g2.setStroke(new BasicStroke(4.0f));
g2.draw(arcInner);
g2.draw(arcOuter);
}
});
Using GradientPaint for gradient background colors is not always satisfactory, especially in certain sizes. For example this code:
public class TestPanel extends JPanel {
protected void paintComponent( Graphics g ) {
Graphics2D g2d = (Graphics2D) g;
int w = getWidth();
int h = getHeight();
Color color1 = Color.BLACK;
Color color2 = Color.GRAY;
GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
TestPanel panel = new TestPanel();
frame.add(panel);
frame.setSize(200,200);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
produces the following:
The cyclic version looks even worse than that:
How can I make the gradient look smoother (in both cases)?
EDIT:
It seems that it is (at least partially) a monitor problem. The gradient colors look awful on my netbook (1024 x 600, True Color 32-bit) while they look a lot better on my desktop pc (1280 x 1024, True Color 32-bit). But the results are still not so smooth even with the desktop's monitor.
Both are using Java Version 6 Update 33.
Does that mean that an application should only use gradient backgrounds when it is viewed with higher resolutions?
EDIT 2:
Anyway, for those facing simlar problem or are just interested in this, I think that the only solution for a gradient color to look smoother is just higher resolution (assuming that the monitor is already set to true color of course) - which is not really a solution. Like I said in a comment, I thought that a 1024 x 600 resolution would be sufficient for a simple black-to-gray gradient color but it seems that I was wrong. When the same code is run on a computer with a monitor that supports higher resolution the gradient looks better, like through my desktop's monitor, 1280 x 1024. Unfortunately I dont have an option for better resolution but I believe it would look even smoother. I also noticed that the two images that I uploaded (taken from my netbook) when they are viewed through a better monitor these same images look smoother... so it must be just the resolution.
Since there is no solution I think that the only way to use specific gradient steps that would always look smooth (like black-to-gray, which even that seems to look bad in lower resolutions) is to have the gui program test for resolution on start-up and make the choice to show the appropriate gradient but I'm not sure if it is worth it. And using less gradient steps is just a compromise.
Due to lack of more/better responses, I've accepted the use of pre-dithered images as an answer.
I see your images, but cannot reproduce the banding. Do you have your display set to TrueColor? Are you using a recent Java version? Anyway, the following line might help:
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
EDIT: it seems that dithering is not supported in Java for TrueColor gradients, even if you don't have enough shades of gray... Some ideas:
use some colors
use pre-dithered image files
http://en.wikipedia.org/wiki/Colour_banding
I can see it. I think it's because the panel's size and the number of colors don't match up. One way to make it smoother is to make the panel's size an even multiple of the number of colors in the gradient. It's not perfect, but I don't know a better way.
public class TestPanel extends JPanel {
private static final int scale = 2;
private static final Color c1 = Color.BLACK;
private static final Color c2 = Color.GRAY;
private static final int size = (c2.getRed() - c1.getRed()) * scale;
#Override
public Dimension getPreferredSize() {
return new Dimension(size, size);
}
#Override
protected void paintComponent( Graphics g ) {
Graphics2D g2d = (Graphics2D) g;
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(0, 0, c1, 0, h, c2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}