PDA

View Full Version : Trying to create a sphere in Processing



hydrodog
01-24-2014, 09:05 PM
I'm familiar with old OpenGL but just getting up to speed on shaders. I was writing code in Processing and took a working demo that draws a cylinder and attempted to convert it to draw a sphere.

There are three components to the code. First, there is the processing code, a class called PShape that encapsulates an OpenGL shape. The code for a cylinder uses a single QUAD_STRIP. For a sphere, I didn't come up with one, though it occurs to me that's not a bad approach. So, question 1: Does anyone have code that maps a sphere, not as a grid of quads with a north pole and south pole cap, but some kind of gently curving path that completely covers the sphere? If not, what is the best way? I was originally intending to create bands of quads that cover the majority of the sphere except for the poles, and an endcap at each pole.

When I inadvertently had a single QUAD_STRIP with the ends not connected to each other, I could see the earth, with blue and white noise on top. I realized that my code was doing a band of latitudes, and that the end of each strip was not connected to the next strip. So I tried to create a number of strips. When I do, I get all white.

I realize that this may be something involving processing, but most of the expertise for this is in OpenGL, so I'm asking here about that aspect.

bad sphere:
1220

With current code, no texture shows at all. I have left in the "can" code so you can see the code that worked creating a cylinder.
I will show first the shaders, then the Processing code that calls them. I have not changed the shaders at all.


#define PROCESSING_TEXTURE_SHADER


uniform mat4 transform;
uniform mat4 texMatrix;


attribute vec4 vertex;
attribute vec4 color;
attribute vec2 texCoord;


varying vec4 vertColor;
varying vec4 vertTexCoord;


void main() {
gl_Position = transform * vertex;

vertColor = color;
vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
}





#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif


uniform sampler2D texture;


varying vec4 vertColor;
varying vec4 vertTexCoord;


void main() {
gl_FragColor = texture2D(texture, vertTexCoord.st) * vertColor;
}




Here is the code in processing that invokes the shaders



PImage label;
PShape can;
float angle;


PShader texShader;


void setup() {
size(1280, 800, P3D);
label = loadImage("earth.jpg");
//can = createCan(100, 200, 32, label);
can = createSphere(350, 64, label);
texShader = loadShader("texfrag.glsl", "texvert.glsl");
}


void draw() {
background(0);
shader(texShader);
translate(width/2, height/2);
rotateX(-PI/2);
rotateZ(angle);
shape(can);
angle += 0.01;
}


PShape createCan(float r, float h, int detail, PImage tex) {
textureMode(NORMAL);
PShape sh = createShape();
sh.beginShape(QUAD_STRIP);
sh.noStroke();
sh.texture(tex);
for (int i = 0; i <= detail; i++) {
float angle = TWO_PI / detail;
float x = sin(i * angle);
float z = cos(i * angle);
float u = float(i) / detail;
sh.normal(x, 0, z);
sh.vertex(x * r, -h/2, z * r, u, 0);
sh.vertex(x * r, +h/2, z * r, u, 1);
}
sh.endShape();
return sh;
}


PShape createSphere(float r, int detail, PImage tex) {
textureMode(NORMAL);
PShape sh = createShape();
sh.noStroke();
sh.texture(tex);
final float dA = TWO_PI / detail; // change in angle

// process the sphere one band at a time
// going from almost south pole to almost north
// poles must be handled separately
float theta2 = -PI/2+dA;
float SHIFT = PI/2;
float z2 = sin(theta2); // height off equator
float rxyUpper = cos(theta2); // closer to equator
for (int i = 1; i < detail; i++) {
float theta1 = theta2;
theta2 = theta1 + dA;
float z1 = z2;
z2 = sin(theta2);
float rxyLower = rxyUpper;
rxyUpper = cos(theta2); // radius in xy plane
sh.beginShape(QUAD_STRIP);
for (int j = 0; j <= detail; j++) {
float phi = j * dA; //longitude in radians
float xLower = rxyLower * cos(phi);
float yLower = rxyLower * sin(phi);
float xUpper = rxyUpper * cos(phi);
float yUpper = rxyUpper * sin(phi);
float u = phi/TWO_PI;
sh.normal(xUpper, yUpper, z2);
sh.vertex(r*xUpper, r*yUpper, r*z2, u,(theta2+SHIFT)/PI);
sh.normal(xLower, yLower, z1);
sh.vertex(r*xLower, r*yLower, r*z1, u,(theta1+SHIFT)/PI);
}
sh.endShape();
}
return sh;
}