hydrodog

01-24-2014, 08: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;

}

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;

}