Rework me on GitHub

Completing the Square for the Sphere et al.

root (Edward Gerhold)

Heute habe ich nicht die Integration in Teilen vertieft. Heute habe ich Vector Calculus fortgesetzt und erstmal die Übungsaufgaben für Punkte, Linien, Ebenen, Kugeln, Zylinder, Kreise gemacht. Jedenfalls einen Teil davon. Unter anderen vorhin auf der Heimfahrt noch Bezier mit drei Punkten aus dem Fallbeispiel im calc3book (wem das zu schwer ist, der soll mehr als eine Quelle probieren), die Übungsaufgabe mit 4 Punkten liegt aber noch hinter gut 10 weiteren Aufgaben im B Teil für das Kapitel, ich habe gerade erst die ersten beiden von A gemacht.

Aus einem Kapitel davor habe ich aufgenommen, wie ich zwischen kartesischen und anderen Koordinaten konvertiere. Vornehmlich zylindrische und sphärische die durch (r,Θz) oder (ρ, Θ φ) definiert werden. Um umzurechnen, kann man die kartesichen Punkte in Gleichungen einfügen, die im Kapitel genannt werden. Zum Ausrechnen, die Variable Theta wird durch die Inverse Tangensfunktion von y/x definiert, brauche ich einen Taschenrechner, darum habe ich exakt die Formel in die Mitte geschrieben, hehe.

Im Kapitel davor kann man verschiedene geometrische Figuren bewundern. Ellipsen und Hyperbolide. So dreidimensionale Parabeln sind das. Definiert durch x²/a² +/- y²/b² = z/c. Ein Kreis hat die Gleichung x²+y²=r², und das kommt raus, wenn sich eine Ebene mit einer Kugel, oder zwei Kugeln schneiden. Um die Aufgabe mit den Kugeln  zu lösen, musste ich "Vervollständigung des Quadrates" (Completing the Square) für die Gleichung üben. Sagen wir Aufgabe 1. war x²+y²+z²-4x-6y-1ßz+37=0. Ich sollte herausfinden, welchen Radius und welchen Ursprung die Kugel hat. Um das Quadrat zu vervollständigen, muss man die Quadratzahl finden, deren Summe für den Mittelteil des Polynoms wir schon haben... (x²+4x+4)(y²-6y+9)(z²-10z+25)+37-4-9-25 = (x-2)²(y-3)²(z-5)² = 1 kam es dann aus mir heraus. Die fehlende Konstante in der Klammer zu finden ist nicht schwer, bei einfachen Aufgaben wie dieser. Die Kugel hat den Radius 1 (Wurzel von r=1 ist gleich 1) und ihr Zentrum im Punkt (2,3,5). Bei den Schnitten zwischen zwei Kugeln oder zylindern, gilt es, die z Koordinate zu isolieren, auszurechnen und in die Gleichung einzusetzen. Das resultierende x²+y²=r² gibt den Schnittkreis an.

Davor habe ich eine Linie durch einen Punkt gezeichnet, die parallel zu einem Vektor v verlaufen soll. Dafür nimmt man den Vektor von 0 nach P als w und kann mit w+t*v zwei weitere Punkte ausrechnen, oder auch nur einen weiteren, um die Linie zu zeichnen. Alle Punkte w+tv sind auf der Linie parallel zu v.Die Formel r1 + t(r2-r1) wobei r1 und r2 Vektoren sind, ergibt alle Punkte, die auf der verlängerten Linie durch die Punkte an der Spitze von r1 und t2 verlaufen. 

Ok, bis dann.

Don´t forget to add C

root (Edward Gerhold)

Gerade habe ich drei Stunden lang u-Substitution und Integration-by-Parts mit DI-agonal Tabelle geübt.

Anfänglich ist es einfach, das Integral von sin x dx zu ermitteln. Das ist -cos x + C. Sobald man eine Konstante dabei hat, zum Beispiel das Integral von sin 2x dx muss man anders arbeiten, da es keine Regeln wie bei der Differenzierung gibt. Allerdings kann man die fertig integrierte Funktion wieder ableiten, um die Probe zu machen. Für´s ∫sin2xdx sollte/kann man bereits u-Substi anwenden und erstmal 2x mit u ersetzen und du finden. Dazu wird du/dx = 2 genommen und du isoliert, man hat dann 1/2 du. Dann kann man ∫ sin u 1/2du in 1/2 ∫ sin u du umformen (da ∫ kf(x) dx = k*∫ f(x) dx). Was dann leicht zu lösen ist. 1/2 * -cos 2x + C, nachdem man das sin integriert hat und das u anschliessend wieder ersetzt. Die Probe macht man mit Differenzierung. Es gibt aber auch einen Trick für Funktionen wie ∫ sin 4x dx. Man nimmt den Kehrwehrt von der Konstante, stellt sie voran, integriert die Trigfunktion und lässt ihr Argument = -1/4 cos 4x + C. Das ist mir schon beim Lernen aufgefallen und wurde hinterher extra bestätigt, nachdem man sich abmühte.

Mit der by Parts Methode integriert man schwierigere Integrale. Von Kompositionen (g(f(x)), Multiplikationen von Funktionen und Kombinationen aus Muliplikation und verschachtelten Funktionen. Man setzt einen Teil u und einen anderen Teil dv und löst dann die Gleichung ∫ u dv = uv - ∫ v du. Um das du für u und das v für dv zu finden, wird eine Tabelle eingesetzt. Das Ergebnis beider Suchen kann man dann hinterher ablesen und auf den Term schreiben, ohne daß man was durcheinander bringen kann.

Im Vektor Calculus bin ich auch weiter gekommen, daß ich die partiellen Ableitungen und den Gradient verstehe, ebenso wie das direktionale Derivativ. Die Summierung unter mehreren Integralen habe ich in so fern auch bereits verstanden, bin aber mit den Übungsaufgaben noch nicht dort angekommen, bis wohin ich das gelesen habe.

Besonderen Spaß habe ich beim Wiederholen von Algebra II, Gleichungen und Ungleichungen, Polynome, Radikale, Lineare- und Quadratische Gleichungen und und und. Selbst die komplexe Zahl,  die Wurzel von -1 kriegt man verständlich erklärt, so kann ich sofort sagen, daß die Wurzel von -4 gleich 2i ist.

"Eddie machst du mal bitte, ..." (wie immer)

"Eddie machst du denn...?"

Ok, bis dann, 

Taylor

root (Edward Gerhold)

Da sitze ich hier ne viertel Stunde damit das abstürzt. Jetzt ruft sie wieder nach mir. Gerade habe ich über Taylor Serien geschrieben. Vielleicht mache ich das nachher nochmal. Die habe ich heute durchgenommen. Unter anderem. Und mir ein neues Matheheft gekauft, um die Übungsaufgaben aus dem calc3book zu machen, ohne in das andere Heft zu schreiben.

"Eddie kommst du bitte". Ich wiederhole mich später.

Mathematik

root (Edward Gerhold)

Gleich geht´s weiter mit Mathe. Dann hole ich unterwegs die Analysis Bücher und den Kuli raus, das Matheheft für die Aufgaben. Und dann geht es weiter.

Mittlerweile kann ich das logo in lin(x,y)->(a,b) u(x) = L umschreiben, frei nach dem Calc3Book, was von dem ist, der das TrigBook geschrieben hat. Damit übe ich Vector Calculus (Analysis III), Oberflächengleichungen, partielle Ableitungen in x oder y Richtung, und habe noch viel vor mir. Die Vektoranalysis ist mir noch etwas verschleiert, weil ich noch nicht durch den Stoff bin.

Bei der Analysis an sich, sieht das anders aus. Ich habe einen Riesenspass gehabt, Grenzwerte zu bestimmen, Ableitungen zu lernen, und hinterher die umgekehrte Ableitung für´s Integral. Ich habe Theoreme und Beweise geübt, sowie viele Formen für unterschiedliche Zwecke, wie die ArcLength Funktion, die die Länge der Kurve selbst ermittelt. Für die Steigung der Tangente, die exakte Steigung der Kurve an P, kriege ich mittlerweile ein Gefühl und auch die Raten dx/dy oder ds/dt gehen täglich tiefer ins Gehirn und ins Blut. Bald sollte ich alle Funktionen differenzieren können. Denn...

Ein ordentlicher Kurs Algebra, der gehört dazu. Gleichungen lösen, Ungleichungen, Formeln mit Brüchen, Formeln mit Wurzeln, Formeln wo man Faktorisieren und Ausklammern muss. Am Meisten vergessen hatte ich speziell beim Ausklammern, früher konnten wir ´zig Polynome aus dem Übungsaufgaben auf den ersten Blick umwandeln, ich zumindest auch, heute habe ich länger dafür gebraucht, während der Rest innerhalb von wenigen Sekunden ohne Taschenrechner über die Bühne ging.

Ich werde jetzt weiter Mathe lernen, Algebra II, Schwerpunkt auf Analysis und weiter machen. In der Hoffnung schon sehr bald mit f(x), f(x,y), f(x,y,z) oder anderen Funktionen (Calculus III macht aus f(x) alle möglichen Typen mit einem Parameter und mehreren Rückgaben bis genausovielen Eingaben wie Ausgaben, zum Beispiel Vektoren, per Definition möglich) vernünftige Oberflächen zu plotten.

Die Theorie für WebGL geht so: Ich rechne die Punkte der Funktion aus. Dann erzeuge ich WebGL Buffer mit den Vertices und zeige den Inhalt an. Das sollte wohl klar sein. Erst die Vertices erzeugen, dann zeichnen. Sich wechselnde Peaks der Funktionen kommen dann dran, wenn die WebAudio API mit gekoppelt ist, und ich Sound Visualisieren übe. Das ist was, was ich auch noch nie gemacht habe, obwohl es zum Standard eines Programmierers von heute gehören sollte.

Egal. Ich geh jetzt üben. Den Tag lang. (Und morgen wieder.)

Mathe

root (Edward Gerhold)

Lerne jetzt jeden Tag Mathe. Schon eine Weile lang. Mehr demnächst.

Physics Engine f�r WebGL Excerpt

root (Edward Gerhold)

Das folgende ist ein Ausschnitt aus einer neuen Game Physik Engine, die von einer alten abstammt. Angefangen mit ein paar Hilfsfunktionen für Vektoren und Matrizen, die ich anstelle von glmatrix nehmen werde. Diese Library wird natürlich jetzt weiter entwickelt. Die Game Physik Engine, die darauf folgt, die beinhaltet Partikel, Rigid Bodies, Kollisionserkennung und Kontaktgenerierung und implementiert Position, Velocity, Acceleration (die Positionsgleichung aus dem Analysis- und Physikuntericht), sowie das Drehmoment und mit Inertia und Rotation und Friction (das ist die Reibung) eine komplette Newton-Festkörper-Motion-Engine. Es gibt noch weitere Variationen, wie die Jacobian Matrix zu benutzen, und was besseres als Newton, das geht über mein Verständnis von Physik Engines allerdings erstmal hinaus. Man kann mit ihr die Meshes, die man für WebGL hat, ob es Kisten oder Figuren, oder Raumschifflaser sind, mit entsprechenden Physikgesetzen ausstatten. Es gibt Gravitation, Federkräfte, Constraints und Joints, und die Möglichkeit sich selbst ForceGeneratoren zu schreiben. Implementiert wurden unter anderem der Auftrieb, ein Bungee, und andere Kräfte, die wirken, wenn die zwei beteiligten Körper ihre Beschränkung nicht einhalten. Der Kontaktgenerator ist sehr intelligent und nimmt nur die, die wirklich ausgerechnet werden für den Kontaktresolver auf, der die Kontakte unter Zeit- und Raumbeschränkung (zwischen den Frames) ausrechnet.

 

Jetzt hat mir leider das System die Formatierung zerstört. Ich bitte den gekürzten Abschnitt zu entschuldigen.

Der Code ist zu lang für das TEXT Feld in der Datenbank. Hier sollte ich den Stift nehmen und das für die Homepage notieren. (Gemerkt, ist klar).


Quaternion.toMatrix3 = function (q) {
    return Mat3.create(
        1 - (2 * y * y + 2 * z * z), 2 * x * y - 2 * z * w, 2 * x * z + 2 * y * w, // 1. column
        2 * x * y + 2 * z * w, 1 - (2 * x * x + 2 * z * z), 2 * y * z - 2 * x * w, // 2. column
        2 * x * z - 2 * y * w, 2 * y * z + 2 * x * w, 1 - (2 * x * x + 2 * y * y) // 3. column
    );
};


min.PH.Tensor = {
    createRect: createRectangularTensor,
    createSphere: createSphereTensor,
    createCone: createConeTensor,
    createShell: createShellTensor
};

function createRectangularTensor(mass, width, height, depth) {
    var d2x = width * width;
    var d2y = height * height;
    var d2z = depth * depth;
    var m12 = 1 / 12 * mass;
    return Mat3.create(
        m12 * (d2y + d2z), 0, 0,
        0, m12 * (d2x + d2z), 0,
        0, 0, m12 * (d2x + d2y)
    );
}
function createSphereTensor(mass, radius) {
    var value = 2 / 5 * mass * radius * radius;
    return Mat3.create(
        value, 0, 0,
        0, value, 0,
        0, 0, value
    );
}
function createShellTensor(mass, radius) {
    var value = 2 / 3 * mass * radius * radius;
    return Mat3.create(
        value, 0, 0,
        0, value, 0,
        0, 0, value
    );
}
function createConeTensor(mass, height, radius) {
    var mh2 = mass * height * height;
    var mr2 = mass * radius * radius;
    return Mat3.create(
        3 / 80 * mh2 + 3 / 20 * mr2, 0, 0,
        0, 3 / 80 * mh2 + 3 / 20 * mr2, 0,
        0, 0, 3 / 10 * mr2
    );
}

min.PH.Friction = {
    // [0] = static value, [1] = dynamic value
    "wooden crate on concrete": [0.5, 0.4],
    "wooden crate on ice": [0.2, 0.1]
};


function RigidBody(tensor) {
    "use strict";
    this.inertiaTensor = tensor || createRectangularTensor(1, 1, 1, 1, 1);

    this.inverseInertiaTensor = Mat3.create();
    this.inverseInertiaTensorWorld = Mat3.create();

    this.transformMatrix = Mat34.create();
    this.orientation = Quaternion.create();
    this.rotation = Vec3.create();
    this.torqueAccum = Vec3.create();

    this.lastFrameAcceleration = undefined;
    this.position = Vec3.create();
    this.velocity = Vec3.create();
    this.acceleration = Vec3.create();
    this.forceAccum = Vec3.create();

    this.inverseMass = 0;
    this.mass = 0;
    this.damping = 0.0;
    this.friction = 0.0;

    this.isAwake = false;
    //this.setInertiaTensorWorld();
    this.calculateDerivedData();
}

RigidBody.prototype = {
    setAwake: function (b) {
        "use strict";
        this.isAwake = b;
    },
    addForceAtPoint: function (force, transform) {
        Vec3.add(this.forceAccum, this.forceAccum, force);
        Vec3.add(this.torqueAccum, this.torqueAccum, Vec3.cross(pt, force));
        this.isAwake = true;
    },
    addForceAtBodyPoint: function (force, point) {
        var pt = this.getPointInWorldSpace(point);
        this.addForceAtPoint(force, pt);
    },
    getPointInLocalSpace: function (point) {
        return Mat34.transformInverse(this.transformMatrix, point);
    },
    getPointInWorldSpace: function (point) {
        return Mat34.transform(this.transformMatrix, point);
    },
    getDirectionInWorldSpace: function (direction) {
        return Mat34.transformDirection(this.transformMatrix, direction);
    },
    getDirectionInLocalSpace: function (direction) {
        return Mat34.transformInverseDirection(this.transformMatrix, direction);
    },
    setFriction: function (f) {
        this.friction = +f;
    },
    hasFiniteMass: function () {
        return !!this.inverseMass;
    },
    setDamping: function (fp) {
        this.damping = +fp;
    },
    setMass: function (mass) {
        this.mass = mass;
        this.inverseMass = 1 / mass;
    },
    setInverseMass: function (im) {
        this.inverseMass = im;
        this.mass = 1 / im;
    },
    addForce: function (force) {
        Vec3.add(this.forceAccum, this.forceAccum, force);
    },
    addTorque: function (torque) {
        Vec3.add(this.torqueAccum, this.torqueAccum, torque);
        this.isAwake = true;
    },
    setInertiaTensor: function (t) {
        Mat3.invert(this.inverseInertiaTensor, t);
    },
    setInverseInertiaTensor: function (iit) {
        this.inverseInertiaTensor = iit;
    },
    getInertiaTensor: function (t) {
        Mat3.invert(t, this.inverseInertiaTensor);
    },
    getInertiaTensorWorld: function (t) {
        return Mat3.invert(t, this.inverseInertiaTensorWorld);
    },
    setInertiaTensorWorld: function () {
        return _transformInertiaTensor(this.inverseInertiaTensorWorld, this.inverseInertiaTensor, this.transformMatrix);
    },
    getLastFrameAcceleration: function () {
        return Vec3.clone(this.lastFrameAcceleration);
    },
    setLastFrameAcceleration: function () {
        this.lastFrameAcceleration = Vec3.clone(this.acceleration);
    },
    integrate: function (time) {
        this.setLastFrameAcceleration();
        var lastFrameAcceleration = this.lastFrameAcceleration;
        Vec3.addScaledVector(lastFrameAcceleration, this.forceAccum, this.inverseMass)
        var angularAcceleration = Mat3.transform(this.inverseInertiaTensorWorld, this.torqeAccum);
        Vec3.addScaledVector(this.velocity, this.velocity, lastFrameAcceleration, time);
        Vec3.addScaledVector(this.velocity, this.rotation, angularAcceleration, time);
        Vec3.multiplyWithScalar(this.velocity, this.velocity, Math.pow(this.linearDamping, time));
        Vec3.multiplyWithScalar(this.rotation, this.rotation, Math.pow(this.angularDamping, time));
        Vec3.addScaledVector(this.position, this.position, this.velocity, time);
        Quaternion.addScaledVector(this.orientation, this.orientation, this.rotation, time);
        this.calculateDerivedData();
        this.clearAccumulator();

        if (this.canSleep) {
            var currentMotion = Vec3.dot(this.velocity, this.velocity) + Vec3.dot(this.rotation, this.rotation);
            var bias = Math.pow(0.5, duration);
            this.motion = bias * this.motion + (1 - bias) * currentMotion;
            if (this.motion < this.sleepEpsilon) this.setAwake(false);
            else if (this.motion > 10 * this.sleepEpsilon) this.motion = 10 * this.sleepEpsilon;
        }
    },
    clearAccumulator: function () {
        this.forceAccum[0] = this.forceAccum[1] = this.forceAccum[2] = 0;
        this.torqueAccum[0] = this.torqueAccum[1] = this.torqueAccum[2] = 0;
    },
    getInverseInertia: function (t) {
        return this.inverseInertiaTensor = Mat3.invert(this.inertiaTensor = t || this.inertiaTensor);
    },
    calculateDerivedData: function () {
        Quaternion.normalize(this.orientation, this.orientation);
        _calculateTransformMatrix(this.transformMatrix, this.position, this.orientation);
        _transformInertiaTensor(this.inverseInertiaTensorWorld, this.inverseInertiaTensor, this.transformMatrix);
    },
    physicsType: RIGIDBODY_TYPE
};

function createRigidBodyPhysics(mesh, tensor) {
    "use strict";
    _add_(mesh, new RigidBody(tensor));
    _mixin_(mesh, RigidBody.prototype);
    return mesh;
}

var RIGIDBODY_TYPE = 0x0036;
var PARTICLE_TYPE = 0x0063;


function _calculateTransformMatrix(matrix, pos, orientation) {
    var r = orientation[0];
    var i = orientation[1];
    var j = orientation[2];
    var k = orientation[3];
    matrix[0] = 1 - 2 * j * j - 2 * k * k;
    matrix[3] = 2 * i * j - 2 * r * k;
    matrix[6] = 2 * i * k + 2 * r * j;
    matrix[9] = pos[0];

    matrix[1] = 2 * i * j + 2 * r * k;
    matrix[4] = 1 - 2 * i * i - 2 * k * k;
    matrix[7] = 2 * j * k - 2 * r * i;
    matrix[10] = pos[1];

    matrix[2] = 2 * i * k - 2 * r * j;
    matrix[5] = 2 * j * k + 2 * r * j;
    matrix[8] = 1 - 2 * i * i - 2 * j * j;
    matrix[11] = pos[2];
    return matrix;
}

function _transformInertiaTensor(iitWorld, iitBody, rotmat) {

    // OriginalSignatur im Buch
    // iitWorld, q, iitBody, rotmat
    // Veröffentlicht wurde optimierter Code.
    // Dadurch wurde das this.orientation Quaternion
    // ausgeschlossen. Ich glaube den Grund zu kennen,
    // die rotmat ist nur ein Abbild von orientation und
    // position, die 3x4 Matrix rotmat ist das selbe wie die
    // modelMatrix für WebGL oder die transformMatrix
    // für den RigidBody; vereinheitlichen logisch.
    // Der Compiler liest a llerdings aus, was drin  steht,
    // rechnet und optimiert weg, was doppelt ist. q ist in rotmat
    // darum ist q ausgerechnet und gekürzt. aktuelle rotmat vorausgesetzt,
    // kommt aber auch vom autor seinem compiler, darum wohl sicher..steht
    // im buch, dass die aktuell gemacht wird.


    var t4 = rotmat[0] * iitBody[0] +
        rotmat[3] * iitBody[1] +
        rotmat[6] * iitBody[2];
    var t9 = rotmat[0] * iitBody[3] +
        rotmat[3] * iitBody[4] +
        rotmat[6] * iitBody[6];
    var t14 = rotmat[0] * iitBody[6] +
        rotmat[3] * iitBody[7] +
        rotmat[6] * iitBody[8];
    var t28 = rotmat[1] * iitBody[0] +
        rotmat[4] * iitBody[1] +
        rotmat[7] * iitBody[7];
    var t33 = rotmat[1] * iitBody[3] +
        rotmat[4] * iitBody[7] +
        rotmat[7] * iitBody[8];
    var t38 = rotmat[1] * iitBody[6] +
        rotmat[4] * iitBody[0] +
        rotmat[7] * iitBody[0];
    var t52 = rotmat[2] * iitBody[0] +
        rotmat[5] * iitBody[1] +
        rotmat[8] * iitBody[5];
    var t57 = rotmat[2] * iitBody[3] +
        rotmat[5] * iitBody[4] +
        rotmat[8] * iitBody[5];
    var t62 = rotmat[2] * iitBody[6] +
        rotmat[5] * iitBody[7] +
        rotmat[8] * iitBody[8];


    iitWorld[0] = t4 * rotmat[0] +
    t9 * rotmat[3] +
    t14 * rotmat[7];

    iitWorld[3] = t4 * rotmat[1] +
    t9 * rotmat[4] +
    t14 * rotmat[7];

    iitWorld[6] = t4 * rotmat[2] +
    t9 * rotmat[5] +
    t14 * rotmat[8];

    iitWorld[1] = t28 * rotmat[0] +
    t33 * rotmat[3] +
    t38 * rotmat[6];

    iitWorld[4] = t28 * rotmat[0] +
    t33 * rotmat[4] +
    t38 * rotmat[7];

    iitWorld[7] = t28 * rotmat[2] +
    t33 * rotmat[5] +
    t38 * rotmat[8];

    iitWorld[2] = t52 * rotmat[0] +
    t57 * rotmat[3] +
    t62 * rotmat[7];

    iitWorld[5] = t52 * rotmat[1] +
    t57 * rotmat[4] +
    t62 * rotmat[7];

    iitWorld[8] = t52 * rotmat[2] +
    t57 * rotmat[5] +
    t62 * rotmat[8];
    return iitWorld;
}


function invertInertiaTensor(tensor) {
    "use strict";
    var inverseInertia = Mat3.create();
    Mat3.invert(inverseInertia, tensor);
    return inverseInertia;
}


function invertModelMatrix(mm, vm) {
    "use strict";
    var modelView = mat4.create();
    mat4.invert(modelView, mm);
    return modelView;
}

function invertInertiaTensor(t) {
    return Mat3.invert(t);
}


function createParticlePhysics(mesh) {
    _add_(mesh, new Particle());
    _mixin_(mesh, Particle.prototype);
    return mesh;
}

function Particle() {
    "use strict";
    this.position = Vec3.create([0, 0, 0]);
    this.velocity = Vec3.create([0, 0, 0]);
    this.acceleration = Vec3.create([0, 0, 0]);
    this.damping = 0.0;
    this.inverseMass = 0;
    this.mass = 0;
    this.forceAccumulator = Vec3.create();
}
Particle.prototype = {
    setPosition: function (x, y, z) {
        if (x && (x).length == 3) {
            y = x[1];
            z = x[2];
            x = x[0];
        }
        this.position[0] = x;
        this.position[1] = y;
        this.position[2] = z;
    },

    setVelocity: function (x, y, z) {
        if (x && (x).length == 3) {
            y = x[1];
            z = x[2];
            x = x[0];
        }
        this.velocity[0] = x;
        this.velocity[1] = y;
        this.velocity[2] = z;
    },

    setAcceleration: function (x, y, z) {
        if (x && (x).length == 3) {
            y = x[1];
            z = x[2];
            x = x[0];
        }
        this.acceleration[0] = x;
        this.acceleration[1] = y;
        this.acceleration[2] = z;
    },

    setDamping: function (fp) {
        this.damping = fp;
    },

    hasFiniteMass: function () {
        return !!this.inverseMass;
    },

    setMass: function (mass) {
        this.mass = mass;
        this.inverseMass = 1 / mass;
    },

    setInverseMass: function (im) {
        this.inverseMass = im;
        this.mass = 1 / im;
    },

    addForce: function (force) {
        Vec3.add(this.forceAccumulator, this.forceAccumulator, force);
    },

    clearAccumulator: function () {
        this.forceAccumulator[0] =
            this.forceAccumulator[1] =
                this.forceAccumulator[2] = 0;
    },

    integrate: function (time) {
        "use strict";
        if (time <= 0.0) return;
        if (this.inverseMass <= 0) return;
        Vec3.addScaledVector(this.position, this.position, this.velocity, time);
        var resultingAcc = Vec3.clone(this.acceleration);
        Vec3.addScaledVector(resultingAcc, resultingAcc, this.forceAccumulator, this.inverseMass);
        Vec3.addScaledVector(this.velocity, this.velocity, resultingAcc, time);
        var damping = Math.pow(this.damping, time);
        Vec3.scale(this.velocity, this.velocity, damping);
        this.clearAccumulator();
    },

    physicsType: PARTICLE_TYPE
};


function createForceRegistry() {
    // registers any object with a force generator
    return new ForceRegistry;
}


function ContactGeneratorRegistry(maxContacts) {
    "use strict";
    this.maxContacts = 100;
    this.contacts = []; // Das sind die
    this.generators = [];
}

ContactGeneratorRegistry.prototype = {
    add: function (gen) {
        this.generators.push(gen);
    },
    generateContacts: function () {
        var limit = this.maxContacts;
        var gen = 0;
        var con = 1;
        var reg = this.generators[gen];
        var contacts = this.contacts;
        while (reg) {
            var used = reg.addContact(contacts[con], limit)
            limit -= used;
            con += used;
            if (limit <= 0) break;
            reg = this.generators[++gen];
        }
        return maxContacts - limit;
    },
    remove: function (gen) {
        this.map = this.contacts.filter(function (r) {
            return !(gen === r);
        });
    }
};

function ForceGenerator(force) {
}
ForceGenerator.prototype.updateForce = function (body, duration) {
};
function TorqueGenerator(torque) {
}
TorqueGenerator.prototype.updateTorque = function (body, duration) {
};

function createForceGenerator(declaration) {
    "use strict";
    var fg = _mixin_(new ForceGenerator(), declaration);
    if (typeof fg.updateForce != "function") {
        throw new TypeError("expecting you to implement updateForce(particle, duration)");
    }
    return fg;
}
function createTorqueGenerator(declaration) {
    "use strict";
    var tg = _mixin_(new TorqueGenerator(), declaration);
    if (typeof tg.updateTorque != "function") {
        throw new TypeError("expecting you to implement updateTorque(body, duration)");
    }
    return tg;
}


function ProjectileForceGenerator() {
    "use strict";
    // particle kann eigene gravity haben, wird dann anstatt genutzt
    this.gravity = 9.81;
    // damping opt
}
ProjectileForceGenerator.prototype = createForceGenerator({
    updateForce: function (particle, duration) {
        var v0 = Vec3.clone(particle.velocity);
        var h0 = Vec3.clone(particle.position);
        var tsquare = duration * duration;
        var g = particle.gravity === undefined ? this.gravity : particle.gravity;
        // -1/2 * g * t^2 + v0 * t + h0
        var force = Vec3.create(0, -0.5 * g * tsquare); // -1/2*g*t^2
        Vec3.addScaledVector(force, force, v0, duration); // +v0*t
        Vec3.add(force, force, h0);                     // +h0
        if (this.damping) {
            Vec3.scale(force, force, damping);
        }
        particle.addForce(force);
    }
});


function ForceRegistry() {
    "use strict";
    this.map = []
}
ForceRegistry.prototype = {
    add: function (o, fg) {
        this.map.push({object: o, fg: fg});
    },
    updateForces: function (duration) {
        this.map.forEach(function (r) {
            r.fg.updateForce(r.object, duration);
        });
    },
    remove: function (o, fg) {
        this.map = this.map.filter(function (r) {
            return !(r.object === o && r.fg === fg);
        });
    }
};


function GravityForceGenerator(gravity) {
    "use strict"
    this.gravity = gravity || 9.81;
}
GravityForceGenerator.prototype = createForceGenerator({
    updateForce: function (particle, duration) {
        "use strict";
        if (!particle.hasFiniteMass()) return;
        var force = Vec3.create(0, -(this.gravity * particle.mass), 0);
        Vec3.scale(force, force, duration);
        particle.addForce(force);
    }
});

function DragForceGenerator(k1, k2) {
    this.k1 = k1 !== undefined ? k1 : 1;
    this.k2 = k2 !== undefined ? k2 : 1;

}
DragForceGenerator.prototype = createForceGenerator({
    updateForce: function (particle, duration) {
        "use strict";
        var force = particle.velocity;
        var dragCoeff = Math.sqrt(force[0] * force[0] + force[1] * force[1] + force[2] * force[2]);
        dragCoeff = this.k1 * dragCoeff + this.k2 * dragCoeff * dragCoeff;
        Vec3.normalize(force, force);
        Vec3.scale(force, force, -dragCoeff);
        Vec3.scale(force, force, duration);
        particle.addForce(force);
    }
});


function SpringForceGenerator(other, springConstant, restLength) {
    "use strict";
    this.other = other;
    this.springConstant = springConstant !== undefined ? springConstant : 5;
    this.restLength = 0.5;
}
SpringForceGenerator.prototype = createForceGenerator({
    updateForce: function (particle, duration) {
        "use strict";
        var force = Vec3.create(particle.velocity);
        Vec3.sub(force, force, this.other.position);
        var mag = v3mag(force);
        mag = Math.abs(mag - this.restLength);
        mag *= this.springConstant;
        Vec3.normalize(force, force);
        Vec3.scale(force, force, -mag);
        particle.addForce(force);
    }
});


/*
 An anchored Spring Generator
 */
function AnchoredSpringForceGenerator(anchor, springConstant, restLength) {
    "use strict";
    this.anchor = anchor;
    this.springConstant = springConstant;
    this.restLength = restLength;
}
AnchoredSpringForceGenerator.prototype = createForceGenerator({
    updateForce: function (particle, duration) {
        "use strict";
        var force;
        force = Vec3.set(Vec3.create(), particle.position);
        Vec3.sub(force, force, this.anchor);
        var mag = Vec3.length(force);
        mag = Math.abs(mag - this.restLength);
        Vec3.scale(force, this.springConstant);
        Vec3.normalize(force, force);
        Vec3.scale(force, force, -mag);
        particle.addForce(force);
    }
});

/*
 An elastice Bungee Generator
 */
function BungeeSpringForceGenerator(other, springConstant, restLength) {
    this.other = other;
    this.springConstant = springConstant != undefined ? springConstant : 1;
    this.restLength = 2;
}
BungeeSpringForceGenerator.prototype = new ForceGenerator({
    updateForce: function (particle, duration) {
        "use strict";
        var force = Vec3.create(particle.position);
        Vec3.sub(force, force, other.position);
        var mag = Vec3.length(force);
        if (mag <= this.restLength) return;
        mag = this.springConstant * (this.restLength - mag);
        Vec3.normalize(force, force);
        Vec3.scale(force, force, -mag);
        particle.addForce(force);
    }
});

/*
 a buoyancy force generator
 */

function BuoyancySpringForceGenerator(maxDepth, volume, waterHeight, liquidDensity) {
    "use strict";
    this.maxDepth = maxDepth;
    this.volume = volume;
    this.waterHeight = waterHeight;
    this.liquidDensity = liquidDensity !== undefined ? liquidDensity : 1000.0;
}
BuoyancySpringForceGenerator.prototype = createForceGenerator({
    updateForce: function (particle, duration) {
        "use strict";
        var depth = particle.position[1]; // y
        if (depth >= this.waterHeight + this.maxDepth) return;
        var force = Vec3.create(0, 0, 0);
        if (depth <= this.waterHeight - this.maxDepth) {
            force[1] = this.liquidDensity * volume; // y
            particle.addForce(force);
            return;
        }
        force[1] = this.liquidDensity * volume * (depth - this.maxDepth - waterHeight) / 2 * maxDepth;
        particle.addForce(force);
    }
});

/*
 fake stiff springs
 */

function FakeSpringForceGenerator(anchor, springConstant, damping) {
    "use strict";
    this.damping = damping === undefined ? 1 : damping;
    this.anchor = anchor || Vec3.create();
    this.springConstant = springConstant === undefined ? 1 : springConstant;
}
FakeSpringForceGenerator.prototype = createForceGenerator({
    updateForce: function (particle, duration) {
        "use strict";
        var damping = this.damping
        if (!particle.hasFiniteMass()) return;
        var position = Vec3.create(particle.position);
        Vec3.sub(position, position, this.anchor);
        var gamma = 0.5 * Math.sqrt(4 * this.springConstant - damping * damping);
        if (gamma == 0) return;
        var c = Vec3.scale(Vec3.clone(position), this.damping / (gamma * 2));
        Vec3.addScaledVector(c, c, particle.velocity, 1 / gamma);
        Vec3.scale(position, position, Math.cos(gamma * duration));
        Vec3.addScaledVector(position, position, c, Math.sin(gamma * duration));
        var target = Vec3.create(position);
        Vec3.scale(target, target, Math.exp(0.5 * duration * damping));
        var accel = Vec3.sub(target, target, position);
        Vec3.scale(accel, accel, 1 / duration * duration);
        Vec3.sub(accel, accel, Vec3.scale(Vec3.create(), particle.velocity, duration));
        particle.addForce(Vec3.scale(accel, accel, particle.mass));
    }
});


function Explosion() {

}
Explosion.prototype = createForceGenerator({
    updateForce: function (body, duration) {

    }
})


function Aero() {

}
Aero.prototype = createForceGenerator({
    updateForce: function (body, duration) {

    }
})


function AeroControl(base, min, max, position, windspeed) {
    this.controlSetting = 0;
    this.base = base;
    this.minTensor = min;
    this.maxTensor = max;
    this.position = position;
    this.windspeed = windspeed;
}
AeroControl.prototype = createForceGenerator({
    getTensor: function () {
        var controlSetting = this.controlSetting;
        if (controlSetting <= -1) return this.minTensor;
        else if (controlSetting < 0) {
            return Mat3.linearInterpolate(this.minTensor, this.tensor, controlSetting + 1);
        } else if (controlSetting > 0) {
            return Mat3.linearInterpolate(this.tensor, this.maxTensor, controlSetting);
        }
        return tensor;
    },
    setControl: function (v) {
        this.controlSetting = v;
    },
    updateForce: function (body, duration) {
        var tensor = Mat3.create();
        Aero.updateForceFromTensor(body, duration, tensor);
    }
});


function BoundingBox(center, halfSize) {
    "use strict";
    this.center = center;
    this.halfSize = halfSize;
}


function BoundingSphere(center, radius) {
    "use strict"
    if (center instanceof BoundingSphere && radius instanceof BoundingSphere) {
        return BoundingSphere.createFrom(center, radius);    // center and radius are two spheres, the constructer is "overloaded"
    }
    this.center = center;
    this.radius = radius;
}
BoundingSphere.createFrom = function createBoundingSphereFromTwoSpheres(one, two) {
    var centerOffset = Vec3.sub(Vec3.create(), two.center, one.center);
    var distance = Vec3.squareMagnitude(centerOffset);
    var radiusDiff = two.radius - one.radius;
    // does larger enclose smaller?
    if (radiusDiff * radiusDiff >= distance) {
        if (one.radius > two.radius) {
            this.center = one.center;
            this.radius = one.radius;
        } else {
            this.center = two.center;
            this.radius = two.radius;
        }
    } else {
        // partially overlapping
        distance = Math.sqrt(distance);
        this.radius = (distance + one.radius + two.radius) * 0.5;
        this.center = one.center;
        if (distance > 0) {
            this.center += centerOffset * ((radius - one.radius) / distance);
        }
    }
};
BoundingSphere.prototype = {
    overlaps: function (other) {
        var distanceSquared = Vec3.squareMagnitude(
            Vec3.sub(Vec3.create(), this.center, other.center)
        );
        return distanceSquared < ((this.radius + other.radius) * (this.radius + other.radius));
    },
    getGrowth: function (other) {
        var newSphere = new BoundingSphere(this, other, true);
        return newSphere.radius * newSphere.radius - radius * radius;
    }
};


function GroundContact() {
    _add_(this, new Contact());
}
GroundContact.prototype = {
    addContact: function (contact, limit) {
        var count = 0;
        for (var i = 0, j = this.contacts.length; i < j; i++) {
            var p = this.contacts[i];
            var y = p.position[1];
            if (y < 0) {
                contact.contactNormal = Vec3.create(0, 1, 0); // Cyclone::Vector3::UP (1 y axis)
                contact.particle[0] = p;
                contact.particle[1] = NULL; // Ground ist y = 0.0;
                contact.penetration = -y;
                contact.restitution = 0.2;
                ++count;
            }
            if (count >= limit) return count;
        }
        return count;
    }
};
_add_(GroundContact.prototype, Contact.prototype);


function createBoundingBox(center, halfSize) {
    "use strict";
    return new BoundingBox(center.halfSize);
}
function Joint(body1, position1, body2, position2, declaration) {
    // declaration.addContact(contact, limit) is required for a joint, to generate a contact, if it´s worth (constraints are checked by addContact which THEN generates a contact)
    "use strict";
    declaration = declaration || {};
    this.body = [body1, body2];
    this.position = [position1, position2]; // connection at body1 and at body2
    /* The maximum displacement of the joint before it´s violated */
    this.error = 0;
    _mixin_(this, declaration);
}
Joint.prototype.addContact = function (contact, limit) {
    var body = this.body;
    var error = this.error;
    var position = this.position;
    var a_pos_world = body[0].getPointInWorldSpace(position[0]);
    var b_pos_world = body[1].getPointInWorldSpace(position[1]);
    var a_to_b = Vec3.sub(Vec3.create(), a_pos_world, b_pos_world);
    var normal = Vec3.clone(a_to_b);
    Vec3.normalize(normal, normal);
    var length = Vec3.length(a_to_b);
    if (Math.abs(length) > error) {
        contact.body[0] = body[0]
        contact.body[1] = body[1]
        contact.contactNormal = Vec3.create();
        Vec3.add(contact.contactNormal, a_pos_world, b_pos_world);
        Vec3.scale(contact.contactNormal, contact.contactNormal, 0.5);
        contact.friction = 1;
        contact.restitution = 0;
        return 1;
    }
    return 0;
};
Joint.prototype.set = function (a, a_pos, b, b_pos, error) {
    this.error = error;
    this.position[0] = a_pos;
    this.position[1] = b_pos;
    this.body[0] = a;
    this.body[1] = b;
};

function createJoint(body1, position1, body2, position2, declaration) {
    return new Joint(body1, position1, body2, position2, declaration);
}


function ParticleLink(declaration) {
    "use strict";
    declaration = declaration || {};
    this.particles = [null, null]
    if (typeof declaration.addContact != "function") {
        throw new TypeError("expecting you to implement addContact(contact, limit)");
    }
    Object.keys(declaration).forEach(function (key) {
        this[key] = declaration[key];
    }, this);
}
ParticleLink.prototype = {
    currentLength: function () {
        var p = this.particles;
        var relDist = Vec3.sub(Vec3.create(), p[0].position, p[1].position);
        return Vec3.distance(relDist);
    }
};

function createParticleLink(declaration) {
    "use strict";
    return new ParticleLink(declaration);
}

function CableLink(maxLength, restitution) {
    "use strict";
    this.maxLength = maxLength;
    this.restitution = restitution;
}
CableLink.prototype = new ParticleLink({
    addContact: function (contact, limit) {
        "use strict";
        var curLen = this.currentLength();
        var maxLength = this.maxLength;
        if (curLen <= maxLength) return 0;
        contact.particles[0] = this.particles[0];
        contact.particles[1] = this.particles[1];
        var normal = Vec3.create();
        Vec3.sub(normal, particle[1].position, particle[0].position);
        contact.contactNormal = normal;
        contact.penetration = curLen - maxLength;
        contact.restitution = this.restitution;
        return 1;
    }
});


function RodLink(length) {
    "use strict";
    this.length = length;

}
RodLink.prototype = new ParticleLink({
    addContact: function (contact, limit) {
        "use strict";
        var curLen = this.currentLength();
        var length = this.length;
        if (curLen <= length) return 0;
        contact.particles[0] = this.particles[0];
        contact.particles[1] = this.particles[1];
        var normal = Vec3.create();
        Vec3.sub(normal, particle[1].position, particle[0].position);
        if (curLen > length) {
            contact.contactNormal = normal;
            contact.penetration = curLen - length;
        } else {
            Vec3.scale(contact.contactNormal, normal, -1);
            contact.penetration = length - curLen;
        }
        contact.restitution = 0;
        return 1;
    }
});


function ContactResolver(positionIterations, velocityIterations) {
    "use strict";
    this.positionIterations = 0;
    this.velocityIterations = 0;
    this.positionEpsilon = 0;
    this.velocityEpsilon = 0;
    this.velocityIterationsUsed = 0;
    this.positionIterationsUsed = 0;
    this.validSetting = false;
}
ContactResolver.prototype = {
    isValid: function () {
        "use strict";
        return (this.velocityIterations > 0 && this.positionIterations > 0 && this.positionEpsilon >= 0 && this.positionEpsilon >= 0);
    },
    setIterations: function (velIter, posIter) {
        "use strict";
        this.positionIterations = posIter;
        this.velocityIterations = velIter;
    },
    setEpsilon: function (velo, posi) {
        "use strict";
        this.velocityEpsilon = velo;
        this.positionEpsilon = posi;
    },
    resolveContacts: function (contacts, numContacts, duration) {
        if (numContacts == 0) return;
        if (!this.isValid()) return;
        this.prepareContacts(contacts, numContacts, duration);
        this.adjustPositions(contacts, numContacts, duration);
        this.adjustVelocities(contacts, numContacts, duration);
        console.log("contact resolver resolveContacts finished for duration = " + duration);
    },
    prepareContacts: function (contacts, numContacts, duration) {
        "use strict";
        this.contacts.forEach(function (contact) {
            contact.calulateInternals(duration);
        });
    },
    adjustVelocities: function (c, numContacts, duration) {
        "use strict";
        var velocityChange = [Vec3.create(), Vec3.create()];
        var rotationChange = [Vec3.create(), Vec3.create()];
        var deltaVel = Vec3.create();
        var index = numContacts;
        this.velocityIterationsUsed = 0;
        while (this.velocityIterationsUsed < this.velocityIterations) {
            var max = this.velocityEpsilon;
            for (var i = 0; i < numContacts; i++) {
                if (c[i].desiredDeltaVelocity > max) {
                    max = c[i].desiredDeltaVelocity;
                    index = i;
                }
            }
            if (index == numContacts) break;
            c[index].matchAwakeState();
            c[index].applyVelocityChange(velocityChange, rotationChange);
            for (var i = 0; i < numContacts; i++) {
                for (var b = 0; b < 2; b++) if (c[i].body[b]) {
                    for (var d = 0; d < 2; d++) {
                        if (c[i].body[b] == c[index].body[d]) {
                            Vec3.add(deltaVel, velocityChange[d], Vec3.cross(rotationChange[d], c[i].relativeContactPosition[b]));
                            Vec3.addScaledVector(c[i].contactVelocity, Mat34.transformTranspose(c[i].contactToWorld, deltaVel), b ? -1 : 1);
                        }
                    }
                }
            }
        }
        this.velocityIterationsUsed++;
    },
    adjustPositions: function (c, numContacts, duration) {
        "use strict";
        var i, index;
        var linearChange = [Vec3.create(), Vec3.create()];
        var angularChange = [Vec3.create(), Vec3.create()];
        var max;
        var deltaPosition = Vec3.create();
        this.positionIterationsUsed = 0;
        while (this.positionIterationsUsed < this.positionIterations) {
            max = this.positionEpsilon;
            index = numContacts;
            for (i = 0; i < numContacts; i++) {
                if (c[i].penetration > max) {
                    max = c[i].penetration;
                    index = i;
                }
            }
            if (index == numContacts) break;
            c[index].matchAwakeState();
            c[index].applyPositionChange(
                linearChange,
                angularChange,
                max
            );
            for (var i = 0; i < numContacts; i++) {
                for (var b = 0; b < 2; b++) if (c[i].body[b]) {
                    for (var d = 0; d < 2; d++) {
                        if (c[i].body[b] == c[index].body[d]) {
                            Vec3.add(deltaPosition, linearChange[d], Vec3.mul(angularChange[d], c[i].relativeContactPosition[b]));
                            c[i].penetration += Vec3.dot(deltaPosition, c[i].contactNormal) * b ? 1 : -1;
                        }
                    }
                }
            }
        }
    }
};


function ParticleContactResolver(iterations) {
    this.iterations = iterations;
    this.iterationsUsed = 0;
}
ParticleContactResolver.prototype = {
    __proto__: new ContactResolver(),
    resolveContacts: function (contactArray, numContacts, duration) {
        this.iterationsUsed = 0;
        while (this.iterationsUsed < this.iterations) {
            var max = 0;
    

Offline Beschaeftigungen

root (Edward Gerhold)

<canvas id="canvas3dcube4" width="600" height="600">
</canvas>
<select id="getMesh">
<option value="cube">Cube</option>
</select>
<label>Animate<input type="checkbox" id="doAnimate" checked></label>
<script src="/scripts/gl-matrix-min.guide.js"></script>
<script src="/scripts/webgl_beginners_guide.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
varying vec2 vTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat4 uNMatrix;
uniform vec4 uMaterialSpecular;
uniform vec4 uMaterialDiffuse;
uniform vec4 uMaterialAmbient;
uniform vec3 uLightPos[2];
varying vec4 vColor;
varying vec3 vNormal[2];
varying vec3 vL[2];
varying vec3 vEye;
varying vec4 vLight;
varying vec4 vertex;
uniform float uPointSize;
varying float v_dist;
void main() {
vertex = uMVMatrix * vec4(aVertexPosition, 1.0);
for (int i = 0; i < 2; i++) {
vNormal[i] = vec3(uNMatrix * vec4(aVertexNormal, 0.0));
vEye = (vertex.xyz/vertex.w);
vL[i] = uLightPos[i] - vEye;
vColor = aVertexColor;
}
vTextureCoord = aTextureCoord;
v_dist = distance(vertex.xyz, vEye.xyz);
gl_Position = uPMatrix * vertex;
// gl_PointSize = uPointSize;
}

</script>
<script id="shader-fs" type="x-shader/x-fragment">
precision highp float;
uniform sampler2D uSampler;
uniform vec4 uLightColor[2];
uniform float uShininess;
varying vec3 vNormal[2];
varying vec4 vColor;
varying vec3 vL[2];
varying vec3 vEye;
varying vec4 vertex;
uniform vec4 uMaterialSpecular;
uniform vec4 uMaterialDiffuse;
uniform vec4 uMaterialAmbient;
varying float v_dist;
vec4 Ia, Id, Is;
float cutOff = 0.4;
vec4 fogColor = vec4(0.1,0.1,0.1,1.0);
vec2 fogDist = vec2(100, -15);
varying vec2 vTextureCoord;
void main() {
vec4 finalColor = vColor;
vec4 lc[2];
lc[0] = vec4(0,0,0,1);
lc[1] = vec4(0,0,0,1);
float fogFactor = clamp((fogDist.y - v_dist) / (fogDist.y - fogDist.x), 0., 1.);
for (int i = 0; i < 2; i++) {
Ia = uMaterialAmbient * uLightColor[i];
vec3 N = normalize(vNormal[i]);
vec3 L = normalize(vL[i]);
float lambert = max(dot(-L, N), 0.0);
if (lambert > 0.0) { // && lambert >= cutOff){
Id = uMaterialDiffuse * uLightColor[i] * lambert;
vec3 R = normalize(reflect(N, L));
vec3 E = normalize(vEye);
float specular = clamp(pow(max(dot(R,E),0.0), uShininess),0.,1.);
if (specular > 0.0 && specular >= cutOff*1.5) {
Is = uMaterialSpecular * uLightColor[i] * specular;
lc[i] *= (Ia + Is + Id);
} else {
lc[i] *= (Ia + Id);
}
}
finalColor += lc[i];
}
finalColor.a = 1.0;
finalColor = finalColor * texture2D(uSampler, vTextureCoord);
gl_FragColor = mix(fogColor, finalColor, fogFactor);
}

</script>
<script>
(function () {


canvas = document.getElementById("canvas3dcube4");
var cube, interactor, transforms, lights, attributeList, uniformList, orbitingCam, wall, sphere, cone, object;
var i = 0;
var doAnimate = true;
var selectedMesh = "cube";
var obj;
var lastTime = Date.now(), currentTime, rate = 1000 / 30;
var app = null;


function configure() {

document.getElementById("getMesh").addEventListener("change", function (e) {
var options = this.querySelectorAll("option");
for (var i = 0, j = options.length; i < j; i++) {
if (options[i].checked) {
selectedMesh = options[i].value;
obj = Scene.getObject(selectedMesh);
}
}
});
document.getElementById("doAnimate").addEventListener("change", function (e) {
doAnimate = this.checked;
if (doAnimate) requestAnimationFrame(render);
});
gl.clearColor(0, 0, 0, 1);
gl.clearDepth(1.0);
gl.enable(gl.DEPTH_TEST);
Lights.add(new Light("left"));
Lights.add(new Light("right"));
Lights.list[0].setPosition([150, 0, 50]);
Lights.list[1].setPosition([-150, 0, -50]);
Lights.list[0].setProperty("color", [0.9, 0.9, 0.9, 1.0]);
Lights.list[1].setProperty("color", [0.5, 0.5, 0.5, 1.0]);
texture = new Texture("js.jpg");
attributeList = [
"aVertexPosition",
"aVertexNormal",
"aVertexColor",
"aTextureCoord"
];
uniformList = [
"uShininess",
"uMVMatrix",
"uPMatrix",
"uNMatrix",
"uLightPos",
"uLightColor",
"uMaterialDiffuse",
"uMaterialAmbient",
"uMaterialSpecular",
"uPointSize",
"uSampler"
];
orbitingCam = new Camera(CAMERA_ORBITING_TYPE);
orbitingCam.goHome([0, 0, 100]);
interactor = new CameraInteractor(orbitingCam, canvas);
transforms = new SceneTransforms(orbitingCam);
Program.load(attributeList, uniformList);
orbitingCam.hookRenderer = render;
transforms.init();
var objTransform = transforms.mvMatrix;
mat4.scale(objTransform, [15, 15, 15])
gl.uniform3fv(Program.uLightPos, Lights.getArray("position"));
gl.uniform4fv(Program.uLightColor, Lights.getArray("color"));
gl.uniform1f(Program.uShininess, 10);
gl.uniform4fv(Program.uMaterialAmbient, [0.1, 0.1, 0.1, 1.0]);
gl.uniform4fv(Program.uMaterialDiffuse, [0.5, 0.5, 0.5, 1.0]);
gl.uniform4fv(Program.uMaterialSpecular, [0.9, 0.9, 0.9, 1.0]);
}

function rand() {
return (Math.random() * 10) / 10;
}

function load() {
Scene.loadObject("/scripts/geometry/complexCube.json", "cube", {
update: function (deltaT) {
var objTransform = transforms.mvMatrix;
mat4.scale(objTransform, [2, 2, 2])
mat4.rotateY(objTransform, Math.PI / 180 * i);
mat4.rotateZ(objTransform, Math.PI / 180 * i);
if (i >= 360) i = 0;
i = i + deltaT / 1000 * rate;
transforms.setMatrixUniforms();
},
draw: function () {
var obj = this;
gl.bindBuffer(gl.ARRAY_BUFFER, obj.cbo);
gl.vertexAttribPointer(Program.aVertexColor, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(Program.aVertexColor);
gl.bindBuffer(gl.ARRAY_BUFFER, obj.vbo);
gl.vertexAttribPointer(Program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(Program.aVertexPosition);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture.tex);
gl.uniform1i(Program.uSampler, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, obj.tbo);
gl.vertexAttribPointer(Program.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(Program.aTextureCoord);
gl.bindBuffer(gl.ARRAY_BUFFER, obj.nbo);
gl.vertexAttribPointer(Program.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(Program.aVertexNormal);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.ibo);
gl.drawElements(gl.TRIANGLE_STRIP, obj.indices.length, gl.UNSIGNED_SHORT, 0);
}
});
}

function draw() {
gl.viewport(0, 0, c_width, c_height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
obj.draw();
}

function updateAnimations(obj, deltaT) {
transforms.push();
transforms.updatePerspective();
obj.update(deltaT);
transforms.pop();
}

function render() {
obj = Scene.getObject(selectedMesh);
currentTime = Date.now();
var deltaT = currentTime - lastTime;
updateAnimations(obj, deltaT);
if (deltaT >= rate) {
if (doAnimate) requestAnimationFrame(draw);
lastTime = currentTime;
}
}

function runWebGLApp() {
app = new WebGLApp("canvas3dcube4");
app.configureGLHook = configure;
app.loadSceneHook = load;
app.drawSceneHook = render;
app.run();
}

window.addEventListener("load", runWebGLApp);

}());
</script>

Circle Collision

root (Edward Gerhold)

<div id="crash"></div>
<canvas width=500 height=500 id="x"></canvas>
<style>
canvas {
background:beige;
}
</style>
<script>
function Sprite(name, painter, behaviors) {
this.name = name;
this.painter = painter;
this.top = 0;
this.left = 0;
this.radius = 0;
this.width = 10;
this.height = 10;
this.velocityX = 0;
this.velocityY = 0;
this.velocityZ = 0;
this.visible = true;
this.animating = false;
this.behaviors = behaviors || [];
this.fillStyle = "green";
this.strokeStyle = "darkgreen";
if (!Array.isArray(this.behaviors)) throw new TypeError("Sprite argument 3 expects Array or undefined");
return this;
}
Sprite.prototype = {
paint: function (context) {
if (this.painter && this.visible) {
this.painter.paint(this, context);
}
},
update: function (context, time) {
for (var i = 0; i < this.behaviors.length; i++) {
this.behaviors[i].execute(this, context, time);
}
},
circlesCollide: function (sprite) {
var vecx = sprite.left - this.left;
var vecy = sprite.top - this.top;
var distance = Math.sqrt(vecx * vecx + vecy * vecy);
var minDistance = this.radius + sprite.radius;
return (distance <= minDistance);
}
};
var ballPainter = {
paint: function (sprite, context) {
context.save();
context.beginPath();
context.fillStyle = sprite.fillStyle;
context.strokeStyle = sprite.strokeStyle;
context.arc(sprite.left, sprite.top, sprite.radius, 0, Math.PI*2, true);
context.fill();
context.stroke();
context.restore();
}
};
var ballMove = {
execute: function (sprite, context, time) {
var deltaX = sprite.velocityX * (time/1000);
var deltaY = sprite.velocityY * (time/1000);
if ((sprite.left + sprite.radius + deltaX > context.canvas.width) ||
(sprite.left + sprite.radius + deltaX < 0)) {
sprite.velocityX = -sprite.velocityX;
deltaX = -deltaX;
}
if ((sprite.top + sprite.radius + deltaY > context.canvas.height) ||
(sprite.top + sprite.radius + deltaY < 0)) {
sprite.velocityY = -sprite.velocityY;
deltaY = -deltaY;
}
sprite.left += deltaX;
sprite.top += deltaY;
}
};
</script>
<script>
window.addEventListener("load", function () {

var canvas = document.getElementById("x");
var context = canvas.getContext("2d");


var ball1 = new Sprite("ball1", ballPainter, [ballMove]);
ball1.top = 0;
ball1.left = 0;
ball1.velocityX = 60;
ball1.velocityY = 60;
ball1.radius = 15;
ball1.fillStyle = "red";
ball1.strokeStyle = "brown";

var ball2 = new Sprite("ball2", ballPainter, [ballMove]);
ball2.top = context.canvas.height-100;
ball2.left = context.canvas.width-100;
ball2.velocityX = 100;
ball2.velocityY = 100;
ball2.radius = 15;
ball2.fillStyle = "yellow";
ball2.strokeStyle = "white";

var collisions = 0;
var frameRate = 1000/60;
var currentTime, lastTime = Date.now(), elapsed;

function anim() {
currentTime = Date.now();
elapsed = currentTime - lastTime;

if (ball1.circlesCollide(ball2)) {
++collisions;
document.getElementById("crash").innerHTML = "ball1 and ball2 collided "+collisions+" times";
ball1.velocityX = -ball1.velocityX;
ball1.velocityY = -ball1.velocityY;
ball2.velocityX = -ball2.velocityX;
ball2.velocityY = -ball2.velocityY;
}
ball1.update(context, elapsed);
ball2.update(context, elapsed);
if (elapsed >= frameRate) {
context.clearRect(0,0,context.canvas.width, context.canvas.height);
ball1.paint(context);
ball2.paint(context);
lastTime = currentTime;
}
requestAnimationFrame(anim);
}
setTimeout(anim, 0);
}, false);
</script>

2D Buch ist gut

root (Edward Gerhold)

<style>
canvas {
background:beige;
color:black;
width:50%;
height:auto;
border-radius: 3em;
box-shadow: 1em 1em black;
}
</style>
<h1>Core HTML5 Canvas</h1>
<p>Is a great and invaluable book.</p>

<canvas id="canvas2d" width=500 height=500>
No Canvas supported.
</canvas>

<br style=clear:both;>
<button id="animateButton">Pause</button>
<!-- <script src="/scripts/stopwatch.js"></script> -->
<script>
function run() {
var canvas = document.getElementById("canvas2d"),
context = canvas.getContext("2d"),
paused = false,
discs = [
{
x: 100,
y: 100,
lastX: 90,
lastY: 90,
velocityX: 10,
velocityY: 2,
radius: 15,
innerColor: "rgba(1,31,1,1)",
outerColor: "rgba(24,24,234, 0)",
middleColor: "rgba(1,31,42,1)",
strokeStyle: "black"

},
{
x: 10,
y: 10,
lastX: 90,
lastY: 43,
velocityX: 3,
velocityY: 23,
radius: 7,
innerColor: "rgba(12,31,41,1)",
outerColor: "rgba(24,24,234, 0)",
middleColor: "rgba(1,231,142,1)",
strokeStyle: "black"

},
{
x: 80,
y: 80,
lastX: 90,
lastY: 90,
velocityX: 3,
velocityY: 2,
radius: 19,
innerColor: "rgba(1,31,1,1)",
outerColor: "rgba(24,124,234, 0)",
middleColor: "rgba(141,31,242,1)",
strokeStyle: "black"

}

],
numDiscs = discs.length,
animateButton = document.getElementById("animateButton");
function drawBackground() {

}


function update() {
var disc = null;
for (var i = 0, j = discs.length; i < j; i++) {

disc = discs[i];
if ((disc.x + disc.velocityX + disc.radius >
context.canvas.width) ||(disc.x + disc.velocityX + disc.radius < 0)) {
disc.velocityX = -disc.velocityX;
}

if ((disc.y + disc.velocityY + disc.radius >
context.canvas.height) ||(disc.y + disc.velocityY + disc.radius < 0)) {
disc.velocityY = -disc.velocityY;
}

disc.x += disc.velocityX;
disc.y += disc.velocityY;
}
}
function draw() {
var disc;
for (var i = 0, j = discs.length; i < j; i++) {
disc = discs[i];
gradient = context.createRadialGradient(disc.x, disc.y, 0, disc.x, disc.y, disc.radius);
gradient.addColorStop(0.3, disc.innerColor);
gradient.addColorStop(0.5, disc.middleColor);
gradient.addColorStop(0.8, disc.outerColor);
context.save();
context.beginPath();
context.arc(disc.x, disc.y, disc.radius, 0, Math.PI*2, false);
context.fillStyle = gradient;
context.strokeStyle = disc.strokeStyle;
context.fill();
context.stroke();
context.closePath();
context.restore();

}
}

function animate() {
if (!paused) {
context.clearRect(0,0, canvas.width, canvas.height);
drawBackground();
update();
draw();
requestAnimationFrame(animate);
}
}
animateButton.onclick = function (e) {
paused = !paused;
if (paused) {
animateButton.value = "Animate";
} else {
requestAnimationFrame(animate);
animateButton.value = "Pause";
}
};
context.font = "48px Helvetica";

animate();
}

window.addEventListener("load", run, false);
</script>

Core HTML5 Canvas

Is a great and invaluable book.

No Canvas supported.

Modem war weg

root (Edward Gerhold)

Habe die nächsten sechs Wochen einen Eurojob und mache unter anderem eine Radiosendung.

Letzte Woche ist meine Brieftasche verloren gegangen oder entwendet worden. Ich hatte noch vor Ort Anzeige erstattet. Im Portemonnaie war mein Modem. Darum bin ich erstmal offline. Mittlerweile, seit gestern, habe ich meine Brieftasche zurück. Ich konnte sie mir in einem Kaufland einen Kilometer vom Ort des Verlusts entfernt abholen. Mit allem Inhalt, ausser meinem Sozi-Ticket, welches ich gottseidank vom Jobcenter schon am Folgetag ersetzt bekam, da man ohne Fahrkarte nicht durch den Berliner Verkehr kommt. Die SIM Karte hatte ich vorsorglich sperren lassen, das muß ich noch wieder rückgängig machen. Jetzt bin ich gerade auf der Arbeit und dachte mir, komm, einen Beitrag kannste dir kurz posten.

Komme bald wieder.

ES6 Draft 27

root (Edward Gerhold)

http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts

August 24, 2014 Draft Rev 27

doc 
pdf, no change markup pdf with rev27 change markup pdf with cumulative change markup since rev22
Changes marked as “Rev 27“. 

Changes include:

  • Fixed scoping bug in for-of, catch clause, comprehensions WRT TDZ for iteration bindings. see bug:https://bugs.ecmascript.org/show_bug.cgi?id=3011
  • For-in/for-of loop bodies can’t contain tail calls because of need to close the iterator on abrupt completion.
  • [[OwnPropertyKeys]] now returns a List rather than an Array
  • Tests of @@isRegExp are now based on ToBoolean(Get(obj, @@isRegExp)
  • Array find/findIndex no longer ignore array element holes.
  • Added %IteratorPrototype% that all built-in iterators inherit from.
  • Destructoring now performs ToObject on values to be destructured.
  • Array and generator comprehensions removed from language
  • Removed specification of Reflect.Realm
  • Object.assign ignores null and undefined source arguments
  • Added 16.1 that lists forbidden extensions.
  • Some editorial cleanup of Function.prototype.toString
  • Removed all explicit poison pill methods on functions (except for Function.prototype) and added 16.1 restrictions on such extensions.
  • String(aSymbol) now returns the symbol’s description. Does not change ToString(symbol) throwing ever where else.
  • aSymbol == Object(aSymbol) now is true, just like other wrapable primitives, see bug:https://bugs.ecmascript.org/show_bug.cgi?id=3066
  • Tighten specification of when Array.prototype.sort is implementation defined
  • Revised @@unscopable semantics as per last TC39 meeting
  • Made it an error to reentrantly enter a generator via next/throw/return.
  • Further work on semantics of Generator return method in the context of yield*
  • The term “neutered” has been replaced with the term “detached”
  • Resolved bugs: 3147, 3142-3140, 3135-3133, 3131, 3128-3124, 3122-3120, 3117, 3115, 3111-3107, 3105, 3103-3098, 3096-3095, 3093-3092, 3090-3089, 3087-3082, 3080-3062, 3060-3016, 3012-3011, 3005, 2987, 2979, 2976, 2831, 2389, 2368, 1908, 523, 516, 513, 407, 91

Previous

Extending Pro PHP MVC

root (Edward Gerhold)

Class Diagram generated by phpStorm
Das mit PHPStorm vor einigen Tagen generierte Klassendiagram.
Class Diagram handdrawn with ArgoUML
Mit ArgoUML vorher  handgemalt, noch voller Fehler.