#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# How to obtain 3D textured Sphere

edited March 2018

Hello everybody, I'd like to ask what kind of technique this render is using:

http://cpetry.github.io/NormalMap-Online/

I man, I don't know how that is called, 3D texture? How can I obtain something like this? Even a simple example :)

Any reference or link will be appreciated, thank you

Tagged:

• So you mean, specifically, you want to model height distortion on the surface of a 3D sphere, like this?

• Yes, nothing too complex, just have the possibility to increase or decrease the texture level.

Here is another example but with MaxMSP: https://www.facebook.com/185345661820182/videos/530908980597180/

• in the Menu File | there are examples

Here it is Topics | Textures

there is one for cube and one for sphere

• Thank you Chrisir, but I know how to apply a play texture to a 3D shape :)

Have you seen the links I provided? There's more than a plain texture.. the shape is 3D transformed based on texture!

• edited March 2018

This is more of a proof of concept than anything else. Basically you can alter the position of a vertex based on the color of the texture at the point where the vertex would be otherwise.

``````int cols, rows;
int scl = 20;
int w = 2000;
int h = 1600;

float flying = 0;

float[][] terrain;

PImage img;

void setup() {
size(600, 600, P3D);
cols = w / scl;
rows = h/ scl;
terrain = new float[cols][rows];
String http = "http://";
img = loadImage( http + "www.tfguy44.com/MyIcon1.PNG");
texture(img);
noStroke();
}

float ax,ay;

void draw() {
lights();
//  flying -= 0.1;

//  float yoff = flying;
//  for (int y = 0; y < rows; y++) {
//    float xoff = 0;
//    for (int x = 0; x < cols; x++) {
//      terrain[x][y] = map(noise(xoff, yoff), 0, 1, -100, 100);
//      xoff += 0.2;
//    }
//    yoff += 0.2;
//  }

background(64);
//stroke(255);
//noFill();

translate(width/2, height/2);
rotateY(map(mouseX,0,width,-PI,PI));
scale(0.2);
translate(-w/2, -h/2);
for (int y = 0; y < rows-1; y++) {
beginShape(TRIANGLE_STRIP);
texture(img);
for (int x = 0; x < cols; x++) {
ax = map(x,0,cols,0,img.width);
ay = map(y,0,rows,0,img.height);

vertex(x*scl, y*scl, map(brightness(img.get(int(ax),int(ay))),0,255,0,200), ax, ay  );

ax = map(x,0,cols,0,img.width);
ay = map(y+1,0,rows,0,img.height);

vertex(x*scl, (y+1)*scl, map(brightness(img.get(int(ax),int(ay))),0,255,0,200), ax, ay );
//rect(x*scl, y*scl, scl, scl);
}
endShape();
}
}
``````
• Thank you TfGuy44, this is great! :D So you think that the "extrusion" is performed with taking the brightness of the img?

How can I add it to a Sphere instead of a plain 2d rectangle?

``````import peasy.*;
PImage img;
float x, y, z;
PeasyCam cam;
PVector [][] globe;
int total = 50;
void setup() {
size(600, 500, P3D);

globe = new PVector[total+1][total+1];
cam = new PeasyCam(this, 300);
}
float ax, ay, az;

void draw() {
background(50);
noStroke();
//lights();
//fill(255,255,0);
float r = 200;

for (int i = 0; i < total+1; i++) {
float lat = map(i, 0, total, 0, PI);
for (int j = 0; j < total+1; j++) {
float lon = map(j, 0, total, 0, TWO_PI);

x = r * sin(lat)* cos(lon);
y = r * sin(lat)* sin(lon);
z = r * cos(lat);

globe[i][j] = new PVector(x, y, z);
}
}

for (int i = 0; i < total; i++) {

beginShape(TRIANGLE_STRIP);
texture(img);
for (int j = 0; j < total+1; j++) {
PVector v = globe[i][j];
ax = map(j, 0, total, 0, img.width);
ay = map(j, 0, total, 0, img.height);
az = map(i, 0, total, 0, img.height);
vertex(v.x, v.y,  v.z + map(brightness(img.get(int(ax), int(ay))), 0, 255, 0, 100), ax, ay  );
//point(x, y, z);
PVector v2 = globe[i+1][j];
vertex(v2.x, v2.y, v.z + map(brightness(img.get(int(ax), int(ay))), 0, 255, 0, 100), ax, ay );
}
endShape();
}
}
``````

I tried, but this is soooo wrong ahah

• edited March 2018 Answer ✓

I modified the textured sphere code from here to do what you want,

edit:

This is 99% of the way there, you just have to fix it so it gets the radius for every 3rd vertex from the next row band of the strip. The triangle strip goes around in bands, it currently leaves gaps between the bands of the strip because the 3rd point of the triangle is not getting the radius from the next band.

Fixed it

lowerTween and upperTween used to adjust the bump mapping offset

The "map.png" I used

``````int ptsW, ptsH;

PGraphics pgBump;
PImage img;

int numPointsW;
int numPointsH_2pi;
int numPointsH;

float[] coorX;
float[] coorY;
float[] coorZ;
float[] multXZ;

float rot = 0, rotX = 0, rotY = 0;
int drawOp  = 20;

boolean keyDown = false;

float lTween = 2.16;
float uTween = 2.5;

void setup() {
size(640, 360, P3D);

noStroke();

ptsW=200;
ptsH=200;
// Parameters below are the number of vertices around the width and height
initializeSphere(ptsW, ptsH);
}

try {
}
finally {
if (img == null) {
img = createImage(width, height, RGB);
for (int i = 0; i < img.pixels.length; i++) img.pixels[i] = color(130);
}
}
pgBump = createGraphics(img.width, img.height, P2D);
pgBump.beginDraw();
pgBump.noStroke();
pgBump.image(img, 0, 0);
pgBump.endDraw();
}

void keyPressed() {
keyDown = true;
}
void keyReleased() {
keyDown = false;
}

void editBump() {
pgBump.beginDraw();
pgBump.image(img, 0, 0);
if (mousePressed) {
if (mouseButton == LEFT)  pgBump.fill(255, drawOp);
else pgBump.fill(0, drawOp);
}
pgBump.endDraw();
img = pgBump.get();
pgBump.beginDraw();

pgBump.fill(255, 0, 0);
pgBump.endDraw();
}

void hud() {
camera(width/2.0, height/2.0, (height/2.0) / tan(PI*30.0 / 180.0), width/2.0, height/2.0, 0, 0, 1, 0);
fill(255);
int y = -5, yS = 15;
text("lowerTween(3/4):"+ nf(lTween,0,2) + " upperTween(5/6):" + nf(uTween,0,2), 10, y+=yS);

text("rotate wasd", 10, y+=yS);
text("fps " + (int)frameRate, 10, y+=yS);
}

void keyHandle() {
if (keyDown) {
if (key == 'a') rotX += 0.01;
if (key == 'w') rotY += 0.01;
if (key == 'd') rotX -= 0.01;
if (key == 's') rotY -= 0.01;
if (key == 'q') drawRad -= 0.2;
if (key == 'e') drawRad += 0.2;
if (key == '1') drawOp -= 1;
if (key == '2') drawOp += 1;
if (key == '3') lTween -= 0.01;
if (key == '4') lTween += 0.01;
if (key == '5') uTween -= 0.01;
if (key == '6') uTween += 0.01;
drawOp = constrain(drawOp, 1, 255);
}
}

void draw() {
keyHandle();
editBump();

background(0);
hud();
lights();
camera(
width/2+map(0, 0, width, -2*width, 2*width),
height/2+map(0, 0, height, -height, height),
height/2/tan(PI*30.0 / 180.0),
width, height/2.0, 0,
0, 1, 0);
pushMatrix();
translate(width/2, height/2, 0);
rotateX(rotX);
rotateZ(rotY);

textureBumpSphere(200, img, pgBump.get(), lTween, uTween);
popMatrix();
}

void initializeSphere(int numPtsW, int numPtsH_2pi) {
// The number of points around the width and height
numPointsW=numPtsW+1;
numPointsH_2pi=numPtsH_2pi;  // How many actual pts around the sphere (not just from top to bottom)
numPointsH=ceil((float)numPointsH_2pi/2)+1;  // How many pts from top to bottom (abs(....) b/c of the possibility of an odd numPointsH_2pi)

coorX=new float[numPointsW];   // All the x-coor in a horizontal circle radius 1
coorY=new float[numPointsH];   // All the y-coor in a vertical circle radius 1
coorZ=new float[numPointsW];   // All the z-coor in a horizontal circle radius 1
multXZ=new float[numPointsH];  // The radius of each horizontal circle (that you will multiply with coorX and coorZ)

for (int i=0; i<numPointsW; i++) {  // For all the points around the width
float thetaW=i*2*PI/(numPointsW-1);
coorX[i]=sin(thetaW);
coorZ[i]=cos(thetaW);
}
for (int i=0; i<numPointsH; i++) {  // For all points from top to bottom
if (int(numPointsH_2pi/2) != (float)numPointsH_2pi/2 && i==numPointsH-1) {  // If the numPointsH_2pi is odd and it is at the last pt
float thetaH=(i-1)*2*PI/(numPointsH_2pi);
coorY[i]=cos(PI+thetaH);
multXZ[i]=0;
} else {
//The numPointsH_2pi and 2 below allows there to be a flat bottom if the numPointsH is odd
float thetaH=i*2*PI/(numPointsH_2pi);

//PI+ below makes the top always the point instead of the bottom.
coorY[i]=cos(PI+thetaH);
multXZ[i]=sin(thetaH);
}
}
}

void textureBumpSphere(float baseRadius, PImage bump, PImage tex, float lowerTween, float upperTween) {
// These are so we can map certain parts of the image on to the shape
float changeU=tex.width/(float)(numPointsW); //-1
float changeV=tex.height/(float)(numPointsH); //-1
float u=0;  // Width variable for the texture
float v=0;  // Height variable for the texture

beginShape(TRIANGLE_STRIP);
texture(tex);
for (int i=0; i<(numPointsH-1); i++) {  // For all the rings but top and bottom
// Goes into the array here instead of loop to save time
float coory=coorY[i];
float cooryPlus=coorY[i+1];
float multxz=multXZ[i];
float multxzPlus=multXZ[i+1];
for (int j=0; j<numPointsW; j++) { // For all the pts in the ring

float pixelBrightness = brightness(bump.get((int)u, (int)v)); // Get the brightnesss from the pixel of bump texture
radius = baseRadius *  map( pixelBrightness, 0, 255, lowerTween, upperTween); // map the brightness between upper and lower tween scaling to a bumped radius
normal(-coorX[j]*multxz, -coory, -coorZ[j]*multxz);

// repeat for the vertex that is 1 triangle_strip band above the last vertex
pixelBrightness = brightness(bump.get((int)u, (int)(v+changeV)));
normal(-coorX[j]*multxzPlus, -cooryPlus, -coorZ[j]*multxzPlus);
u+=changeU;
}
v+=changeV;
u=0;
}
endShape();
}
``````

result

Unfortunately to get results like the video you linked your probably going to want to do this inside of a shader, it would be hundreds-thousands times more efficient than doing it on CPU, or do it half-way on the GPU with mesh tweening.

You should check out the MeshTweening example in Examples>Demos>Graphics

edit2: I did a little more on it and added the ability to draw on the bump map in processing. I wish I knew the math to be able to convert from screen coordinates to the surface of the sphere. https://pastebin.com/Dfc4PXyZ

• Thank you lmccandless this is soooo beautiful!! I will need to study trigonometry to understand this (I can't comprehend anything ahah) but, I'm really impressed, thank you!!!

I'm out of borders if I ask you to add some comments that describe some functions? It would help me a lot :)

Than, I'll move to study shader.. so I have a LOT of work to do :D

Thank you again

• edited March 2018 Answer ✓

I also made a version that uses textures and elevation maps from NASA of the moon. The previous version recalculated the bumping of the sphere every frame, this version stores the bumped sphere in a PShape and only recalculates it when needed.

https://github.com/lmccandless/moonBumpMap

• edited March 2018

WOW =D> this is absolutely outstanding and astonishing, I will never say enough thank you for this!

I only hope someday I'll can do something like this and share some of my knowledge with other people too.

Inspirational