package scenes;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Random;
import org.apache.log4j.Logger;
import models.Shape3D;
import codeanticode.glgraphics.*;
import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PGraphics;
import processing.core.PMatrix3D;
import processing.core.PVector;
import remixlab.proscene.Frame;
import remixlab.proscene.Quaternion;
import utils.ConsoleIO;
import utils.Util;
import textures.FacesLoader;
import traer.physics.Particle;
import traer.physics.ParticleSystem;
import traer.physics.Spring;
public class ElasticGrid extends Scene{
static Logger logger = Logger.getLogger(ElasticGrid.class);
////////////////////////////////////////////
// EL SISTEMA DE PARTICULAS
////////////////////////////////////////////
private ParticleSystem ps;
private Particle[][] particles;
private Spring[][] springs;
////////////////////////////////////////////
// GLModel + vertices used for construction
// texture
////////////////////////////////////////////
private GLModel grid;
private GLTexture texture;
private ArrayList vertices;
private ArrayList texCoords;
private ArrayList normals;
////////////////////////////////////////////
// variables que uso en la
// actualizacion de los vertices
////////////////////////////////////////////
private float x = 0;
private float y = 0;
private float z = 0;
private float u = 0;
private float v = 0;
private int index = 0;
private PVector currentVertex = new PVector(x, y, z);
private PVector destVertex = new PVector(x, y, z);
////////////////////////////////////////////
// vectores usados para calcular las normales de los
// triangulos
////////////////////////////////////////////
private PVector a = new PVector(x, y, z);
private PVector b = new PVector(x, y, z);
private PVector c = new PVector(x, y, z);
private PVector[] triangle = new PVector[3];
private PVector normal = new PVector(0, 0, 0);
////////////////////////////////////////////
// CONFIGURACION de la grilla
////////////////////////////////////////////
private int grid_Columns = 100;
private int grid_Rows = 100;
private int grid_HNodes = grid_Columns + 1;
private int grid_VNodes = grid_Rows + 1;
private float grid_width = 12;
private float grid_height = 9;
private float particle_drag = .5f; // 1f
private float particle_mass = 1.09f;
private float particle_tick = 0.09f;
public float spring_Strengh = 5;// 3f;
public float spring_Damp = 1; //0.5f;
private float spring_HLength = grid_width / grid_HNodes;
private float spring_VLength = grid_height / grid_VNodes;
private boolean fixCorners = false;
////////////////////////////////////////////
// varios
////////////////////////////////////////////
private Random random;
////////////////////////////////////////////
// CONSTRUCTORES
////////////////////////////////////////////
/**
* La implementacion de Scene siempre tiene que lleva como parametro un PApplet
* Scene necesita crear un GLGraphicsOffScreen ademas de los modelos
* y texturas
*
* @param parent la aplicacion sobre la cual estoy instanciando esta escena
* @param OUTPUT_W a que tama�o lo quiero renderear
* @param OUTPUT_H a que tama�o lo quiero renderear
*/
public ElasticGrid(PApplet parent, int OUTPUT_W, int OUTPUT_H) {
super(parent, OUTPUT_W, OUTPUT_H);
random = new Random();
ps = new ParticleSystem( 0, 0, 0, particle_drag);
// cada particula se conecta con el de abajo y el de la derecha
particles = new Particle[grid_HNodes][grid_VNodes];
springs = new Spring[(grid_HNodes) * (grid_VNodes)][2];
// creamos los puntos de la grilla
createGrid();
// luego creamos el modelo
createModel();
}
public void setTexture(GLTexture texture){
this.texture = texture;
logger.info("TEXTURE: " + texture.toString());
grid.initTexures(1);
grid.setTexture(0, texture);
logger.info("TEXCORD SIZE: " + texCoords.size());
grid.updateTexCoords(0, texCoords);
}
public void renderScene(){
model(grid);
}
public void update(){
int index = 0;
ps.tick(particle_tick);
///////////////////////////////////////
for(int ix = 0; ix < grid_Rows ; ix++){
for (int jy = 0; jy < grid_Columns ; jy++) {
// PRIMER TRIANGULO
// PUNTO 0
x = particles[ix][jy].position().x();
y = particles[ix][jy].position().y();
z = particles[ix][jy].position().z();
a.set(x, y, z);
// PUNTO 1
x = particles[ix][jy+1].position().x();
y = particles[ix][jy+1].position().y();
z = particles[ix][jy+1].position().z();
b.set(x, y, z);
// PUNTO 2
x = particles[ix+1][jy].position().x();
y = particles[ix+1][jy].position().y();
z = particles[ix+1][jy].position().z();
c.set(x, y, z);
//////////////////////////////////////////////////////////////
// CALCULAR LA NORMAL PARA EL PRIMER TRIANGULO
triangle[0] = a;
triangle[1] = b;
triangle[2] = c;
normal = getNormal(triangle);
// normal.normalize();
for(int i = 0 ; i < triangle.length; i++){
((PVector) vertices.get(index)).set(triangle[i]);
((PVector) normals.get(index)).set(normal);
index++;
}
//////////////////////////////////////////////////////////////
// SEGUNDO TRIANGULO
// PUNTO 3
x = particles[ix][jy+1].position().x();
y = particles[ix][jy+1].position().y();
z = particles[ix][jy+1].position().z();
a.set(x,y,z);
// PUNTO 4
x = particles[ix+1][jy+1].position().x();
y = particles[ix+1][jy+1].position().y();
z = particles[ix+1][jy+1].position().z();
b.set(x,y,z);
// PUNTO 5
x = particles[ix+1][jy].position().x();
y = particles[ix+1][jy].position().y();
z = particles[ix+1][jy].position().z();
c.set(x,y,z);
//////////////////////////////////////////////////////////////
// CALCULAR LA NORMAL PARA EL SEGUNDO TRIANGULO
triangle[0] = a;
triangle[1] = b;
triangle[2] = c;
normal = getNormal(triangle);
// normal.normalize();
for(int i = 0 ; i < triangle.length; i++){
((PVector) vertices.get(index)).set(triangle[i]);
((PVector) normals.get(index)).set(normal);
index++;
}
//////////////////////////////////////////////////////////////
}
}
grid.updateVertices(vertices);
grid.updateNormals(normals);
}
private PVector getNormal (PVector[] triangle){
/*
* v1 = A-B, y
* v2 = A-C
* y un vector perpendicular al tri�ngulo (no tiene porqu� ser �nico)
* es el propucto cruz entre estos vectores:
* n = (v1 x v2)
*/
return PVector.sub(triangle[2], triangle[1]).cross(PVector.sub(triangle[1], triangle[0]));
}
private void printVertex(int ix, int jy){
System.out.print(
"I: " +ix+ " " +
"J: " +jy+ " " +
"X: " +x+ " " +
"Y: " +y+ " " +
"Z: " +z+ " " +
"U: " +u+ " " +
"V: " +v);
System.out.println();
}
void addVertex(float x, float y, float z, float u, float v)
{
PVector vert = new PVector(x, y, z);
PVector texCoord = new PVector(u, v);
PVector vertNorm = PVector.div(vert, vert.mag());
vertices.add(vert);
texCoords.add(texCoord);
normals.add(vertNorm);
}
/////////////////////////////////////////////
// FUNCIONAMIENTO DE LA GRILLA
/////////////////////////////////////////////
public void noiseShake(float tick, float amplification){
for(int i = 1; i < grid_HNodes - 1; i++){
for(int j = 1; j < grid_VNodes - 1; j++){
particles[i][j].position().add(
0,
0,
amplification * ( -0.5f + parent.noise(i * 0.07f , j * 0.07f, tick * 0.01f))
);
}
}
}
public void shake(float value){
for(int i = 0; i < grid_HNodes; i++){
for(int j = 0; j < grid_VNodes; j++){
particles[i][j].velocity().add(
0,
0,
Util.map(random.nextFloat(), 0.f, 1.f, -5 * value, 5 * value)
);
}
}
}
public void flock(float noiseTick){
parent.noiseDetail(10);
for(int i = 1; i < grid_HNodes - 1; i++){
for(int j = 1; j < grid_VNodes - 1; j++){
float zcoord = -0.5f + parent.noise(i,j,noiseTick);
particles[i][j].position().add(
0,
0,
zcoord * .1f
);
}
}
}
private void createGrid(){
//////////////////////////////////////////////////
// ESTRUCTURA GRILLA CENTRADA
///////////////////////////////////////////////////
float x, y, z;
for (int ix = 0; ix < grid_VNodes; ix++){
for (int jy = 0; jy < grid_HNodes; jy++){
///////////////////////////////////////////////////////
// creo los puntos de la grilla
///////////////////////////////////////////////////////
// para centrar la grilla
// tengo que compensar que el numero de columnas en realidad es
// el numero de vertices. La cantidad de columnas es el numero de vertices
// menos 1
x = (-grid_width + grid_width / grid_VNodes) / 2.f + ix * grid_width / grid_VNodes;
y = (-grid_height + grid_height / grid_HNodes) / 2.f + jy * grid_height / grid_HNodes;
z = 0.0f;
///////////////////////////////////////////////////////
// sistema de particulas
///////////////////////////////////////////////////////
particles[ix][jy] = ps.makeParticle(
particle_mass,
x ,
y,
z);
}
}
if(fixCorners){
// dejo fijas las cuatro de las esquinas
particles[0][0].makeFixed();
particles[0][grid_VNodes - 1].makeFixed();
particles[grid_HNodes - 1][0].makeFixed();
particles[grid_HNodes - 1][grid_VNodes - 1].makeFixed();
}else{
// fijo las de los costados
for(int i = 0 ; i < grid_HNodes; i++) particles[0][i].makeFixed();
for(int i = 0 ; i < grid_HNodes; i++) particles[grid_HNodes - 1][i].makeFixed();
for(int i = 0 ; i < grid_VNodes; i++) particles[i][0].makeFixed();
for(int i = 0 ; i < grid_VNodes; i++) particles[i][grid_VNodes - 1].makeFixed();
// fijo arriba y abajo
}
// conecto todo
// voy a recorrer todas las particulas teniendo la precaucion
// de que la si llegue al borde solo conecte hacia abajo
// o hacia la derecha segun corresponda
// hacia abajo evitando la ultima fila porque no conecta con nada
// hacia la derecha evitando la ultima columna porque no conecta con nada
for (int i = 0; i < grid_HNodes ; i++){
for (int j = 0; j < grid_VNodes ; j++){
// si no llegue abajo de todo
// conecto este con el de abajo
if(j != grid_VNodes - 1){
springs[(i * grid_HNodes) + j][0] = ps.makeSpring(
particles[i][j], particles[i][j+1],
spring_Strengh ,
spring_Damp,
spring_VLength
);
}
// si no llegue al borde de la derecha
// conecto este con el de derecha
if(i != grid_HNodes - 1){
springs[(i * grid_HNodes) + j][1] = ps.makeSpring(
particles[i][j], particles[i + 1][j],
spring_Strengh,
spring_Damp,
spring_HLength
);
}
}
}
// como no conecte ni la ultima fila ni la ultima columna
// el ultimo nodo lo conecto a mano pero al reves...
springs[grid_HNodes - 1][0] = ps.makeSpring(
particles[grid_Columns-1][grid_Rows-1], particles[grid_Columns-1][ grid_Rows - 2],
spring_Strengh ,
spring_Damp,
spring_VLength
);
springs[(grid_Columns * grid_Rows) - 1][1] = ps.makeSpring(
particles[grid_Columns-1][grid_Rows-1], particles[grid_Columns-2][ grid_Rows - 1],
spring_Strengh ,
spring_Damp,
spring_HLength
);
}
private void createModel(){
vertices = new ArrayList();
texCoords = new ArrayList();
normals = new ArrayList();
x = 0;
y = 0;
z = 0;
u = 0;
v = 0;
// creo los puntos que van a componer al modelo
// para cada vertice hay una particula asociada
for(int ix = 0; ix < grid_Rows; ix++){
for (int jy = 0; jy < grid_Columns; jy++) {
// PRIMER TRIANGULO
// PUNTO 0
x = particles[ix][jy].position().x();
y = particles[ix][jy].position().y();
z = particles[ix][jy].position().z();
u = (float) (1.0 / grid_Rows) * ix;
v = (float) (1.0 / grid_Columns) * jy;
addVertex(x, y, z, u, v);
printVertex(ix, jy);
// PUNTO 1
x = particles[ix][jy+1].position().x();
y = particles[ix][jy+1].position().y();
z = particles[ix][jy+1].position().z();
u = (float) (1.0 / grid_Rows) * ix;
v = (float) (1.0 / grid_Columns) * (jy + 1);
addVertex(x, y, z, u, v);
printVertex(ix, jy);
// PUNTO 2
x = particles[ix+1][jy].position().x();
y = particles[ix+1][jy].position().y();
z = particles[ix+1][jy].position().z();
u = (float) (1.0 / grid_Rows) * (ix + 1);
v = (float) (1.0 / grid_Columns) * jy;
addVertex(x, y, z, u, v);
printVertex(ix, jy);
// SEGUNDO TRIANGULO
// PUNTO 3
x = particles[ix][jy+1].position().x();
y = particles[ix][jy+1].position().y();
z = particles[ix][jy+1].position().z();
u = (float) (1.0 / grid_Rows) * ix;
v = (float) (1.0 / grid_Columns) * (jy + 1);
addVertex(x, y, z, u, v);
printVertex(ix, jy);
// PUNTO 4
x = particles[ix+1][jy+1].position().x();
y = particles[ix+1][jy+1].position().y();
z = particles[ix+1][jy+1].position().z();
u = (float) (1.0 / grid_Rows) * (ix + 1);
v = (float) (1.0 / grid_Columns) * (jy + 1);
addVertex(x, y, z, u, v);
printVertex(ix, jy);
// PUNTO 5
x = particles[ix+1][jy].position().x();
y = particles[ix+1][jy].position().y();
z = particles[ix+1][jy].position().z();
u = (float) (1.0 / grid_Rows) * (ix + 1);
v = (float) (1.0 / grid_Columns) * jy;
addVertex(x, y, z, u, v);
printVertex(ix, jy);
}
}
// una vez que tengo todos los puntos de la grilla
// creo el modelo
grid = new GLModel(
parent,
vertices.size(),
PConstants.TRIANGLES,
GLModel.STATIC);
grid.updateVertices(vertices);
//Sets the normals.
grid.initNormals();
grid.updateNormals(normals);
// Sets the colors of all the vertices to white.
grid.setBlendMode(PConstants.BLEND);
grid.setTint(255,255,255,255);
}
}