Checking in first round of opengl2 examples

This commit is contained in:
codeanticode
2011-02-01 09:47:13 +00:00
parent 31446d5c23
commit 0fe112e817
35 changed files with 16607 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
// Blending, by Andres Colubri
// Images can be blended using one of the 10 blending modes
// available in OPENGL2.
// Images by Kevin Bjorke.
import processing.opengl2.*;
PImage pic1, pic2;
int selMode = REPLACE;
String name = "replace";
int picAlpha = 255;
void setup() {
size(800, 480, OPENGL2);
PFont font = createFont(PFont.list()[0], 20);
textFont(font, 20);
pic1 = loadImage("bjorke1.jpg");
pic2 = loadImage("bjorke2.jpg");
}
void draw() {
background(0);
tint(255, 255);
image(pic1, 0, 0, pic1.width, pic1.height);
blend(selMode);
tint(255, picAlpha);
image(pic2, 0, 0, pic2.width, pic2.height);
noBlend();
fill(200, 50, 50);
rect(0, height - 50, map(picAlpha, 0, 255, 0, width), 50);
fill(255);
text("Selected blend mode: " + name + ". Click to move to next", 10, pic1.height + 30);
text("Drag this bar to change alpha of image", 10, height - 18);
}
void mousePressed() {
if (height - 50 < mouseY) return;
if (selMode == REPLACE) {
selMode = BLEND;
name = "blend";
} else if (selMode == BLEND) {
selMode = ADD;
name = "add";
} else if (selMode == ADD) {
selMode = SUBTRACT;
name = "subtract";
} else if (selMode == SUBTRACT) {
selMode = LIGHTEST;
name = "lightest";
} else if (selMode == LIGHTEST) {
selMode = DARKEST;
name = "darkest";
} else if (selMode == DARKEST) {
selMode = DIFFERENCE;
name = "difference";
} else if (selMode == DIFFERENCE) {
selMode = EXCLUSION;
name = "exclusion";
} else if (selMode == EXCLUSION) {
selMode = MULTIPLY;
name = "multiply";
} else if (selMode == MULTIPLY) {
selMode = SCREEN;
name = "screen";
} else if (selMode == SCREEN) {
selMode = REPLACE;
name = "replace";
}
}
void mouseDragged() {
if (height - 50 < mouseY) {
picAlpha = int(map(mouseX, 0, width, 0, 255));
}
}

View File

@@ -0,0 +1,95 @@
// Concentric, by Andres Colubri
// This example shows how to use the shape recording functionality
// to create a PShape3D object with multiple child shapes that can
// be later organized in a tree structure to apply geometrical
// transformations to different levels of the tree.
import processing.opengl2.*;
PShape3D object;
PShape group1, group2, group3;
void setup() {
size(600, 600, OPENGL2);
noStroke();
// We record all the geometry in object.
object = (PShape3D)beginRecord();
// By setting different names, the different shapes
// drawn here will be stored in the tree as separate
// child shapes.
shapeName("sphere");
fill(50, 200, 50);
sphere(50);
fill(200, 50, 50);
shapeName("torus1");
drawTorus(80, 5, 12, 48, 0);
shapeName("torus2");
drawTorus(80, 5, 12, 48, 1);
shapeName("torus3");
drawTorus(80, 5, 12, 48, 3);
fill(50, 50, 200);
shapeName("torus4");
drawTorus(150, 10, 12, 48, 0);
shapeName("torus5");
drawTorus(150, 10, 12, 48, 1);
shapeName("torus6");
drawTorus(150, 10, 12, 48, 3);
endRecord();
println("BEFORE GROUPING");
printShape(object, "");
// Now we group the child shapes by indicating the name of the shapes
// we want to put together.
group1 = object.groupChildren(new String[] {"torus1", "torus2", "torus3", "torus4", "torus5", "torus6"}, "group1");
group2 = object.groupChildren(new String[] {"torus1", "torus2", "torus3"}, "group2");
group3 = object.groupChildren(new String[] {"torus4", "torus5", "torus6"}, "group3");
println("AFTER GROUPING");
printShape(object, "");
}
void draw() {
background(0);
// Transformations to parts of the shape can be applied
// before drawing the entire object.
object.resetMatrix();
group1.resetMatrix();
group2.resetMatrix();
group3.resetMatrix();
object.translate(0, 0, map(sin(frameCount * PI / 600), -1, 1, 550, 0));
group1.scale(map(cos(frameCount * PI / 200), -1, 1, 1, 1.5));
group2.rotateX(frameCount * PI / 100);
group2.rotateY(frameCount * PI / 100);
group3.rotateX(-frameCount * PI / 140);
group3.rotateY(-frameCount * PI / 160);
pointLight(250, 250, 250, 0, 0, 400);
translate(width/2, height/2);
shape(object);
}
void printShape(PShape pshape, String tab) {
int f = pshape.getFamily();
if (f == PShape.GROUP) println(tab + "GROUP shape");
else if (f == PShape.GEOMETRY) println(tab + "GEOMETRY shape");
println(tab + "Name: " + pshape.getName());
println(tab + "Children: " + pshape.getChildCount());
for (int i = 0; i < pshape.getChildCount(); i++) {
PShape child = pshape.getChild(i);
printShape(child, tab + " ");
}
println(tab + "-------------------");
}

View File

@@ -0,0 +1,46 @@
void drawTorus(float outerRad, float innerRad, int numc, int numt, int axis) {
float x, y, z, s, t, u, v;
float nx, ny, nz;
float aInner, aOuter;
int idx = 0;
beginShape(QUAD_STRIP);
for (int i = 0; i < numc; i++) {
for (int j = 0; j <= numt; j++) {
t = j;
v = t / (float)numt;
aOuter = v * TWO_PI;
float cOut = cos(aOuter);
float sOut = sin(aOuter);
for (int k = 1; k >= 0; k--) {
s = (i + k);
u = s / (float)numc;
aInner = u * TWO_PI;
float cIn = cos(aInner);
float sIn = sin(aInner);
if (axis == 0) {
x = (outerRad + innerRad * cIn) * cOut;
y = (outerRad + innerRad * cIn) * sOut;
z = innerRad * sIn;
} else if (axis == 1) {
x = innerRad * sIn;
y = (outerRad + innerRad * cIn) * sOut;
z = (outerRad + innerRad * cIn) * cOut;
} else {
x = (outerRad + innerRad * cIn) * cOut;
y = innerRad * sIn;
z = (outerRad + innerRad * cIn) * sOut;
}
nx = cIn * cOut;
ny = cIn * sOut;
nz = sIn;
normal(nx, ny, nz);
vertex(x, y, z);
}
}
}
endShape();
}

View File

@@ -0,0 +1,198 @@
// Earth
// by Mike 'Flux' Chang (cleaned up by Aaron Koblin).
// Based on code by Toxi.
// Android port by Andres Colubri
//
// This example shows the shape recording functionality in A3D,
// where an entire geometry drawn with the regular API can be
// stored in a PShape3D object for later use. This greatly
// improves the performance of the application.
// Click on the screen to enable/disable drawing with the recorded
// shape.
import processing.opengl2.*;
PShape globe;
PImage texmap;
int sDetail = 200; // Sphere detail setting
float rotationY = 0;
float globeRadius = 450;
float pushBack = 0;
float[] cx, cz, sphereX, sphereY, sphereZ;
float sinLUT[];
float cosLUT[];
float SINCOS_PRECISION = 0.5f;
int SINCOS_LENGTH = (int)(360.0f / SINCOS_PRECISION);
boolean usingPShape = false;
public void setup() {
size(600, 600, OPENGL2);
PFont font = createFont(PFont.list()[0], 12);
textFont(font, 12);
texmap = loadImage("world32k.jpg");
initializeSphere(sDetail);
autoNormal(false);
noStroke();
// Everything that is drawn between beginRecord/endRecord
// is saved into the PShape3D returned by beginRecord.
// Drawing the PShape3D object is much faster than redrawing
// all the geometry again in the draw() function.
globe = beginRecord();
texturedSphere(globeRadius, texmap);
endRecord();
}
public void draw() {
background(0);
renderGlobe();
fill(255);
if (usingPShape) {
text("With PShape3D. FPS: " + frameRate, 10, height - 30);
} else {
text("Without PShape3D. FPS: " + frameRate, 10, height - 30);
}
}
void mousePressed() {
usingPShape = !usingPShape;
}
public void renderGlobe() {
pushMatrix();
translate(width/2.0f, height/2.0f, pushBack);
lights();
pushMatrix();
rotateY(rotationY);
if (usingPShape) {
shape(globe);
} else {
texturedSphere(globeRadius, texmap);
}
popMatrix();
popMatrix();
rotationY += 0.01;
}
public void initializeSphere(int res) {
sinLUT = new float[SINCOS_LENGTH];
cosLUT = new float[SINCOS_LENGTH];
for (int i = 0; i < SINCOS_LENGTH; i++) {
sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
}
float delta = (float)SINCOS_LENGTH/res;
float[] cx = new float[res];
float[] cz = new float[res];
// Calc unit circle in XZ plane
for (int i = 0; i < res; i++) {
cx[i] = -cosLUT[(int) (i*delta) % SINCOS_LENGTH];
cz[i] = sinLUT[(int) (i*delta) % SINCOS_LENGTH];
}
// Computing vertexlist vertexlist starts at south pole
int vertCount = res * (res-1) + 2;
int currVert = 0;
// Re-init arrays to store vertices
sphereX = new float[vertCount];
sphereY = new float[vertCount];
sphereZ = new float[vertCount];
float angle_step = (SINCOS_LENGTH*0.5f)/res;
float angle = angle_step;
// Step along Y axis
for (int i = 1; i < res; i++) {
float curradius = sinLUT[(int) angle % SINCOS_LENGTH];
float currY = -cosLUT[(int) angle % SINCOS_LENGTH];
for (int j = 0; j < res; j++) {
sphereX[currVert] = cx[j] * curradius;
sphereY[currVert] = currY;
sphereZ[currVert++] = cz[j] * curradius;
}
angle += angle_step;
}
sDetail = res;
}
// Generic routine to draw textured sphere
void texturedSphere(float r, PImage t) {
int v1,v11,v2;
r = (r + 240 ) * 0.33;
beginShape(TRIANGLE_STRIP);
texture(t);
float iu=(float)(t.width-1)/(sDetail);
float iv=(float)(t.height-1)/(sDetail);
float u=0,v=iv;
for (int i = 0; i < sDetail; i++) {
normal(0, -1, 0);
vertex(0, -r, 0,u,0);
normal(sphereX[i], sphereY[i], sphereZ[i]);
vertex(sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v);
u+=iu;
}
vertex(0, -r, 0,u,0);
normal(sphereX[0], sphereY[0], sphereZ[0]);
vertex(sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v);
endShape();
// Middle rings
int voff = 0;
for(int i = 2; i < sDetail; i++) {
v1=v11=voff;
voff += sDetail;
v2=voff;
u=0;
beginShape(TRIANGLE_STRIP);
texture(t);
for (int j = 0; j < sDetail; j++) {
normal(sphereX[v1], sphereY[v1], sphereZ[v1]);
vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v);
normal(sphereX[v2], sphereY[v2], sphereZ[v2]);
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v+iv);
u+=iu;
}
// Close each ring
v1=v11;
v2=voff;
normal(sphereX[v1], sphereY[v1], sphereZ[v1]);
vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v);
normal(sphereX[v2], sphereY[v2], sphereZ[v2]);
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v+iv);
endShape();
v+=iv;
}
u=0;
// Add the northern cap
beginShape(TRIANGLE_STRIP);
texture(t);
for (int i = 0; i < sDetail; i++) {
v2 = voff + i;
normal(sphereX[v2], sphereY[v2], sphereZ[v2]);
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v);
normal(0, 1, 0);
vertex(0, r, 0, u, v+iv);
u+=iu;
}
normal(sphereX[voff], sphereY[voff], sphereZ[voff]);
vertex(sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v);
endShape();
}

View File

@@ -0,0 +1,66 @@
// Kinetic Type, by Zach Lieberman.
//
// Using push() and pop() to define the curves of the lines of type.
import processing.opengl2.*;
Line ln;
Line lns[];
String words[] = {
"sometimes it's like", "the lines of text", "are so happy", "that they want to dance",
"or leave the page or jump", "can you blame them?", "living on the page like that",
"waiting to be read..."
};
void setup() {
size(800, 480, OPENGL2);
// Array of line objects
lns = new Line[8];
// Load the font from the sketch's data directory
textFont(loadFont("Univers-66.vlw"), 1.0);
// White type
fill(255);
// Creating the line objects
for(int i = 0; i < 8; i++) {
// For every line in the array, create a Line object to animate
// i * 70 is the spacing
ln = new Line(words[i], 0, i * 70);
lns[i] = ln;
}
hint(DISABLE_DEPTH_MASK);
}
void draw() {
background(0);
translate(-200, -50, -450);
rotateY(0.3);
// Now animate every line object & draw it...
for(int i = 0; i < 8; i++) {
float f1 = sin((i + 1.0) * (millis() / 10000.0) * TWO_PI);
float f2 = sin((8.0 - i) * (millis() / 10000.0) * TWO_PI);
Line line = lns[i];
pushMatrix();
translate(0.0, line.yPosition, 0.0);
for(int j = 0; j < line.myLetters.length; j++) {
if(j != 0) {
translate(textWidth(line.myLetters[j - 1].myChar) * 75, 0.0, 0.0);
}
rotateY(f1 * 0.005 * f2);
pushMatrix();
scale(75.0);
text(line.myLetters[j].myChar, 0.0, 0.0);
popMatrix();
}
popMatrix();
}
}

View File

@@ -0,0 +1,13 @@
class Letter
{
char myChar;
float x;
float y;
Letter(char c, float f, float f1)
{
myChar = c;
x = f;
y = f1;
}
}

View File

@@ -0,0 +1,28 @@
class Line
{
String myString;
int xPosition;
int yPosition;
int highlightNum;
float speed;
float curlInX;
Letter myLetters[];
Line(String s, int i, int j)
{
myString = s;
xPosition = i;
yPosition = j;
myLetters = new Letter[s.length()];
float f1 = 0.0;
for(int k = 0; k < s.length(); k++)
{
char c = s.charAt(k);
f1 += textWidth(c);
Letter letter = new Letter(c, f1, 0.0);
myLetters[k] = letter;
}
curlInX = 0.1;
}
}

View File

@@ -0,0 +1,10 @@
class Word
{
String myName;
int x;
Word(String s)
{
myName = s;
}
}

View File

@@ -0,0 +1,147 @@
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.io.IOException;
import java.io.InputStream;
BufferedImage loadBitmap(String file) throws IOException {
BufferedImage image;
InputStream input = null;
try {
input = createInput(file);
int bitmapFileHeaderLength = 14;
int bitmapInfoHeaderLength = 40;
byte bitmapFileHeader[] = new byte[bitmapFileHeaderLength];
byte bitmapInfoHeader[] = new byte[bitmapInfoHeaderLength];
input.read(bitmapFileHeader, 0, bitmapFileHeaderLength);
input.read(bitmapInfoHeader, 0, bitmapInfoHeaderLength);
int nSize = bytesToInt(bitmapFileHeader, 2);
int nWidth = bytesToInt(bitmapInfoHeader, 4);
int nHeight = bytesToInt(bitmapInfoHeader, 8);
int nBiSize = bytesToInt(bitmapInfoHeader, 0);
int nPlanes = bytesToShort(bitmapInfoHeader, 12);
int nBitCount = bytesToShort(bitmapInfoHeader, 14);
int nSizeImage = bytesToInt(bitmapInfoHeader, 20);
int nCompression = bytesToInt(bitmapInfoHeader, 16);
int nColoursUsed = bytesToInt(bitmapInfoHeader, 32);
int nXPixelsMeter = bytesToInt(bitmapInfoHeader, 24);
int nYPixelsMeter = bytesToInt(bitmapInfoHeader, 28);
int nImportantColours = bytesToInt(bitmapInfoHeader, 36);
if (nBitCount == 24) {
image = read24BitBitmap(nSizeImage, nHeight, nWidth, input);
}
else if (nBitCount == 8) {
image = read8BitBitmap(nColoursUsed, nBitCount, nSizeImage, nWidth, nHeight, input);
}
else {
System.out.println("Not a 24-bit or 8-bit Windows Bitmap, aborting...");
image = null;
}
}
finally {
try {
if (input != null)
input.close();
}
catch (IOException e) {
}
}
return image;
}
BufferedImage read8BitBitmap(int nColoursUsed, int nBitCount, int nSizeImage, int nWidth, int nHeight, InputStream input) throws IOException {
int nNumColors = (nColoursUsed > 0) ? nColoursUsed : (1 & 0xff) << nBitCount;
if (nSizeImage == 0) {
nSizeImage = ((((nWidth * nBitCount) + 31) & ~31) >> 3);
nSizeImage *= nHeight;
}
int npalette[] = new int[nNumColors];
byte bpalette[] = new byte[nNumColors * 4];
readBuffer(input, bpalette);
int nindex8 = 0;
for (int n = 0; n < nNumColors; n++) {
npalette[n] = (255 & 0xff) << 24 |
(bpalette[nindex8 + 2] & 0xff) << 16 |
(bpalette[nindex8 + 1] & 0xff) << 8 |
(bpalette[nindex8 + 0] & 0xff);
nindex8 += 4;
}
int npad8 = (nSizeImage / nHeight) - nWidth;
BufferedImage bufferedImage = new BufferedImage(nWidth, nHeight, BufferedImage.TYPE_INT_ARGB);
DataBufferInt dataBufferByte = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer());
int[][] bankData = dataBufferByte.getBankData();
byte bdata[] = new byte[(nWidth + npad8) * nHeight];
readBuffer(input, bdata);
nindex8 = 0;
for (int j8 = nHeight - 1; j8 >= 0; j8--) {
for (int i8 = 0; i8 < nWidth; i8++) {
bankData[0][j8 * nWidth + i8] = npalette[((int) bdata[nindex8] & 0xff)];
nindex8++;
}
nindex8 += npad8;
}
return bufferedImage;
}
BufferedImage read24BitBitmap(int nSizeImage, int nHeight, int nWidth, InputStream input) throws IOException {
int npad = (nSizeImage / nHeight) - nWidth * 3;
if (npad == 4 || npad < 0)
npad = 0;
int nindex = 0;
BufferedImage bufferedImage = new BufferedImage(nWidth, nHeight, BufferedImage.TYPE_4BYTE_ABGR);
DataBufferByte dataBufferByte = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer());
byte[][] bankData = dataBufferByte.getBankData();
byte brgb[] = new byte[(nWidth + npad) * 3 * nHeight];
readBuffer(input, brgb);
for (int j = nHeight - 1; j >= 0; j--) {
for (int i = 0; i < nWidth; i++) {
int base = (j * nWidth + i) * 4;
bankData[0][base] = (byte) 255;
bankData[0][base + 1] = brgb[nindex];
bankData[0][base + 2] = brgb[nindex + 1];
bankData[0][base + 3] = brgb[nindex + 2];
nindex += 3;
}
nindex += npad;
}
return bufferedImage;
}
int bytesToInt(byte[] bytes, int index) {
return (bytes[index + 3] & 0xff) << 24 |
(bytes[index + 2] & 0xff) << 16 |
(bytes[index + 1] & 0xff) << 8 |
bytes[index + 0] & 0xff;
}
short bytesToShort(byte[] bytes, int index) {
return (short) (((bytes[index + 1] & 0xff) << 8) |
(bytes[index + 0] & 0xff));
}
void readBuffer(InputStream in, byte[] buffer) throws IOException {
int bytesRead = 0;
int bytesToRead = buffer.length;
while (bytesToRead > 0) {
int read = in.read(buffer, bytesRead, bytesToRead);
bytesRead += read;
bytesToRead -= read;
}
}

View File

@@ -0,0 +1,238 @@
// Nehe by Andres Colubri
// Example of direct OpenGL use inside Processing with the
// OPENGL2 renderer.
// Ported from NeHe tutorial 8:
// http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=08
import processing.opengl2.*;
import javax.media.opengl.*;
import java.nio.*;
import javax.media.opengl.glu.gl2.GLUgl2;
boolean lighting = true;
boolean blending = true;
boolean depthTest = true;
boolean depthMask = false;
boolean texturing = true;
int selBlend = 1;
int selFilter = 0;
float transparency = 0.5f;
// The color depth of the sketch can be set with this
// method. The 6 numbers separated by colons correspond
// to the red, green, blue, alpha, depth and stencil bits.
// If this method is not defined, then Processing will let
// OpenGL to automatically choose the color depth.
String sketchColordepth() {
return "8:8:8:8:16:0";
}
// Whether the sketch surface supports translucenty or not.
boolean sketchTranslucency() {
return true;
}
FloatBuffer[] cubeVertexBfr;
FloatBuffer[] cubeNormalBfr;
FloatBuffer[] cubeTextureBfr;
FloatBuffer lightAmbBfr;
FloatBuffer lightDifBfr;
FloatBuffer lightPosBfr;
private IntBuffer texturesBuffer;
private float xRot;
private float yRot;
float xSpeed = 0.2f;
float ySpeed = 0.2f;
GLUgl2 glu;
void setup() {
size(400, 400, OPENGL2);
// orientation(PORTRAIT);
glu = new GLUgl2();
int SIZEOF_FLOAT = Float.SIZE / 8;
cubeVertexBfr = new FloatBuffer[6];
cubeNormalBfr = new FloatBuffer[6];
cubeTextureBfr = new FloatBuffer[6];
for (int i = 0; i < 6; i++) {
ByteBuffer vbb = ByteBuffer.allocateDirect(4 * 3 * SIZEOF_FLOAT);
vbb.order(ByteOrder.nativeOrder());
cubeVertexBfr[i] = vbb.asFloatBuffer();
cubeVertexBfr[i].put(cubeVertexCoords[i]);
cubeVertexBfr[i].flip();
ByteBuffer nbb = ByteBuffer.allocateDirect(4 * 3 * SIZEOF_FLOAT);
nbb.order(ByteOrder.nativeOrder());
cubeNormalBfr[i] = nbb.asFloatBuffer();
cubeNormalBfr[i].put(cubeNormalCoords[i]);
cubeNormalBfr[i].flip();
ByteBuffer tbb = ByteBuffer.allocateDirect(4 * 2 * SIZEOF_FLOAT);
tbb.order(ByteOrder.nativeOrder());
cubeTextureBfr[i] = tbb.asFloatBuffer();
cubeTextureBfr[i].put(cubeTextureCoords[i]);
cubeTextureBfr[i].flip();
}
lightAmbBfr = FloatBuffer.wrap(lightAmb);
lightDifBfr = FloatBuffer.wrap(lightDif);
lightPosBfr = FloatBuffer.wrap(lightPos);
PGraphicsOpenGL2 pgl = (PGraphicsOpenGL2)g;
GL gl = pgl.beginGL();
Texture teximage = null;
try {
teximage = readTexture("glass.bmp");
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
texturesBuffer = IntBuffer.allocate(3);
gl.glGenTextures(3, texturesBuffer);
gl.glEnable(GL.GL_TEXTURE_2D);
// setup texture 0 with nearest filtering
gl.glBindTexture(GL.GL_TEXTURE_2D, texturesBuffer.get(0));
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
makeRGBTexture(gl, glu, teximage, GL.GL_TEXTURE_2D, false);
// setup texture 1 with linear filtering for both minification and magnification,
// this is usually called bilinear sampling
gl.glBindTexture(GL.GL_TEXTURE_2D, texturesBuffer.get(1));
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
makeRGBTexture(gl, glu, teximage, GL.GL_TEXTURE_2D, false);
// setup texture 2 with linear filtering for magnification and linear-linear mipmapping
// (trilinear sampling)
gl.glBindTexture(GL.GL_TEXTURE_2D, texturesBuffer.get(2));
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
makeRGBTexture(gl, glu, teximage, GL.GL_TEXTURE_2D, true);
gl.glDisable(GL.GL_TEXTURE_2D);
pgl.endGL();
}
public void draw() {
background(0);
PGraphicsOpenGL2 pgl = (PGraphicsOpenGL2)g;
GL gl = pgl.beginGL();
pgl.gl2f.glShadeModel(GL2.GL_SMOOTH);
gl.glClearColor(0, 0, 0, 0);
if (depthTest) {
gl.glClearDepthf(1.0f);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
}
else {
gl.glDisable(GL.GL_DEPTH_TEST);
}
gl.glDepthMask(depthMask);
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
// lighting
gl.glEnable(GL2.GL_LIGHT0);
pgl.gl2f.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, lightAmbBfr);
pgl.gl2f.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, lightDifBfr);
pgl.gl2f.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, lightPosBfr);
// blending
gl.glEnable(GL2.GL_COLOR_MATERIAL);
pgl.gl2f.glColor4f(1.0f, 1.0f, 1.0f, transparency);
if (selBlend == 0) {
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
}
else if (selBlend == 1) {
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
}
gl.glViewport(0, 0, width, height);
// setup projection matrix
pgl.gl2f.glMatrixMode(GL2.GL_PROJECTION);
pgl.gl2f.glLoadIdentity();
glu.gluPerspective(45.0f, (float)width / (float)height, 1.0f, 100.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
pgl.gl2f.glMatrixMode(GL2.GL_MODELVIEW);
pgl.gl2f.glLoadIdentity();
// update lighting
if (lighting) {
gl.glEnable(GL2.GL_LIGHTING);
}
else {
gl.glDisable(GL2.GL_LIGHTING);
}
// update blending
if (blending) {
gl.glEnable(GL.GL_BLEND);
gl.glDisable(GL.GL_CULL_FACE);
}
else {
gl.glDisable(GL.GL_BLEND);
gl.glEnable(GL.GL_CULL_FACE);
}
pgl.gl2f.glTranslatef(0, 0, -6);
pgl.gl2f.glRotatef(xRot, 1, 0, 0);
pgl.gl2f.glRotatef(yRot, 0, 1, 0);
if (texturing) {
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL.GL_TEXTURE_2D, texturesBuffer.get(selFilter));
}
pgl.gl2f.glEnableClientState(GL2.GL_VERTEX_ARRAY);
pgl.gl2f.glEnableClientState(GL2.GL_NORMAL_ARRAY);
if (texturing) pgl.gl2f.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
for (int i = 0; i < 6; i++) // draw each face
{
pgl.gl2f.glVertexPointer(3, GL.GL_FLOAT, 0, cubeVertexBfr[i]);
if (texturing) pgl.gl2f.glTexCoordPointer(2, GL.GL_FLOAT, 0, cubeTextureBfr[i]);
pgl.gl2f.glNormalPointer(GL.GL_FLOAT, 0, cubeNormalBfr[i]);
pgl.gl2f.glDrawArrays(GL.GL_TRIANGLE_FAN, 0, 4);
}
pgl.gl2f.glDisableClientState(GL2.GL_VERTEX_ARRAY);
pgl.gl2f.glDisableClientState(GL2.GL_NORMAL_ARRAY);
if (texturing) {
pgl.gl2f.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
gl.glDisable(GL.GL_TEXTURE_2D);
}
// update rotations
xRot += xSpeed;
yRot += ySpeed;
pgl.endGL();
}
void makeRGBTexture(GL gl, GLUgl2 glu, Texture img, int target, boolean mipmapped) {
if (mipmapped) {
glu.gluBuild2DMipmaps(target, GL.GL_RGB8, img.getWidth(), img.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
} else {
gl.glTexImage2D(target, 0, GL.GL_RGB, img.getWidth(), img.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
}
}

View File

@@ -0,0 +1,82 @@
import com.sun.opengl.util.BufferUtil;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.nio.ByteBuffer;
Texture readTexture(String filename) throws IOException {
return readTexture(filename, false);
}
Texture readTexture(String filename, boolean storeAlphaChannel) throws IOException {
BufferedImage bufferedImage;
if (filename.endsWith(".bmp")) {
bufferedImage = loadBitmap(filename);
}
else {
bufferedImage = readImage(filename);
}
return readPixels(bufferedImage, storeAlphaChannel);
}
BufferedImage readImage(String resourceName) throws IOException {
return ImageIO.read(createInput(resourceName));
}
Texture readPixels(BufferedImage img, boolean storeAlphaChannel) {
int[] packedPixels = new int[img.getWidth() * img.getHeight()];
PixelGrabber pixelgrabber = new PixelGrabber(img, 0, 0, img.getWidth(), img.getHeight(), packedPixels, 0, img.getWidth());
try {
pixelgrabber.grabPixels();
}
catch (InterruptedException e) {
throw new RuntimeException();
}
int bytesPerPixel = storeAlphaChannel ? 4 : 3;
ByteBuffer unpackedPixels = BufferUtil.newByteBuffer(packedPixels.length * bytesPerPixel);
for (int row = img.getHeight() - 1; row >= 0; row--) {
for (int col = 0; col < img.getWidth(); col++) {
int packedPixel = packedPixels[row * img.getWidth() + col];
unpackedPixels.put((byte) ((packedPixel >> 16) & 0xFF));
unpackedPixels.put((byte) ((packedPixel >> 8) & 0xFF));
unpackedPixels.put((byte) ((packedPixel >> 0) & 0xFF));
if (storeAlphaChannel) {
unpackedPixels.put((byte) ((packedPixel >> 24) & 0xFF));
}
}
}
unpackedPixels.flip();
return new Texture(unpackedPixels, img.getWidth(), img.getHeight());
}
class Texture {
ByteBuffer pixels;
int width;
int height;
public Texture(ByteBuffer pixels, int width, int height) {
this.height = height;
this.pixels = pixels;
this.width = width;
}
public int getHeight() {
return height;
}
public ByteBuffer getPixels() {
return pixels;
}
public int getWidth() {
return width;
}
}

View File

@@ -0,0 +1,147 @@
float[][] cubeVertexCoords = new float[][] {
new float[] { // top
1, 1,-1,
-1, 1,-1,
-1, 1, 1,
1, 1, 1
}
,
new float[] { // bottom
1,-1, 1,
-1,-1, 1,
-1,-1,-1,
1,-1,-1
}
,
new float[] { // front
1, 1, 1,
-1, 1, 1,
-1,-1, 1,
1,-1, 1
}
,
new float[] { // back
1,-1,-1,
-1,-1,-1,
-1, 1,-1,
1, 1,-1
}
,
new float[] { // left
-1, 1, 1,
-1, 1,-1,
-1,-1,-1,
-1,-1, 1
}
,
new float[] { // right
1, 1,-1,
1, 1, 1,
1,-1, 1,
1,-1,-1
}
,
};
float[][] cubeNormalCoords = new float[][] {
new float[] { // top
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0
}
,
new float[] { // bottom
0,-1, 0,
0,-1, 0,
0,-1, 0,
0,-1, 0
}
,
new float[] { // front
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1
}
,
new float[] { // back
0, 0,-1,
0, 0,-1,
0, 0,-1,
0, 0,-1
}
,
new float[] { // left
-1, 0, 0,
-1, 0, 0,
-1, 0, 0,
-1, 0, 0
}
,
new float[] { // right
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0
}
,
};
float[][] cubeTextureCoords = new float[][] {
new float[] { // top
1, 0,
1, 1,
0, 1,
0, 0
}
,
new float[] { // bottom
0, 0,
1, 0,
1, 1,
0, 1
}
,
new float[] { // front
1, 1,
0, 1,
0, 0,
1, 0
}
,
new float[] { // back
0, 1,
0, 0,
1, 0,
1, 1
}
,
new float[] { // left
1, 1,
0, 1,
0, 0,
1, 0
}
,
new float[] { // right
0, 1,
0, 0,
1, 0,
1, 1
}
,
};
float lightAmb[]= {
0.5f, 0.5f, 0.5f, 1.0f
};
float lightDif[]= {
1.0f, 1.0f, 1.0f, 1.0f
};
float lightPos[]= {
0.0f, 0.0f, 2.0f, 1.0f
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,261 @@
// Implementation of 1D, 2D, and 3D Perlin noise. Based on the
// C code by Paul Bourke:
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/perlin/
class Perlin {
int B = 0x100;
int BM = 0xff;
int N = 0x1000;
int NP = 12;
int NM = 0xfff;
int p[];
float g3[][];
float g2[][];
float g1[];
void normalize2(float v[]) {
float s = sqrt(v[0] * v[0] + v[1] * v[1]);
v[0] = v[0] / s;
v[1] = v[1] / s;
}
void normalize3(float v[]) {
float s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] = v[0] / s;
v[1] = v[1] / s;
v[2] = v[2] / s;
}
float sCurve(float t) {
return t * t * (3.0 - 2.0 * t);
}
float at2(float q[], float rx, float ry) {
return rx * q[0] + ry * q[1];
}
float at3(float q[], float rx, float ry, float rz) {
return rx * q[0] + ry * q[1] + rz * q[2];
}
Perlin() {
p = new int[B + B + 2];
g3 = new float[B + B + 2][3];
g2 = new float[B + B + 2][2];
g1 = new float[B + B + 2];
init();
}
void init() {
int i, j, k;
for (i = 0 ; i < B ; i++) {
p[i] = i;
g1[i] = (random(B + B) - B) / B;
for (j = 0 ; j < 2 ; j++)
g2[i][j] = (random(B + B) - B) / B;
normalize2(g2[i]);
for (j = 0 ; j < 3 ; j++)
g3[i][j] = (random(B + B) - B) / B;
normalize3(g3[i]);
}
while (0 < --i) {
k = p[i];
p[i] = p[j = int(random(B))];
p[j] = k;
}
for (i = 0 ; i < B + 2 ; i++) {
p[B + i] = p[i];
g1[B + i] = g1[i];
for (j = 0 ; j < 2 ; j++)
g2[B + i][j] = g2[i][j];
for (j = 0 ; j < 3 ; j++)
g3[B + i][j] = g3[i][j];
}
}
float noise1(float[] vec) {
int bx0, bx1;
float rx0, rx1, sx, t, u, v;
t = vec[0] + N;
bx0 = int(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - int(t);
rx1 = rx0 - 1.0;
sx = sCurve(rx0);
u = rx0 * g1[p[bx0]];
v = rx1 * g1[p[bx1]];
return lerp(u, v, sx);
}
float noise2(float[] vec) {
int bx0, bx1, by0, by1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
float[] q;
int i, j;
t = vec[0] + N;
bx0 = int(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - int(t);
rx1 = rx0 - 1.0;
t = vec[1] + N;
by0 = int(t) & BM;
by1 = (by0 + 1) & BM;
ry0 = t - int(t);
ry1 = ry0 - 1.0;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
sx = sCurve(rx0);
sy = sCurve(ry0);
q = g2[b00];
u = at2(q, rx0, ry0);
q = g2[b10];
v = at2(q, rx1, ry0);
a = lerp(u, v, sx);
q = g2[b01] ;
u = at2(q, rx0, ry1);
q = g2[b11] ;
v = at2(q, rx1, ry1);
b = lerp(u, v, sx);
return lerp(a, b, sy);
}
float noise3(float[] vec) {
int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
float[] q;
int i, j;
t = vec[0] + N;
bx0 = int(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - int(t);
rx1 = rx0 - 1.0;
t = vec[1] + N;
by0 = int(t) & BM;
by1 = (by0 + 1) & BM;
ry0 = t - int(t);
ry1 = ry0 - 1.0;
t = vec[2] + N;
bz0 = int(t) & BM;
bz1 = (bz0 + 1) & BM;
rz0 = t - int(t);
rz1 = rz0 - 1.0;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
t = sCurve(rx0);
sy = sCurve(ry0);
sz = sCurve(rz0);
q = g3[b00 + bz0];
u = at3(q, rx0, ry0, rz0);
q = g3[b10 + bz0];
v = at3(q, rx1, ry0, rz0);
a = lerp(u, v, t);
q = g3[b01 + bz0];
u = at3(q, rx0, ry1, rz0);
q = g3[b11 + bz0];
v = at3(q, rx1, ry1, rz0);
b = lerp(u, v, t);
c = lerp(a, b, sy);
q = g3[b00 + bz1];
u = at3(q, rx0, ry0, rz1);
q = g3[b10 + bz1];
v = at3(q, rx1, ry0, rz1);
a = lerp(u, v, t);
q = g3[b01 + bz1];
u = at3(q, rx0, ry1, rz1);
q = g3[b11 + bz1];
v = at3(q, rx1, ry1, rz1);
b = lerp(u, v, t);
d = lerp(a, b, sy);
return lerp(c, d, sz);
}
// In what follows "nalpha" is the weight when the sum is formed.
// Typically it is 2, as this approaches 1 the function is noisier.
// "nbeta" is the harmonic scaling/spacing, typically 2. n is the
// number of harmonics added up in the final result. Higher number
// results in more detailed noise.
float noise1D(float x, float nalpha, float nbeta, int n) {
float val, sum = 0;
float v[] = {x};
float nscale = 1;
for (int i = 0; i < n; i++) {
val = noise1(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
}
return sum;
}
float noise2D(float x, float y, float nalpha, float nbeta, int n) {
float val,sum = 0;
float v[] = {x, y};
float nscale = 1;
for (int i = 0; i < n; i++) {
val = noise2(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
v[1] *= nbeta;
}
return sum;
}
float noise3D(float x, float y, float z, float nalpha, float nbeta, int n) {
float val, sum = 0;
float v[] = {x, y, z};
float nscale = 1;
for (int i = 0 ; i < n; i++) {
val = noise3(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
v[1] *= nbeta;
v[2] *= nbeta;
}
return sum;
}
}

View File

@@ -0,0 +1,129 @@
// Planets, by Andres Colubri
// This example uses the beginRecord/endRecord method to save
// an entire shape geometry into a PShape3D object for faster
// drawing. It also demonstrates mulitexturing and displacement
// of texture coordinates
// Sun and mercury textures from http://planetpixelemporium.com
// Star field picture from http://www.galacticimages.com/
import processing.opengl2.*;
PImage starfield;
PShape sun;
PImage suntex;
PShape planet1;
PImage surftex1;
PImage cloudtex;
PShape planet2;
PImage surftex2;
void setup() {
size(480, 800, OPENGL2);
starfield = loadImage("starfield.jpg");
suntex = loadImage("sun.jpg");
surftex1 = loadImage("planet.jpg");
// We need trilinear sampling for this texture so it looks good
// even when rendered very small.
PTexture.Parameters params1 = PTexture.newParameters(ARGB, TRILINEAR);
surftex2 = loadImage("mercury.jpg", params1);
// The clouds texture will "move" having the values of its u
// texture coordinates displaced by adding a constant increment
// in each frame. This requires REPEAT wrapping mode so texture
// coordinates can be larger than 1.
PTexture.Parameters params2 = PTexture.newParameters();
params2.wrapU = REPEAT;
cloudtex = createImage(512, 256, ARGB, params2);
// Using 3D Perlin noise to generate a clouds texture that is seamless on
// its edges so it can be applied on a sphere.
println("Generating clouds texture. It takes some time, please wait...");
cloudtex.loadPixels();
Perlin perlin = new Perlin();
for (int j = 0; j < cloudtex.height; j++) {
for (int i = 0; i < cloudtex.width; i++) {
// The angle values corresponding to each u,v pair:
float u = float(i) / cloudtex.width;
float v = float(j) / cloudtex.height;
float phi = map(u, 0, 1, TWO_PI, 0);
float theta = map(v, 0, 1, -HALF_PI, HALF_PI);
// The x, y, z point corresponding to these angles:
float x = cos(phi) * cos(theta);
float y = sin(theta);
float z = sin(phi) * cos(theta);
float n = perlin.noise3D(x, y, z, 1.2, 2, 8);
cloudtex.pixels[j * cloudtex.width + i] = color(255, 255, 255, 255 * n * n);
}
}
cloudtex.updatePixels();
println("Done.");
textureMode(NORMAL);
noStroke();
fill(255);
sun = beginRecord();
drawSphere(150, 40, suntex, null);
endRecord();
planet1 = beginRecord();
drawSphere(150, 40, surftex1, cloudtex);
endRecord();
planet2 = beginRecord();
drawSphere(50, 20, surftex2, null);
endRecord();
}
void draw() {
// Even we draw a full screen image after this, it is recommended to use
// background to clear the screen anyways, otherwise A3D will think
// you want to keep each drawn frame in the framebuffer, which results in
// slower rendering.
background(0);
// Disabling writing to the depth mask so the
// background image doesn't occludes any 3D object.
hint(DISABLE_DEPTH_MASK);
image(starfield, 0, 0, width, height);
hint(ENABLE_DEPTH_MASK);
// Displacing the u texture coordinate of layer 1 in planet
// so it creates the effect of moving clouds.
PShape3D p = (PShape3D)planet1;
p.loadTexcoords(1);
for (int i = 0; i < p.getVertexCount(); i++) {
float u = p.texcoords[2 * i + 0];
u += 0.002;
p.texcoords[2 * i + 0] = u;
}
p.updateTexcoords();
pushMatrix();
translate(width/2, height/2, -100);
pushMatrix();
rotateY(PI * frameCount / 500);
shape(sun);
popMatrix();
pointLight(255, 255, 255, 0, 0, 0);
rotateY(PI * frameCount / 300);
translate(0, 0, 300);
shape(planet2);
popMatrix();
noLights();
pointLight(255, 255, 255, 0, 0, 100);
translate(0.75 * width, 0.6 * height, 350);
shape(planet1);
}

View File

@@ -0,0 +1,79 @@
// Just draws an sphere of the given radius and resolutoin, using up to
// two images for texturing.
void drawSphere(float r, int n, PImage tex0, PImage tex1) {
float startLat = -90;
float startLon = 0.0;
float latInc = 180.0 / n;
float lonInc = 360.0 / n;
float u, v;
float phi1, phi2;
float theta1, theta2;
PVector p0 = new PVector();
PVector p1 = new PVector();
PVector p2 = new PVector();
beginShape(TRIANGLES);
if (tex1 != null) {
texture(tex0, tex1);
} else {
texture(tex0);
}
for (int col = 0; col < n; col++) {
phi1 = (startLon + col * lonInc) * DEG_TO_RAD;
phi2 = (startLon + (col + 1) * lonInc) * DEG_TO_RAD;
for (int row = 0; row < n; row++) {
theta1 = (startLat + row * latInc) * DEG_TO_RAD;
theta2 = (startLat + (row + 1) * latInc) * DEG_TO_RAD;
p0.x = cos(phi1) * cos(theta1);
p0.y = sin(theta1);
p0.z = sin(phi1) * cos(theta1);
p1.x = cos(phi1) * cos(theta2);
p1.y = sin(theta2);
p1.z = sin(phi1) * cos(theta2);
p2.x = cos(phi2) * cos(theta2);
p2.y = sin(theta2);
p2.z = sin(phi2) * cos(theta2);
normal(p0.x, p0.y, p0.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p0.x, r * p0.y, r * p0.z, u, v);
normal(p1.x, p1.y, p1.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p1.x, r * p1.y, r * p1.z, u, v);
normal(p2.x, p2.y, p2.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p2.x, r * p2.y, r * p2.z, u, v);
p1.x = cos(phi2) * cos(theta1);
p1.y = sin(theta1);
p1.z = sin(phi2) * cos(theta1);
normal(p0.x, p0.y, p0.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p0.x, r * p0.y, r * p0.z, u, v);
normal(p2.x, p2.y, p2.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p2.x, r * p2.y, r * p2.z, u, v);
normal(p1.x, p1.y, p1.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p1.x, r * p1.y, r * p1.z, u, v);
}
}
endShape();
}

View File

@@ -0,0 +1,261 @@
// Implementation of 1D, 2D, and 3D Perlin noise. Based on the
// C code by Paul Bourke:
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/perlin/
class Perlin {
int B = 0x100;
int BM = 0xff;
int N = 0x1000;
int NP = 12;
int NM = 0xfff;
int p[];
float g3[][];
float g2[][];
float g1[];
void normalize2(float v[]) {
float s = sqrt(v[0] * v[0] + v[1] * v[1]);
v[0] = v[0] / s;
v[1] = v[1] / s;
}
void normalize3(float v[]) {
float s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] = v[0] / s;
v[1] = v[1] / s;
v[2] = v[2] / s;
}
float sCurve(float t) {
return t * t * (3.0 - 2.0 * t);
}
float at2(float q[], float rx, float ry) {
return rx * q[0] + ry * q[1];
}
float at3(float q[], float rx, float ry, float rz) {
return rx * q[0] + ry * q[1] + rz * q[2];
}
Perlin() {
p = new int[B + B + 2];
g3 = new float[B + B + 2][3];
g2 = new float[B + B + 2][2];
g1 = new float[B + B + 2];
init();
}
void init() {
int i, j, k;
for (i = 0 ; i < B ; i++) {
p[i] = i;
g1[i] = (random(B + B) - B) / B;
for (j = 0 ; j < 2 ; j++)
g2[i][j] = (random(B + B) - B) / B;
normalize2(g2[i]);
for (j = 0 ; j < 3 ; j++)
g3[i][j] = (random(B + B) - B) / B;
normalize3(g3[i]);
}
while (0 < --i) {
k = p[i];
p[i] = p[j = int(random(B))];
p[j] = k;
}
for (i = 0 ; i < B + 2 ; i++) {
p[B + i] = p[i];
g1[B + i] = g1[i];
for (j = 0 ; j < 2 ; j++)
g2[B + i][j] = g2[i][j];
for (j = 0 ; j < 3 ; j++)
g3[B + i][j] = g3[i][j];
}
}
float noise1(float[] vec) {
int bx0, bx1;
float rx0, rx1, sx, t, u, v;
t = vec[0] + N;
bx0 = int(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - int(t);
rx1 = rx0 - 1.0;
sx = sCurve(rx0);
u = rx0 * g1[p[bx0]];
v = rx1 * g1[p[bx1]];
return lerp(u, v, sx);
}
float noise2(float[] vec) {
int bx0, bx1, by0, by1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
float[] q;
int i, j;
t = vec[0] + N;
bx0 = int(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - int(t);
rx1 = rx0 - 1.0;
t = vec[1] + N;
by0 = int(t) & BM;
by1 = (by0 + 1) & BM;
ry0 = t - int(t);
ry1 = ry0 - 1.0;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
sx = sCurve(rx0);
sy = sCurve(ry0);
q = g2[b00];
u = at2(q, rx0, ry0);
q = g2[b10];
v = at2(q, rx1, ry0);
a = lerp(u, v, sx);
q = g2[b01] ;
u = at2(q, rx0, ry1);
q = g2[b11] ;
v = at2(q, rx1, ry1);
b = lerp(u, v, sx);
return lerp(a, b, sy);
}
float noise3(float[] vec) {
int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
float[] q;
int i, j;
t = vec[0] + N;
bx0 = int(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - int(t);
rx1 = rx0 - 1.0;
t = vec[1] + N;
by0 = int(t) & BM;
by1 = (by0 + 1) & BM;
ry0 = t - int(t);
ry1 = ry0 - 1.0;
t = vec[2] + N;
bz0 = int(t) & BM;
bz1 = (bz0 + 1) & BM;
rz0 = t - int(t);
rz1 = rz0 - 1.0;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
t = sCurve(rx0);
sy = sCurve(ry0);
sz = sCurve(rz0);
q = g3[b00 + bz0];
u = at3(q, rx0, ry0, rz0);
q = g3[b10 + bz0];
v = at3(q, rx1, ry0, rz0);
a = lerp(u, v, t);
q = g3[b01 + bz0];
u = at3(q, rx0, ry1, rz0);
q = g3[b11 + bz0];
v = at3(q, rx1, ry1, rz0);
b = lerp(u, v, t);
c = lerp(a, b, sy);
q = g3[b00 + bz1];
u = at3(q, rx0, ry0, rz1);
q = g3[b10 + bz1];
v = at3(q, rx1, ry0, rz1);
a = lerp(u, v, t);
q = g3[b01 + bz1];
u = at3(q, rx0, ry1, rz1);
q = g3[b11 + bz1];
v = at3(q, rx1, ry1, rz1);
b = lerp(u, v, t);
d = lerp(a, b, sy);
return lerp(c, d, sz);
}
// In what follows "nalpha" is the weight when the sum is formed.
// Typically it is 2, as this approaches 1 the function is noisier.
// "nbeta" is the harmonic scaling/spacing, typically 2. n is the
// number of harmonics added up in the final result. Higher number
// results in more detailed noise.
float noise1D(float x, float nalpha, float nbeta, int n) {
float val, sum = 0;
float v[] = {x};
float nscale = 1;
for (int i = 0; i < n; i++) {
val = noise1(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
}
return sum;
}
float noise2D(float x, float y, float nalpha, float nbeta, int n) {
float val,sum = 0;
float v[] = {x, y};
float nscale = 1;
for (int i = 0; i < n; i++) {
val = noise2(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
v[1] *= nbeta;
}
return sum;
}
float noise3D(float x, float y, float z, float nalpha, float nbeta, int n) {
float val, sum = 0;
float v[] = {x, y, z};
float nscale = 1;
for (int i = 0 ; i < n; i++) {
val = noise3(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
v[1] *= nbeta;
v[2] *= nbeta;
}
return sum;
}
}

View File

@@ -0,0 +1,495 @@
import processing.core.*;
import processing.xml.*;
import processing.opengl2.*;
import java.applet.*;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.MouseEvent;
import java.awt.event.KeyEvent;
import java.awt.event.FocusEvent;
import java.awt.Image;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
import java.util.regex.*;
public class Planets extends PApplet {
// Planets, by Andres Colubri
// This example uses the beginRecord/endRecord method to save
// an entire shape geometry into a PShape3D object for faster
// drawing. It also demonstrates mulitexturing and displacement
// of texture coordinates
// Sun and mercury textures from http://planetpixelemporium.com
// Star field picture from http://www.galacticimages.com/
PImage starfield;
PShape sun;
PImage suntex;
PShape planet1;
PImage surftex1;
PImage cloudtex;
PShape planet2;
PImage surftex2;
public void setup() {
size(480, 800, OPENGL2);
//orientation(PORTRAIT);
starfield = loadImage("starfield.jpg");
suntex = loadImage("sun.jpg");
surftex1 = loadImage("planet.jpg");
// We need trilinear sampling for this texture so it looks good
// even when rendered very small.
PTexture.Parameters params1 = PTexture.newParameters(ARGB, TRILINEAR);
surftex2 = loadImage("mercury.jpg", params1);
// The clouds texture will "move" having the values of its u
// texture coordinates displaced by adding a constant increment
// in each frame. This requires REPEAT wrapping mode so texture
// coordinates can be larger than 1.
PTexture.Parameters params2 = PTexture.newParameters();
params2.wrapU = REPEAT;
cloudtex = createImage(512, 256, ARGB, params2);
// Using 3D Perlin noise to generate a clouds texture that is seamless on
// its edges so it can be applied on a sphere.
println("Generating clouds texture. It takes some time, please wait...");
cloudtex.loadPixels();
Perlin perlin = new Perlin();
for (int j = 0; j < cloudtex.height; j++) {
for (int i = 0; i < cloudtex.width; i++) {
// The angle values corresponding to each u,v pair:
float u = PApplet.parseFloat(i) / cloudtex.width;
float v = PApplet.parseFloat(j) / cloudtex.height;
float phi = map(u, 0, 1, TWO_PI, 0);
float theta = map(v, 0, 1, -HALF_PI, HALF_PI);
// The x, y, z point corresponding to these angles:
float x = cos(phi) * cos(theta);
float y = sin(theta);
float z = sin(phi) * cos(theta);
float n = perlin.noise3D(x, y, z, 1.2f, 2, 8);
cloudtex.pixels[j * cloudtex.width + i] = color(255, 255, 255, 255 * n * n);
}
}
cloudtex.updatePixels();
println("Done.");
textureMode(NORMAL);
noStroke();
fill(255);
sun = beginShapeRecord();
drawSphere(150, 40, suntex, null);
endShapeRecord();
planet1 = beginShapeRecord();
drawSphere(150, 40, surftex1, cloudtex);
endShapeRecord();
planet2 = beginShapeRecord();
drawSphere(50, 20, surftex2, null);
endShapeRecord();
}
public void draw() {
// Even we draw a full screen image after this, it is recommended to use
// background to clear the screen anyways, otherwise A3D will think
// you want to keep each drawn frame in the framebuffer, which results in
// slower rendering.
background(0);
// Disabling writing to the depth mask so the
// background image doesn't occludes any 3D object.
hint(DISABLE_DEPTH_MASK);
image(starfield, 0, 0, width, height);
hint(ENABLE_DEPTH_MASK);
// Displacing the u texture coordinate of layer 1 in planet
// so it creates the effect of moving clouds.
PShape3D p = (PShape3D)planet1;
p.loadTexcoords(1);
for (int i = 0; i < p.getVertexCount(); i++) {
float u = p.texcoords[2 * i + 0];
u += 0.002f;
p.texcoords[2 * i + 0] = u;
}
p.updateTexcoords();
pushMatrix();
translate(width/2, height/2, -100);
pushMatrix();
rotateY(PI * frameCount / 500);
shape(sun);
popMatrix();
pointLight(255, 255, 255, 0, 0, 0);
rotateY(PI * frameCount / 300);
translate(0, 0, 300);
shape(planet2);
popMatrix();
noLights();
pointLight(255, 255, 255, 0, 0, 100);
translate(0.75f * width, 0.6f * height, 350);
shape(planet1);
}
// Implementation of 1D, 2D, and 3D Perlin noise. Based on the
// C code by Paul Bourke:
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/perlin/
class Perlin {
int B = 0x100;
int BM = 0xff;
int N = 0x1000;
int NP = 12;
int NM = 0xfff;
int p[];
float g3[][];
float g2[][];
float g1[];
public void normalize2(float v[]) {
float s = sqrt(v[0] * v[0] + v[1] * v[1]);
v[0] = v[0] / s;
v[1] = v[1] / s;
}
public void normalize3(float v[]) {
float s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] = v[0] / s;
v[1] = v[1] / s;
v[2] = v[2] / s;
}
public float sCurve(float t) {
return t * t * (3.0f - 2.0f * t);
}
public float at2(float q[], float rx, float ry) {
return rx * q[0] + ry * q[1];
}
public float at3(float q[], float rx, float ry, float rz) {
return rx * q[0] + ry * q[1] + rz * q[2];
}
Perlin() {
p = new int[B + B + 2];
g3 = new float[B + B + 2][3];
g2 = new float[B + B + 2][2];
g1 = new float[B + B + 2];
init();
}
public void init() {
int i, j, k;
for (i = 0 ; i < B ; i++) {
p[i] = i;
g1[i] = (random(B + B) - B) / B;
for (j = 0 ; j < 2 ; j++)
g2[i][j] = (random(B + B) - B) / B;
normalize2(g2[i]);
for (j = 0 ; j < 3 ; j++)
g3[i][j] = (random(B + B) - B) / B;
normalize3(g3[i]);
}
while (0 < --i) {
k = p[i];
p[i] = p[j = PApplet.parseInt(random(B))];
p[j] = k;
}
for (i = 0 ; i < B + 2 ; i++) {
p[B + i] = p[i];
g1[B + i] = g1[i];
for (j = 0 ; j < 2 ; j++)
g2[B + i][j] = g2[i][j];
for (j = 0 ; j < 3 ; j++)
g3[B + i][j] = g3[i][j];
}
}
public float noise1(float[] vec) {
int bx0, bx1;
float rx0, rx1, sx, t, u, v;
t = vec[0] + N;
bx0 = PApplet.parseInt(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - PApplet.parseInt(t);
rx1 = rx0 - 1.0f;
sx = sCurve(rx0);
u = rx0 * g1[p[bx0]];
v = rx1 * g1[p[bx1]];
return lerp(u, v, sx);
}
public float noise2(float[] vec) {
int bx0, bx1, by0, by1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
float[] q;
int i, j;
t = vec[0] + N;
bx0 = PApplet.parseInt(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - PApplet.parseInt(t);
rx1 = rx0 - 1.0f;
t = vec[1] + N;
by0 = PApplet.parseInt(t) & BM;
by1 = (by0 + 1) & BM;
ry0 = t - PApplet.parseInt(t);
ry1 = ry0 - 1.0f;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
sx = sCurve(rx0);
sy = sCurve(ry0);
q = g2[b00];
u = at2(q, rx0, ry0);
q = g2[b10];
v = at2(q, rx1, ry0);
a = lerp(u, v, sx);
q = g2[b01] ;
u = at2(q, rx0, ry1);
q = g2[b11] ;
v = at2(q, rx1, ry1);
b = lerp(u, v, sx);
return lerp(a, b, sy);
}
public float noise3(float[] vec) {
int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
float[] q;
int i, j;
t = vec[0] + N;
bx0 = PApplet.parseInt(t) & BM;
bx1 = (bx0 + 1) & BM;
rx0 = t - PApplet.parseInt(t);
rx1 = rx0 - 1.0f;
t = vec[1] + N;
by0 = PApplet.parseInt(t) & BM;
by1 = (by0 + 1) & BM;
ry0 = t - PApplet.parseInt(t);
ry1 = ry0 - 1.0f;
t = vec[2] + N;
bz0 = PApplet.parseInt(t) & BM;
bz1 = (bz0 + 1) & BM;
rz0 = t - PApplet.parseInt(t);
rz1 = rz0 - 1.0f;
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
t = sCurve(rx0);
sy = sCurve(ry0);
sz = sCurve(rz0);
q = g3[b00 + bz0];
u = at3(q, rx0, ry0, rz0);
q = g3[b10 + bz0];
v = at3(q, rx1, ry0, rz0);
a = lerp(u, v, t);
q = g3[b01 + bz0];
u = at3(q, rx0, ry1, rz0);
q = g3[b11 + bz0];
v = at3(q, rx1, ry1, rz0);
b = lerp(u, v, t);
c = lerp(a, b, sy);
q = g3[b00 + bz1];
u = at3(q, rx0, ry0, rz1);
q = g3[b10 + bz1];
v = at3(q, rx1, ry0, rz1);
a = lerp(u, v, t);
q = g3[b01 + bz1];
u = at3(q, rx0, ry1, rz1);
q = g3[b11 + bz1];
v = at3(q, rx1, ry1, rz1);
b = lerp(u, v, t);
d = lerp(a, b, sy);
return lerp(c, d, sz);
}
// In what follows "nalpha" is the weight when the sum is formed.
// Typically it is 2, as this approaches 1 the function is noisier.
// "nbeta" is the harmonic scaling/spacing, typically 2. n is the
// number of harmonics added up in the final result. Higher number
// results in more detailed noise.
public float noise1D(float x, float nalpha, float nbeta, int n) {
float val, sum = 0;
float v[] = {x};
float nscale = 1;
for (int i = 0; i < n; i++) {
val = noise1(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
}
return sum;
}
public float noise2D(float x, float y, float nalpha, float nbeta, int n) {
float val,sum = 0;
float v[] = {x, y};
float nscale = 1;
for (int i = 0; i < n; i++) {
val = noise2(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
v[1] *= nbeta;
}
return sum;
}
public float noise3D(float x, float y, float z, float nalpha, float nbeta, int n) {
float val, sum = 0;
float v[] = {x, y, z};
float nscale = 1;
for (int i = 0 ; i < n; i++) {
val = noise3(v);
sum += val / nscale;
nscale *= nalpha;
v[0] *= nbeta;
v[1] *= nbeta;
v[2] *= nbeta;
}
return sum;
}
}
// Just draws an sphere of the given radius and resolutoin, using up to
// two images for texturing.
public void drawSphere(float r, int n, PImage tex0, PImage tex1) {
float startLat = -90;
float startLon = 0.0f;
float latInc = 180.0f / n;
float lonInc = 360.0f / n;
float u, v;
float phi1, phi2;
float theta1, theta2;
PVector p0 = new PVector();
PVector p1 = new PVector();
PVector p2 = new PVector();
beginShape(TRIANGLES);
if (tex1 != null) {
texture(tex0, tex1);
} else {
texture(tex0);
}
for (int col = 0; col < n; col++) {
phi1 = (startLon + col * lonInc) * DEG_TO_RAD;
phi2 = (startLon + (col + 1) * lonInc) * DEG_TO_RAD;
for (int row = 0; row < n; row++) {
theta1 = (startLat + row * latInc) * DEG_TO_RAD;
theta2 = (startLat + (row + 1) * latInc) * DEG_TO_RAD;
p0.x = cos(phi1) * cos(theta1);
p0.y = sin(theta1);
p0.z = sin(phi1) * cos(theta1);
p1.x = cos(phi1) * cos(theta2);
p1.y = sin(theta2);
p1.z = sin(phi1) * cos(theta2);
p2.x = cos(phi2) * cos(theta2);
p2.y = sin(theta2);
p2.z = sin(phi2) * cos(theta2);
normal(p0.x, p0.y, p0.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p0.x, r * p0.y, r * p0.z, u, v);
normal(p1.x, p1.y, p1.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p1.x, r * p1.y, r * p1.z, u, v);
normal(p2.x, p2.y, p2.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p2.x, r * p2.y, r * p2.z, u, v);
p1.x = cos(phi2) * cos(theta1);
p1.y = sin(theta1);
p1.z = sin(phi2) * cos(theta1);
normal(p0.x, p0.y, p0.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p0.x, r * p0.y, r * p0.z, u, v);
normal(p2.x, p2.y, p2.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p2.x, r * p2.y, r * p2.z, u, v);
normal(p1.x, p1.y, p1.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p1.x, r * p1.y, r * p1.z, u, v);
}
}
endShape();
}
static public void main(String args[]) {
PApplet.main(new String[] { "--bgcolor=#FFFFFF", "Planets" });
}
}

View File

@@ -0,0 +1,130 @@
// Planets, by Andres Colubri
// This example uses the beginRecord/endRecord method to save
// an entire shape geometry into a PShape3D object for faster
// drawing. It also demonstrates mulitexturing and displacement
// of texture coordinates
// Sun and mercury textures from http://planetpixelemporium.com
// Star field picture from http://www.galacticimages.com/
import processing.opengl2.*;
PImage starfield;
PShape sun;
PImage suntex;
PShape planet1;
PImage surftex1;
PImage cloudtex;
PShape planet2;
PImage surftex2;
void setup() {
size(480, 800, OPENGL2);
//orientation(PORTRAIT);
starfield = loadImage("starfield.jpg");
suntex = loadImage("sun.jpg");
surftex1 = loadImage("planet.jpg");
// We need trilinear sampling for this texture so it looks good
// even when rendered very small.
PTexture.Parameters params1 = PTexture.newParameters(ARGB, TRILINEAR);
surftex2 = loadImage("mercury.jpg", params1);
// The clouds texture will "move" having the values of its u
// texture coordinates displaced by adding a constant increment
// in each frame. This requires REPEAT wrapping mode so texture
// coordinates can be larger than 1.
PTexture.Parameters params2 = PTexture.newParameters();
params2.wrapU = REPEAT;
cloudtex = createImage(512, 256, ARGB, params2);
// Using 3D Perlin noise to generate a clouds texture that is seamless on
// its edges so it can be applied on a sphere.
println("Generating clouds texture. It takes some time, please wait...");
cloudtex.loadPixels();
Perlin perlin = new Perlin();
for (int j = 0; j < cloudtex.height; j++) {
for (int i = 0; i < cloudtex.width; i++) {
// The angle values corresponding to each u,v pair:
float u = float(i) / cloudtex.width;
float v = float(j) / cloudtex.height;
float phi = map(u, 0, 1, TWO_PI, 0);
float theta = map(v, 0, 1, -HALF_PI, HALF_PI);
// The x, y, z point corresponding to these angles:
float x = cos(phi) * cos(theta);
float y = sin(theta);
float z = sin(phi) * cos(theta);
float n = perlin.noise3D(x, y, z, 1.2, 2, 8);
cloudtex.pixels[j * cloudtex.width + i] = color(255, 255, 255, 255 * n * n);
}
}
cloudtex.updatePixels();
println("Done.");
textureMode(NORMAL);
noStroke();
fill(255);
sun = beginShapeRecord();
drawSphere(150, 40, suntex, null);
endShapeRecord();
planet1 = beginShapeRecord();
drawSphere(150, 40, surftex1, cloudtex);
endShapeRecord();
planet2 = beginShapeRecord();
drawSphere(50, 20, surftex2, null);
endShapeRecord();
}
void draw() {
// Even we draw a full screen image after this, it is recommended to use
// background to clear the screen anyways, otherwise A3D will think
// you want to keep each drawn frame in the framebuffer, which results in
// slower rendering.
background(0);
// Disabling writing to the depth mask so the
// background image doesn't occludes any 3D object.
hint(DISABLE_DEPTH_MASK);
image(starfield, 0, 0, width, height);
hint(ENABLE_DEPTH_MASK);
// Displacing the u texture coordinate of layer 1 in planet
// so it creates the effect of moving clouds.
PShape3D p = (PShape3D)planet1;
p.loadTexcoords(1);
for (int i = 0; i < p.getVertexCount(); i++) {
float u = p.texcoords[2 * i + 0];
u += 0.002;
p.texcoords[2 * i + 0] = u;
}
p.updateTexcoords();
pushMatrix();
translate(width/2, height/2, -100);
pushMatrix();
rotateY(PI * frameCount / 500);
shape(sun);
popMatrix();
pointLight(255, 255, 255, 0, 0, 0);
rotateY(PI * frameCount / 300);
translate(0, 0, 300);
shape(planet2);
popMatrix();
noLights();
pointLight(255, 255, 255, 0, 0, 100);
translate(0.75 * width, 0.6 * height, 350);
shape(planet1);
}

View File

@@ -0,0 +1,79 @@
// Just draws an sphere of the given radius and resolutoin, using up to
// two images for texturing.
void drawSphere(float r, int n, PImage tex0, PImage tex1) {
float startLat = -90;
float startLon = 0.0;
float latInc = 180.0 / n;
float lonInc = 360.0 / n;
float u, v;
float phi1, phi2;
float theta1, theta2;
PVector p0 = new PVector();
PVector p1 = new PVector();
PVector p2 = new PVector();
beginShape(TRIANGLES);
if (tex1 != null) {
texture(tex0, tex1);
} else {
texture(tex0);
}
for (int col = 0; col < n; col++) {
phi1 = (startLon + col * lonInc) * DEG_TO_RAD;
phi2 = (startLon + (col + 1) * lonInc) * DEG_TO_RAD;
for (int row = 0; row < n; row++) {
theta1 = (startLat + row * latInc) * DEG_TO_RAD;
theta2 = (startLat + (row + 1) * latInc) * DEG_TO_RAD;
p0.x = cos(phi1) * cos(theta1);
p0.y = sin(theta1);
p0.z = sin(phi1) * cos(theta1);
p1.x = cos(phi1) * cos(theta2);
p1.y = sin(theta2);
p1.z = sin(phi1) * cos(theta2);
p2.x = cos(phi2) * cos(theta2);
p2.y = sin(theta2);
p2.z = sin(phi2) * cos(theta2);
normal(p0.x, p0.y, p0.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p0.x, r * p0.y, r * p0.z, u, v);
normal(p1.x, p1.y, p1.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p1.x, r * p1.y, r * p1.z, u, v);
normal(p2.x, p2.y, p2.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p2.x, r * p2.y, r * p2.z, u, v);
p1.x = cos(phi2) * cos(theta1);
p1.y = sin(theta1);
p1.z = sin(phi2) * cos(theta1);
normal(p0.x, p0.y, p0.z);
u = map(phi1, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p0.x, r * p0.y, r * p0.z, u, v);
normal(p2.x, p2.y, p2.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta2, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p2.x, r * p2.y, r * p2.z, u, v);
normal(p1.x, p1.y, p1.z);
u = map(phi2, TWO_PI, 0, 0, 1);
v = map(theta1, -HALF_PI, HALF_PI, 0, 1);
vertex(r * p1.x, r * p1.y, r * p1.z, u, v);
}
}
endShape();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,191 @@
// Ariel and V3ga's arcball class with a couple tiny mods by Robert Hodgin
class Arcball{
float center_x, center_y, radius;
Vec3 v_down, v_drag;
Quat q_now, q_down, q_drag;
Vec3[] axisSet;
int axis;
float mxv, myv;
float x, y;
Arcball(float center_x, float center_y, float radius){
this.center_x = center_x;
this.center_y = center_y;
this.radius = radius;
v_down = new Vec3();
v_drag = new Vec3();
q_now = new Quat();
q_down = new Quat();
q_drag = new Quat();
axisSet = new Vec3[] {new Vec3(1.0f, 0.0f, 0.0f), new Vec3(0.0f, 1.0f, 0.0f), new Vec3(0.0f, 0.0f, 1.0f)};
axis = -1; // no constraints...
}
void mousePressed(){
v_down = mouse_to_sphere(mouseX, mouseY);
q_down.set(q_now);
q_drag.reset();
}
void mouseDragged(){
v_drag = mouse_to_sphere(mouseX, mouseY);
q_drag.set(Vec3.dot(v_down, v_drag), Vec3.cross(v_down, v_drag));
}
void run(){
q_now = Quat.mul(q_drag, q_down);
applyQuat2Matrix(q_now);
x += mxv;
y += myv;
mxv -= mxv * .01;
myv -= myv * .01;
}
Vec3 mouse_to_sphere(float x, float y){
Vec3 v = new Vec3();
v.x = (x - center_x) / radius;
v.y = (y - center_y) / radius;
float mag = v.x * v.x + v.y * v.y;
if (mag > 1.0f){
v.normalize();
} else {
v.z = sqrt(1.0f - mag);
}
return (axis == -1) ? v : constrain_vector(v, axisSet[axis]);
}
Vec3 constrain_vector(Vec3 vector, Vec3 axis){
Vec3 res = new Vec3();
res.sub(vector, Vec3.mul(axis, Vec3.dot(axis, vector)));
res.normalize();
return res;
}
void applyQuat2Matrix(Quat q){
// instead of transforming q into a matrix and applying it...
float[] aa = q.getValue();
rotate(aa[0], aa[1], aa[2], aa[3]);
}
}
static class Vec3{
float x, y, z;
Vec3(){
}
Vec3(float x, float y, float z){
this.x = x;
this.y = y;
this.z = z;
}
void normalize(){
float length = length();
x /= length;
y /= length;
z /= length;
}
float length(){
return (float) Math.sqrt(x * x + y * y + z * z);
}
static Vec3 cross(Vec3 v1, Vec3 v2){
Vec3 res = new Vec3();
res.x = v1.y * v2.z - v1.z * v2.y;
res.y = v1.z * v2.x - v1.x * v2.z;
res.z = v1.x * v2.y - v1.y * v2.x;
return res;
}
static float dot(Vec3 v1, Vec3 v2){
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
static Vec3 mul(Vec3 v, float d){
Vec3 res = new Vec3();
res.x = v.x * d;
res.y = v.y * d;
res.z = v.z * d;
return res;
}
void sub(Vec3 v1, Vec3 v2){
x = v1.x - v2.x;
y = v1.y - v2.y;
z = v1.z - v2.z;
}
}
static class Quat{
float w, x, y, z;
Quat(){
reset();
}
Quat(float w, float x, float y, float z){
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
void reset(){
w = 1.0f;
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
void set(float w, Vec3 v){
this.w = w;
x = v.x;
y = v.y;
z = v.z;
}
void set(Quat q){
w = q.w;
x = q.x;
y = q.y;
z = q.z;
}
static Quat mul(Quat q1, Quat q2){
Quat res = new Quat();
res.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
res.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
res.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z;
res.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;
return res;
}
float[] getValue(){
// transforming this quat into an angle and an axis vector...
float[] res = new float[4];
float sa = (float) Math.sqrt(1.0f - w * w);
if (sa < EPSILON){
sa = 1.0f;
}
res[0] = (float) Math.acos(w) * 2.0f;
res[1] = x / sa;
res[2] = y / sa;
res[3] = z / sa;
return res;
}
}

View File

@@ -0,0 +1,301 @@
final int MAX_BEZIER_ORDER = 10; // Maximum curve order.
final float[][] BSplineMatrix = {
{-1.0/6.0, 1.0/2.0, -1.0/2.0, 1.0/6.0},
{ 1.0/2.0, -1.0, 1.0/2.0, 0.0},
{-1.0/2.0, 0.0, 1.0/2.0, 0.0},
{ 1.0/6.0, 2.0/3.0, 1.0/6.0, 0.0}
};
// The element(i, n) of this array contains the binomial coefficient
// C(i, n) = n!/(i!(n-i)!)
final int[][] BinomialCoefTable = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{0, 1, 3, 6, 10, 15, 21, 28, 36, 45},
{0, 0, 1, 4, 10, 20, 35, 56, 84, 120},
{0, 0, 0, 1, 5, 15, 35, 70, 126, 210},
{0, 0, 0, 0, 1, 6, 21, 56, 126, 252},
{0, 0, 0, 0, 0, 1, 7, 28, 84, 210},
{0, 0, 0, 0, 0, 0, 1, 8, 36, 120},
{0, 0, 0, 0, 0, 0, 0, 1, 9, 45},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 10},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
};
// The element of this(i, j) of this table contains(i/10)^(3-j).
final float[][] TVectorTable = {
// t^3, t^2, t^1, t^0
{ 0, 0, 0, 1}, // t = 0.0
{0.001, 0.01, 0.1, 1}, // t = 0.1
{0.008, 0.04, 0.2, 1}, // t = 0.2
{0.027, 0.09, 0.3, 1}, // t = 0.3
{0.064, 0.16, 0.4, 1}, // t = 0.4
{0.125, 0.25, 0.5, 1}, // t = 0.5
{0.216, 0.36, 0.6, 1}, // t = 0.6
{0.343, 0.49, 0.7, 1}, // t = 0.7
{0.512, 0.64, 0.8, 1}, // u = 0.8
{0.729, 0.81, 0.9, 1}, // t = 0.9
{ 1, 1, 1, 1} // t = 1.0
};
// The element of this(i, j) of this table contains(3-j)*(i/10)^(2-j) if
// j < 3, 0 otherwise.
final float[][] DTVectorTable = {
// 3t^2, 2t^1, t^0
{ 0, 0, 1, 0}, // t = 0.0
{0.03, 0.2, 1, 0}, // t = 0.1
{0.12, 0.4, 1, 0}, // t = 0.2
{0.27, 0.6, 1, 0}, // t = 0.3
{0.48, 0.8, 1, 0}, // t = 0.4
{0.75, 1.0, 1, 0}, // t = 0.5
{1.08, 1.2, 1, 0}, // t = 0.6
{1.47, 1.4, 1, 0}, // t = 0.7
{1.92, 1.6, 1, 0}, // t = 0.8
{2.43, 1.8, 1, 0}, // t = 0.9
{ 3, 2, 1, 0} // t = 1.0
};
abstract class Curve3D {
abstract void feval(float t, PVector p);
abstract void deval(float t, PVector d);
abstract float fevalX(float t);
abstract float fevalY(float t);
abstract float fevalZ(float t);
abstract float devalX(float t);
abstract float devalY(float t);
abstract float devalZ(float t);
}
abstract class Spline extends Curve3D {
// The factorial of n.
int factorial(int n) {
return n <= 0 ? 1 : n * factorial(n - 1);
}
// Gives n!/(i!(n-i)!).
int binomialCoef(int i, int n) {
if ((i <= MAX_BEZIER_ORDER) &&(n <= MAX_BEZIER_ORDER)) return BinomialCoefTable[i][n - 1];
else return int(factorial(n) /(factorial(i) * factorial(n - i)));
}
// Evaluates the Berstein polinomial(i, n) at u.
float bersteinPol(int i, int n, float u) {
return binomialCoef(i, n) * pow(u, i) * pow(1 - u, n - i);
}
// The derivative of the Berstein polinomial.
float dbersteinPol(int i, int n, float u) {
float s1, s2;
if (i == 0) s1 = 0;
else s1 = i * pow(u, i-1) * pow(1 - u, n - i);
if (n == i) s2 = 0;
else s2 = -(n - i) * pow(u, i) * pow(1 - u, n - i - 1);
return binomialCoef(i, n) *(s1 + s2);
}
}
class BSpline extends Spline {
BSpline() {
initParameters(true);
}
BSpline(boolean t) {
initParameters(t);
}
// Sets lookup table use.
void initParameters(boolean t) {
bsplineCPoints = new float[4][3];
TVector = new float[4];
DTVector = new float[4];
M3 = new float[4][3];
pt = new float[3];
tg = new float[3];
lookup = t;
}
// Sets n-th control point.
void setCPoint(int n, PVector P) {
bsplineCPoints[n][0] = P.x;
bsplineCPoints[n][1] = P.y;
bsplineCPoints[n][2] = P.z;
updateMatrix3();
}
// Gets n-th control point.
void getCPoint(int n, PVector P) {
P.set(bsplineCPoints[n]);
}
// Replaces the current B-spline control points(0, 1, 2) with(1, 2, 3). This
// is used when a new spline is to be joined to the recently drawn.
void shiftBSplineCPoints() {
for (int i = 0; i < 3; i++) {
bsplineCPoints[0][i] = bsplineCPoints[1][i];
bsplineCPoints[1][i] = bsplineCPoints[2][i];
bsplineCPoints[2][i] = bsplineCPoints[3][i];
}
updateMatrix3();
}
void copyCPoints(int n_source, int n_dest) {
for (int i = 0; i < 3; i++) {
bsplineCPoints[n_dest][i] = bsplineCPoints[n_source][i];
}
}
// Updates the temporal matrix used in order 3 calculations.
void updateMatrix3() {
float s;
int i, j, k;
for(i = 0; i < 4; i++) {
for(j = 0; j < 3; j++) {
s = 0;
for(k = 0; k < 4; k++) s += BSplineMatrix[i][k] * bsplineCPoints[k][j];
M3[i][j] = s;
}
}
}
void feval(float t, PVector p) {
evalPoint(t);
p.set(pt);
}
void deval(float t, PVector d) {
evalTangent(t);
d.set(tg);
}
float fevalX(float t) {
evalPoint(t);
return pt[0];
}
float fevalY(float t) {
evalPoint(t);
return pt[1];
}
float fevalZ(float t) {
evalPoint(t);
return pt[2];
}
float devalX(float t) {
evalTangent(t);
return tg[0];
}
float devalY(float t) {
evalTangent(t);
return tg[1];
}
float devalZ(float t) {
evalTangent(t);
return tg[2];
}
// Point evaluation.
void evalPoint(float t) {
if (lookup) {
bsplinePointI(int(10 * t));
} else {
bsplinePoint(t);
}
}
// Tangent evaluation.
void evalTangent(float t) {
if (lookup) {
bsplineTangentI(int(10 * t));
} else {
bsplineTangent(t);
}
}
// Calculates the point on the cubic spline corresponding to the parameter value t in [0, 1].
void bsplinePoint(float t) {
// Q(u) = UVector * BSplineMatrix * BSplineCPoints
float s;
int i, j, k;
for(i = 0; i < 4; i++) {
TVector[i] = pow(t, 3 - i);
}
for(j = 0; j < 3; j++) {
s = 0;
for(k = 0; k < 4; k++) {
s += TVector[k] * M3[k][j];
}
pt[j] = s;
}
}
// Calculates the tangent vector of the spline at t.
void bsplineTangent(float t) {
// Q(u) = DTVector * BSplineMatrix * BSplineCPoints
float s;
int i, j, k;
for(i = 0; i < 4; i++) {
if (i < 3) {
DTVector[i] = (3 - i) * pow(t, 2 - i);
} else {
DTVector[i] = 0;
}
}
for(j = 0; j < 3; j++) {
s = 0;
for(k = 0; k < 4; k++) {
s += DTVector[k] * M3[k][j];
}
tg[j] = s;
}
}
// Gives the point on the cubic spline corresponding to t/10(using the lookup table).
void bsplinePointI(int t) {
// Q(u) = TVectorTable[u] * BSplineMatrix * BSplineCPoints
float s;
int j, k;
for(j = 0; j < 3; j++) {
s = 0;
for(k = 0; k < 4; k++) {
s += TVectorTable[t][k] * M3[k][j];
}
pt[j] = s;
}
}
// Calulates the tangent vector of the spline at t/10.
void bsplineTangentI(int t) {
// Q(u) = DTVectorTable[u] * BSplineMatrix * BSplineCPoints
float s;
int j, k;
for(j = 0; j < 3; j++) {
s = 0;
for(k = 0; k < 4; k++) {
s += DTVectorTable[t][k] * M3[k][j];
}
tg[j] = s;
}
}
// Control points.
float[][] bsplineCPoints;
// Parameters.
boolean lookup;
// Auxiliary arrays used in the calculations.
float[][] M3;
float[] TVector, DTVector;
// Point and tangent vectors.
float[] pt, tg;
}

View File

@@ -0,0 +1,460 @@
BSpline splineSide1;
BSpline splineCenter;
BSpline splineSide2;
PVector flipTestV;
int uspacing;
int HELIX = 0;
int STRAND = 1;
int COIL = 2;
int LHANDED = -1;
int RHANDED = 1;
void createRibbonModel(ArrayList residues, PShape3D model, ArrayList trj) {
ArrayList vertices;
ArrayList normals;
vertices = new ArrayList();
normals = new ArrayList();
if (ribbonDetail == 1) uspacing = 10;
else if (ribbonDetail == 2) uspacing = 5;
else if (ribbonDetail == 3) uspacing = 2;
else uspacing = 1;
flipTestV = new PVector();
splineSide1 = new BSpline(false);
splineCenter = new BSpline(false);
splineSide2 = new BSpline(false);
int[] ss = new int[residues.size()];
int[] handness = new int[residues.size()];
calculateSecStr(residues, ss, handness);
for (int i = 0; i < residues.size(); i++) {
constructControlPoints(residues, i, ss[i], handness[i]);
if (renderMode == 0) {
generateSpline(0, vertices);
generateSpline(1, vertices);
generateSpline(2, vertices);
}
else generateFlatRibbon(vertices, normals);
}
if (renderMode == 0) {
PShape3D.Parameters params = PShape3D.newParameters(LINES, STATIC);
model = (PShape3D)createShape(vertices.size(), params);
model.setVertices(vertices);
} else {
PShape3D.Parameters params = PShape3D.newParameters(TRIANGLES, STATIC);
model = (PShape3D)createShape(vertices.size(), params);
model.setVertices(vertices);
model.setNormals(normals);
}
model.setColor(ribbonColor);
trj.add(model);
println("Adding new model with " + vertices.size() + " vertices.");
}
float calculateGyrRadius(ArrayList atoms) {
PVector ati, atj;
float dx, dy, dz;
float r = 0;
for (int i = 0; i < atoms.size(); i++) {
ati = (PVector)atoms.get(i);
for (int j = i + 1; j < atoms.size(); j++) {
atj = (PVector)atoms.get(j);
dx = ati.x - atj.x;
dy = ati.y - atj.y;
dz = ati.z - atj.z;
r += dx * dx + dy * dy + dz * dz;
}
}
return sqrt(r) / (atoms.size() + 1);
}
// Does a cheap and dirty secondary structure assignment to the protein
// residues given in the array.
void calculateSecStr(ArrayList residues, int[] ss, int[] handness) {
PVector c0, n1, ca1, c1, n2;
HashMap res0, res1, res2;
int n = residues.size();
float[] phi = new float[n];
float[] psi = new float[n];
for (int i = 0; i < n; i++) {
if (i == 0 || i == n - 1) {
phi[i] = 90;
psi[i] = 90;
} else {
res0 = (HashMap)residues.get(i - 1);
res1 = (HashMap)residues.get(i);
res2 = (HashMap)residues.get(i + 1);
c0 = (PVector)res0.get("C");
n1 = (PVector)res1.get("N");
ca1 = (PVector)res1.get("CA");
c1 = (PVector)res1.get("C");
n2 = (PVector)res2.get("N");
phi[i] = calculateTorsionalAngle(c0, n1, ca1, c1);
psi[i] = calculateTorsionalAngle(n1, ca1, c1, n2);
}
}
int firstHelix = 0;
int nconsRHelix = 0;
int nconsLHelix = 0;
int firstStrand = 0;
int nconsStrand = 0;
for (int i = 0; i < n; i++) {
// Right-handed helix
if ((dist(phi[i], psi[i], -60, -45) < 30) && (i < n - 1)) {
if (nconsRHelix == 0) firstHelix = i;
nconsRHelix++;
}
else {
if (3 <= nconsRHelix) {
for (int k = firstHelix; k < i; k++) {
ss[k] = HELIX;
handness[k] = RHANDED;
}
}
nconsRHelix = 0;
}
// Left-handed helix
if ((dist(phi[i], psi[i], +60, +45) < 30) && (i < n - 1)) {
if (nconsLHelix == 0) firstHelix = i;
nconsLHelix++;
} else {
if (3 <= nconsLHelix) {
for (int k = firstHelix; k < i; k++) {
ss[k] = HELIX;
handness[k] = LHANDED;
}
}
nconsLHelix = 0;
}
// Strand
if ((dist(phi[i], psi[i], -110, +130) < 30) && (i < n - 1)) {
if (nconsStrand == 0) firstStrand = i;
nconsStrand++;
} else {
if (2 <= nconsStrand) {
for (int k = firstStrand; k < i; k++) {
ss[k] = STRAND;
handness[k] = RHANDED;
}
}
nconsStrand = 0;
}
ss[i] = COIL;
handness[i] = RHANDED;
}
}
// Calculates the torsional angle defined by four atoms with positions at0, at1, at2 and at3.
float calculateTorsionalAngle(PVector at0, PVector at1, PVector at2, PVector at3) {
PVector r01 = PVector.sub(at0, at1);
PVector r32 = PVector.sub(at3, at2);
PVector r12 = PVector.sub(at1, at2);
PVector p = r12.cross(r01);
PVector q = r12.cross(r32);
PVector r = r12.cross(q);
float u = q.dot(q);
float v = r.dot(r);
float a;
if (u <= 0.0 || v <= 0.0) {
a = 360.0;
} else {
float u1 = p.dot(q); // u1 = p * q
float v1 = p.dot(r); // v1 = p * r
u = u1 / sqrt(u);
v = v1 / sqrt(v);
if (abs(u) > 0.01 || abs(v) > 0.01) a = degrees(atan2(v, u));
else a = 360.0;
}
return a;
}
void generateSpline(int n, ArrayList vertices) {
int ui;
float u;
PVector v0, v1;
v0 = new PVector();
v1 = new PVector();
if (n == 0) splineSide1.feval(0, v1);
else if (n == 1) splineCenter.feval(0, v1);
else splineSide2.feval(0, v1);
for (ui = 1; ui <= 10; ui ++) {
if (ui % uspacing == 0) {
u = 0.1 * ui;
v0.set(v1);
if (n == 0) splineSide1.feval(u, v1);
else if (n == 1) splineCenter.feval(u, v1);
else splineSide2.feval(u, v1);
vertices.add(new PVector(v0.x, v0.y, v0.z));
vertices.add(new PVector(v1.x, v1.y, v1.z));
}
}
}
void generateFlatRibbon(ArrayList vertices, ArrayList normals) {
PVector CentPoint0, CentPoint1;
PVector Sid1Point0, Sid1Point1;
PVector Sid2Point0, Sid2Point1;
PVector Transversal, Tangent;
PVector Normal0, Normal1;
int ui;
float u;
CentPoint0 = new PVector();
CentPoint1 = new PVector();
Sid1Point0 = new PVector();
Sid1Point1 = new PVector();
Sid2Point0 = new PVector();
Sid2Point1 = new PVector();
Transversal = new PVector();
Tangent = new PVector();
Normal0 = new PVector();
Normal1 = new PVector();
// The initial geometry is generated.
splineSide1.feval(0, Sid1Point1);
splineCenter.feval(0, CentPoint1);
splineSide2.feval(0, Sid2Point1);
// The tangents at the three previous points are the same.
splineSide2.deval(0, Tangent);
// Vector transversal to the ribbon.
Transversal = PVector.sub(Sid1Point1, Sid2Point1);
// The normal is calculated.
Normal1 = Transversal.cross(Tangent);
Normal1.normalize();
for (ui = 1; ui <= 10; ui ++) {
if (ui % uspacing == 0) {
u = 0.1 * ui;
// The geometry of the previous iteration is saved.
Sid1Point0.set(Sid1Point1);
CentPoint0.set(CentPoint1);
Sid2Point0.set(Sid2Point1);
Normal0.set(Normal1);
// The new geometry is generated.
splineSide1.feval(u, Sid1Point1);
splineCenter.feval(u, CentPoint1);
splineSide2.feval(u, Sid2Point1);
// The tangents at the three previous points are the same.
splineSide2.deval(u, Tangent);
// Vector transversal to the ribbon.
Transversal = PVector.sub(Sid1Point1, Sid2Point1);
// The normal is calculated.
Normal1 = Transversal.cross(Tangent);
Normal1.normalize();
// The (Sid1Point0, Sid1Point1, CentPoint1) triangle is added.
vertices.add(new PVector(Sid1Point0.x, Sid1Point0.y, Sid1Point0.z));
normals.add(new PVector(Normal0.x, Normal0.y, Normal0.z));
vertices.add(new PVector(Sid1Point1.x, Sid1Point1.y, Sid1Point1.z));
normals.add(new PVector(Normal1.x, Normal1.y, Normal1.z));
vertices.add(new PVector(CentPoint1.x, CentPoint1.y, CentPoint1.z));
normals.add(new PVector(Normal1.x, Normal1.y, Normal1.z));
// The (Sid1Point0, CentPoint1, CentPoint0) triangle is added.
vertices.add(new PVector(Sid1Point0.x, Sid1Point0.y, Sid1Point0.z));
normals.add(new PVector(Normal0.x, Normal0.y, Normal0.z));
vertices.add(new PVector(CentPoint1.x, CentPoint1.y, CentPoint1.z));
normals.add(new PVector(Normal1.x, Normal1.y, Normal1.z));
vertices.add(new PVector(CentPoint0.x, CentPoint0.y, CentPoint0.z));
normals.add(new PVector(Normal0.x, Normal0.y, Normal0.z));
// (Sid2Point0, Sid2Point1, CentPoint1) triangle is added.
vertices.add(new PVector(Sid2Point0.x, Sid2Point0.y, Sid2Point0.z));
normals.add(new PVector(Normal0.x, Normal0.y, Normal0.z));
vertices.add(new PVector(Sid2Point1.x, Sid2Point1.y, Sid2Point1.z));
normals.add(new PVector(Normal1.x, Normal1.y, Normal1.z));
vertices.add(new PVector(CentPoint1.x, CentPoint1.y, CentPoint1.z));
normals.add(new PVector(Normal1.x, Normal1.y, Normal1.z));
// (Sid2Point0, CentPoint1, CentPoint0) triangle is added.
vertices.add(new PVector(Sid2Point0.x, Sid2Point0.y, Sid2Point0.z));
normals.add(new PVector(Normal0.x, Normal0.y, Normal0.z));
vertices.add(new PVector(CentPoint1.x, CentPoint1.y, CentPoint1.z));
normals.add(new PVector(Normal1.x, Normal1.y, Normal1.z));
vertices.add(new PVector(CentPoint0.x, CentPoint0.y, CentPoint0.z));
normals.add(new PVector(Normal0.x, Normal0.y, Normal0.z));
}
}
}
/******************************************************************************
* The code in the following three functions is based in the method introduced
* in this paper:
* "Algorithm for ribbon models of proteins."
* Authors: Mike Carson and Charles E. Bugg
* Published in: J.Mol.Graphics 4, pp. 121-122 (1986)
******************************************************************************/
// Shifts the control points one place to the left.
void shiftControlPoints() {
splineSide1.shiftBSplineCPoints();
splineCenter.shiftBSplineCPoints();
splineSide2.shiftBSplineCPoints();
}
// Adds a new control point to the arrays CPCenter, CPRight and CPLeft
void addControlPoints(PVector ca0, PVector ox0, PVector ca1, int ss, int handness) {
PVector A, B, C, D, p0, cpt0, cpt1, cpt2;
A = PVector.sub(ca1, ca0);
B = PVector.sub(ox0, ca0);
// Vector normal to the peptide plane (pointing outside in the case of the
// alpha helix).
C = A.cross(B);
// Vector contained in the peptide plane (perpendicular to its direction).
D = C.cross(A);
// Normalizing vectors.
C.normalize();
D.normalize();
// Flipping test (to avoid self crossing in the strands).
if ((ss != HELIX) && (90.0 < degrees(PVector.angleBetween(flipTestV, D)))) {
// Flip detected. The plane vector is inverted.
D.mult(-1.0);
}
// The central control point is constructed.
cpt0 = linearComb(0.5, ca0, 0.5, ca1);
splineCenter.setCPoint(3, cpt0);
if (ss == HELIX) {
// When residue i is contained in a helix, the control point is moved away
// from the helix axis, along the C direction.
p0 = new PVector();
splineCenter.getCPoint(3, p0);
cpt0 = linearComb(1.0, p0, handness * helixDiam, C);
splineCenter.setCPoint(3, cpt0);
}
// The control points for the side ribbons are constructed.
cpt1 = linearComb(1.0, cpt0, +ribbonWidth[ss], D);
splineSide1.setCPoint(3, cpt1);
cpt2 = linearComb(1.0, cpt0, -ribbonWidth[ss], D);
splineSide2.setCPoint(3, cpt2);
// Saving the plane vector (for the flipping test in the next call).
flipTestV.set(D);
}
void constructControlPoints(ArrayList residues, int res, int ss, int handness) {
PVector ca0, ox0, ca1;
PVector p0, p1, p2, p3;
p1 = new PVector();
p2 = new PVector();
p3 = new PVector();
HashMap res0, res1;
res0 = res1 = null;
if (res == 0) {
// The control points 2 and 3 are created.
flipTestV.set(0, 0, 0);
res0 = (HashMap)residues.get(res);
res1 = (HashMap)residues.get(res + 1);
ca0 = (PVector)res0.get("CA");
ox0 = (PVector)res0.get("O");
ca1 = (PVector)res1.get("CA");
addControlPoints(ca0, ox0, ca1, ss, handness);
splineSide1.copyCPoints(3, 2);
splineCenter.copyCPoints(3, 2);
splineSide2.copyCPoints(3, 2);
res0 = (HashMap)residues.get(res + 1);
res1 = (HashMap)residues.get(res + 2);
ca0 = (PVector)res0.get("CA");
ox0 = (PVector)res0.get("O");
ca1 = (PVector)res1.get("CA");
addControlPoints(ca0, ox0, ca1, ss, handness);
// We still need the two first control points.
// Moving backwards along the cp_center[2] - cp_center[3] direction.
splineCenter.getCPoint(2, p2);
splineCenter.getCPoint(3, p3);
p1 = linearComb(2.0, p2, -1, p3);
splineCenter.setCPoint(1, p1);
splineSide1.setCPoint(1, linearComb(1.0, p1, +ribbonWidth[ss], flipTestV));
splineSide2.setCPoint(1, linearComb(1.0, p1, -ribbonWidth[ss], flipTestV));
p0 = linearComb(2.0, p1, -1, p2);
splineCenter.setCPoint(0, p0);
splineSide1.setCPoint(0, linearComb(1.0, p0, +ribbonWidth[ss], flipTestV));
splineSide2.setCPoint(0, linearComb(1.0, p0, -ribbonWidth[ss], flipTestV));
} else {
shiftControlPoints();
if ((residues.size() - 1 == res) || (residues.size() - 2 == res)) {
// Moving forward along the cp_center[1] - cp_center[2] direction.
splineCenter.getCPoint(1, p1);
splineCenter.getCPoint(2, p2);
p3 = linearComb(2.0, p2, -1, p1);
splineCenter.setCPoint(3, p3);
splineSide1.setCPoint(3, linearComb(1.0, p3, +ribbonWidth[ss], flipTestV));
splineSide2.setCPoint(3, linearComb(1.0, p3, -ribbonWidth[ss], flipTestV));
} else {
res0 = (HashMap)residues.get(res + 1);
res1 = (HashMap)residues.get(res + 2);
ca0 = (PVector)res0.get("CA");
ox0 = (PVector)res0.get("O");
ca1 = (PVector)res1.get("CA");
addControlPoints(ca0, ox0, ca1, ss, handness);
}
}
splineSide1.updateMatrix3();
splineCenter.updateMatrix3();
splineSide2.updateMatrix3();
}
PVector linearComb(float scalar0, PVector vector0, float scalar1, PVector vector1) {
return PVector.add(PVector.mult(vector0, scalar0), PVector.mult(vector1, scalar1));
}

View File

@@ -0,0 +1,121 @@
void readPDB(String filename) {
String strLines[];
float xmin, xmax, ymin, ymax, zmin, zmax;
String xstr, ystr, zstr;
float x, y, z;
int res, res0;
int nmdl;
String atstr, resstr;
PShape3D model;
ArrayList atoms;
ArrayList residues;
HashMap residue;
PVector v;
String s;
strLines = loadStrings(filename);
models = new ArrayList();
xmin = ymin = zmin = 10000;
xmax = ymax = zmax = -10000;
atoms = null;
residues = null;
residue = null;
model = null;
res0 = -1;
nmdl = -1;
for (int i = 0; i < strLines.length; i++) {
s = strLines[i];
if (s.startsWith("MODEL") || (s.startsWith("ATOM") && res0 == -1)) {
nmdl++;
res0 = -1;
atoms = new ArrayList();
residues = new ArrayList();
}
if (s.startsWith("ATOM")) {
atstr = s.substring(12, 15);
atstr = atstr.trim();
resstr = s.substring(22, 26);
resstr = resstr.trim();
res = parseInt(resstr);
xstr = s.substring(30, 37);
xstr = xstr.trim();
ystr = s.substring(38, 45);
ystr = ystr.trim();
zstr = s.substring(46, 53);
zstr = zstr.trim();
x = scaleFactor * parseFloat(xstr);
y = scaleFactor * parseFloat(ystr);
z = scaleFactor * parseFloat(zstr);
v = new PVector(x, y, z);
xmin = min(xmin, x);
xmax = max(xmax, x);
ymin = min(ymin, y);
ymax = max(ymax, y);
zmin = min(zmin, z);
zmax = max(zmax, z);
atoms.add(v);
if (res0 != res) {
if (residue != null) residues.add(residue);
residue = new HashMap();
}
residue.put(atstr, v);
res0 = res;
}
if (s.startsWith("ENDMDL") || s.startsWith("TER")) {
if (residue != null) residues.add(residue);
createRibbonModel(residues, model, models);
float rgyr = calculateGyrRadius(atoms);
res0 = -1;
residue = null;
atoms = null;
residues = null;
}
}
if (residue != null) {
if (residue != null) residues.add(residue);
createRibbonModel(residues, model, models);
float rgyr = calculateGyrRadius(atoms);
atoms = null;
residues = null;
}
// Centering models at (0, 0, 0).
float dx = -0.5f * (xmin + xmax);
float dy = -0.5f * (ymin + ymax);
float dz = -0.5f * (zmin + zmax);
for (int n = 0; n < models.size(); n++) {
model = (PShape3D)models.get(n);
model.loadVertices();
for (int i = 0; i < model.getVertexCount(); i++) {
model.vertices[3 * i + 0] += dx;
model.vertices[3 * i + 1] += dy;
model.vertices[3 * i + 2] += dz;
}
model.updateVertices();
}
println("Loaded PDB file with " + models.size() + " models.");
}

View File

@@ -0,0 +1,57 @@
// Ribbons, by Andres Colubri
// ArcBall class by Ariel, V3ga and Robert Hodgin (flight404)
// This sketch loads 3D atomic coordinates of a protein molecule
// from a file in PDB format (http://www.pdb.org/) and displays
// the structure using a ribbon representation.
import processing.opengl2.*;
String pdbFile = "4HHB.pdb"; // PDB file to read
//String pdbFile = "2POR.pdb";
//String pdbFile = "1CBS.pdb";
// Some parameters to control the visual appearance:
float scaleFactor = 5; // Size factor
int renderMode = 1; // 0 = lines, 1 = flat ribbons
int ribbonDetail = 4; // Ribbon detail: from 1 (lowest) to 4 (highest)
float helixDiam = 10; // Helix diameter.
int[] ribbonWidth = {10, 7, 2}; // Ribbon widths for helix, strand and coil
color ribbonColor = color(20, 30, 200, 255); // Ribbon color
// All the molecular models read from the PDB file (it could contain more than one)
ArrayList models;
Arcball arcball;
void setup() {
size(800, 600, OPENGL2);
arcball = new Arcball(width/2, height/2, 600);
readPDB(pdbFile);
}
void draw() {
background(0);
if (renderMode == 1) {
lights();
}
translate(width/2, height/2, 200);
arcball.run();
for (int i = 0; i < models.size(); i++) {
PShape3D model = (PShape3D)models.get(i);
shape(model);
}
}
void mousePressed(){
arcball.mousePressed();
}
void mouseDragged(){
arcball.mouseDragged();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,162 @@
// Rocket, by Andres Colubri.
// This example shows the OBJ load functionality and the use of
// the PShape3D class to create a particle system.
// Rocket model from http://keleb.free.fr/codecorner/models-en.htm
import processing.opengl2.*;
PShape3D rocket;
PShape3D particles;
int[] lifetimes;
int numParticlesTotal = 1200;
int numParticlesPerFrame = 10;
int particleLifetime;
float time;
float timeInc = 0.03;
PVector axis, pos, vel;
void setup() {
size(800, 600, OPENGL2);
//orientation(PORTRAIT);
rocket = (PShape3D)loadShape("rocket.obj");
// Adjusting the size, orientation and position of the object.
// The bulk scale, rotate and translate operations done on the
// shape are permanent.
rocket.scaleVertices(0.2);
rocket.rotateVerticesX(-PI);
rocket.translateVertices(-5, 25, 0);
// The particle system is stored in a PShape3D object set to
// POINT_SPRITES mode
PShape3D.Parameters params = PShape3D.newParameters(POINT_SPRITES, STREAM);
particles = (PShape3D)createShape(numParticlesTotal, params);
particleLifetime = numParticlesTotal / numParticlesPerFrame;
lifetimes = new int[numParticlesTotal];
// Loading and setting the sprite image.
PImage sprite = loadImage("smoke.png");
particles.setTexture(sprite);
// The default maximum sprite size is determined by the graphics
// hardware (it usually ranges between 32 and 128 pixels).
println("Maximum sprite size: " + particles.getMaxSpriteSize());
// The maximum size can be set with setMaxSpriteSize(), but will be
// capped by the maximum size supported by the hardware.
particles.setMaxSpriteSize(32);
// The actual sprite size depends on the distance d from the sprite
// to the camera as follows:
// s = smax / (1 + c * d * d) (quadratic dependence on d)
// or
// s = smax / (1 + c * d) (linear dependence on d)
// where smax is the maximum sprite size and c an adjustable constant.
// In the next call, the constant is adjusted so that the actual sprite
// size is 10 when the distance is 400. A quadratic dependence on d is used.
particles.setSpriteSize(10, 400, QUADRATIC);
// PShape3D objects automatically update their bounding boxes, but we don't
// want this for the particle system object.
particles.autoBounds(false);
particles.setColor(color(0)); // Making sure that all particles start as black.
// Initialzing particles with negative lifetimes so they are added
// progresively into the scene during the first frames of the program
int t = -1;
for (int i = 0; i < numParticlesTotal; i++) {
if (i % numParticlesPerFrame == 0) {
t++;
}
lifetimes[i] = -t;
}
pos = new PVector(0, 0, 0);
vel = new PVector(0, 0, 0);
// The rocket object is originally aligned to the Y axis. We
// use this vector to calculate the rotation needed to make
// the rocket aligned to the velocity vector
axis = new PVector(0, 1, 0);
}
void draw() {
background(0);
updatePosition();
updateParticles();
ambient(250, 250, 250);
pointLight(255, 255, 255, 500, height/2, 400);
pushMatrix();
translate(pos.x, pos.y, pos.z);
PVector rotAxis = axis.cross(vel);
float angle = PVector.angleBetween(axis, vel);
rotate(angle, rotAxis.x, rotAxis.y, rotAxis.z);
rotateY(2 * time);
shape(rocket);
popMatrix();
// The particles are not lit.
noLights();
// Writing to the depth mask is disabled to avoid rendering artifacts due
// to the fact that the particles are transparent but not depth sorted
hint(DISABLE_DEPTH_MASK);
shape(particles);
hint(ENABLE_DEPTH_MASK);
time += timeInc;
}
void updatePosition() {
pos.x = width/2 + 150 * cos(time);
pos.y = 50 + height/2 + 200 * cos(2 * time);
pos.z = 150 + 200 * sin(time);
vel.x = 150 * sin(time);
vel.y = 400 * sin(2 * time);
vel.z = -150 * cos(time);
}
void updateParticles() {
// Respawn dead particles
particles.loadVertices();
for (int i = 0; i < numParticlesTotal; i++) {
if (lifetimes[i] == 0) {
particles.vertices[3 * i + 0] = random(pos.x - 8, pos.x + 8);
particles.vertices[3 * i + 1] = random(pos.y - 8, pos.y + 8);
particles.vertices[3 * i + 2] = random(pos.z - 8, pos.z + 8);
}
}
particles.updateVertices();
// Update colors and lifetimes of particles
particles.loadColors();
for (int i = 0; i < numParticlesTotal; i++) {
if (0 <= lifetimes[i]) {
// Interpolating between alpha 1 to 0:
float a = 1.0 - float(lifetimes[i]) / particleLifetime;
// Interpolating from orange to white during the first
// quarter of the particle's life (the color shoud be specified
// in normalized RGBA components)
float f = min(float(lifetimes[i]) / (0.25 * particleLifetime), 1);
particles.colors[4 * i + 0] = (1 - f) * 0.98 + f;
particles.colors[4 * i + 1] = (1 - f) * 0.75 + f;
particles.colors[4 * i + 2] = (1 - f) * 0.26 + f;
particles.colors[4 * i + 3] = a;
}
lifetimes[i]++;
if (lifetimes[i] == particleLifetime) {
lifetimes[i] = 0;
}
}
particles.updateColors();
}

View File

@@ -0,0 +1,8 @@
newmtl Default
illum 2
Ka 0.698039 0.698039 0.698039
Kd 0.698039 0.698039 0.698039
Ks 0.710000 0.710000 0.710000
Ns 76.109253
map_Kd rocket.png

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
// Code to draw a trefoil knot surface, with normals and texture
// coordinates.
// Adapted from the parametric equations example by Philip Rideout:
// http://iphone-3d-programming.labs.oreilly.com/ch03.html
// Evaluates the surface point corresponding to normalized
// parameters (u, v)
PVector evalPoint(float u, float v) {
float a = 0.5;
float b = 0.3;
float c = 0.5;
float d = 0.1;
float s = TWO_PI * u;
float t = (TWO_PI * (1 - v)) * 2;
float r = a + b * cos(1.5 * t);
float x = r * cos(t);
float y = r * sin(t);
float z = c * sin(1.5 * t);
PVector dv = new PVector();
dv.x = -1.5f * b * sin(1.5f * t) * cos(t) -
(a + b * cos(1.5f * t)) * sin(t);
dv.y = -1.5f * b * sin(1.5f * t) * sin(t) +
(a + b * cos(1.5f * t)) * cos(t);
dv.z = 1.5f * c * cos(1.5f * t);
PVector q = dv;
q.normalize();
PVector qvn = new PVector(q.y, -q.x, 0);
qvn.normalize();
PVector ww = q.cross(qvn);
PVector pt = new PVector();
pt.x = x + d * (qvn.x * cos(s) + ww.x * sin(s));
pt.y = y + d * (qvn.y * cos(s) + ww.y * sin(s));
pt.z = z + d * ww.z * sin(s);
return pt;
}
// Evaluates the surface normal corresponding to normalized
// parameters (u, v)
PVector evalNormal(float u, float v) {
// Compute the tangents and their cross product.
PVector p = evalPoint(u, v);
PVector tangU = evalPoint(u + 0.01, v);
PVector tangV = evalPoint(u, v + 0.01);
tangU.sub(p);
tangV.sub(p);
PVector normUV = tangV.cross(tangU);
normUV.normalize();
return normUV;
}
// This function draws a trefoil knot surface as a triangle mesh derived
// from its parametric equation.
void drawSurface(float s, int ny, int nx, PImage tex) {
PVector p0, p1, p2;
PVector n0, n1, n2;
float u0, u1, v0, v1;
beginShape(TRIANGLES);
texture(tex);
for (int j = 0; j < nx; j++) {
u0 = float(j) / nx;
u1 = float(j + 1) / nx;
for (int i = 0; i < ny; i++) {
v0 = float(i) / ny;
v1 = float(i + 1) / ny;
p0 = evalPoint(u0, v0);
n0 = evalNormal(u0, v0);
p1 = evalPoint(u0, v1);
n1 = evalNormal(u0, v1);
p2 = evalPoint(u1, v1);
n2 = evalNormal(u1, v1);
// Triangle p0-p1-p2
normal(n0.x, n0.y, n0.z);
vertex(s * p0.x, s * p0.y, s * p0.z, u0, v0);
normal(n1.x, n1.y, n1.z);
vertex(s * p1.x, s * p1.y, s * p1.z, u0, v1);
normal(n2.x, n2.y, n2.z);
vertex(s * p2.x, s * p2.y, s * p2.z, u1, v1);
p1 = evalPoint(u1, v0);
n1 = evalNormal(u1, v0);
// Triangle p0-p2-p1
normal(n0.x, n0.y, n0.z);
vertex(s * p0.x, s * p0.y, s * p0.z, u0, v0);
normal(n2.x, n2.y, n2.z);
vertex(s * p2.x, s * p2.y, s * p2.z, u1, v1);
normal(n1.x, n1.y, n1.z);
vertex(s * p1.x, s * p1.y, s * p1.z, u1, v0);
}
}
endShape();
}

View File

@@ -0,0 +1,109 @@
// Trefoil, by Andres Colubri
// A parametric surface is textured procedurally
// using a particle system rendered to an offscreen
// surface.
// Click the screen to cycle between the textured surface,
// the same surface but without the texture, and the
// offscreen texture with the particle system.
import processing.opengl2.*;
PGraphics pg;
PShape trefoil;
PShape3D particles;
int mode = 0;
void setup() {
size(280, 400, OPENGL2);
PFont font = createFont(PFont.list()[0], 18);
textFont(font, 18);
textureMode(NORMAL);
noStroke();
// Creating offscreen surface for 3D rendering.
pg = createGraphics(32, 512, OPENGL2);
// Initializing particle system
PShape3D.Parameters params = PShape3D.newParameters(POINT_SPRITES, STREAM);
particles = (PShape3D)createShape(1000, params);
particles.loadVertices();
for (int i = 0; i < particles.getVertexCount(); i++) {
particles.set(i, random(0, 10), random(0, 10), 0);
}
particles.updateVertices();
particles.loadColors();
for (int i = 0; i < particles.getVertexCount(); i++) {
particles.set(i, random(0, 1), random(0, 1), random(0, 1));
}
particles.updateColors();
PImage sprite = loadImage("particle.png");
particles.setTexture(sprite);
particles.setSpriteSize(8);
// Saving trefoil surface into a PShape3D object
trefoil = beginRecord();
drawSurface(250, 60, 15, pg);
endRecord();
}
void draw() {
background(0);
// Updating particle system
particles.loadVertices();
float[] v = particles.vertices;
for (int i = 0; i < particles.getVertexCount(); i++) {
// Just random wandering
v[3 * i + 0] += random(-1, 1);
v[3 * i + 1] += random(-1, 1);
// Particles wrap around the edges
if (v[3 * i + 0] < 0) v[3 * i + 0] += pg.width;
if (v[3 * i + 1] < 0) v[3 * i + 1] += pg.height;
if (pg.width < v[3 * i + 0]) v[3 * i + 0] -= pg.width;
if (pg.height < v[3 * i + 1]) v[3 * i + 1] -= pg.height;
}
particles.updateVertices();
// Drawing particles into offscreen surface, used to
// texture the trefoil shape.
pg.beginDraw();
pg.hint(DISABLE_DEPTH_MASK);
pg.shape(particles);
pg.hint(ENABLE_DEPTH_MASK);
pg.endDraw();
if (mode < 2) {
ambient(250, 250, 250);
pointLight(255, 255, 255, 0, 0, 200);
pushMatrix();
translate(width/2, height/2, -200);
rotateX(frameCount * PI / 500);
rotateY(frameCount * PI / 500);
if (mode == 0) {
trefoil.enableStyle();
hint(DISABLE_DEPTH_MASK);
blend(ADD);
} else {
trefoil.disableStyle();
blend(BLEND);
}
shape(trefoil);
hint(ENABLE_DEPTH_MASK);
popMatrix();
} else {
image(pg, 0, 0, width, height);
}
fill(255);
text("fps: " + frameRate, 10, height - 20);
}
void mousePressed() {
mode = (mode + 1) % 3;
}