diff --git a/Gruntfile.js b/Gruntfile.js index 03399b29d3..eb28ec39f3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -157,6 +157,7 @@ module.exports = function(grunt) { browserify: { p5: { options: { + transform: ['brfs'], browserifyOptions: { standalone: 'p5' }, diff --git a/examples/3d/center_origin/index.html b/examples/3d/center_origin/index.html new file mode 100644 index 0000000000..92e08b1696 --- /dev/null +++ b/examples/3d/center_origin/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + +

[0, 0, 0] is in the center of the screen by default

+ + + + diff --git a/examples/3d/center_origin/sketch.js b/examples/3d/center_origin/sketch.js new file mode 100644 index 0000000000..d88e202574 --- /dev/null +++ b/examples/3d/center_origin/sketch.js @@ -0,0 +1,29 @@ +function setup(){ + createCanvas(windowWidth, windowHeight, 'webgl'); +} + +function draw(){ + + background(255); + + translate(0, 0, -800); + rotateY(frameCount * 0.01); + + var gap = 200; + var w = 100; + var h = 100; + + for(var i = -2; i < 3; i++){ + for(var j = -2; j < 3; j++){ + fill( (i+2) * 40, (j+2) * 40, 0); + quad( + i * gap, j * gap, 0, + i * gap + w, j * gap, 0, + i * gap, j * gap + h, 0, + i * gap + w, j * gap + h/2 * (sin(frameCount * 0.1 + i + j) + 1), 0 + ); + } + } + + +} \ No newline at end of file diff --git a/examples/3d/geometry/sketch.js b/examples/3d/geometry/sketch.js index e139eb64da..7807337f3a 100644 --- a/examples/3d/geometry/sketch.js +++ b/examples/3d/geometry/sketch.js @@ -7,47 +7,48 @@ var theta = 0; function draw(){ background(255, 255, 255, 255); - translate(-120, 0, -170); + translate(-width/2, 0, -800); + normalMaterial(); push(); rotateZ(theta * mouseX * 0.001); rotateX(theta * mouseX * 0.001); rotateY(theta * mouseX * 0.001); - plane(100, 100); + plane(80, 80); pop(); - translate(50, 0, 0); + translate(250, 0, 0); push(); rotateZ(theta * mouseX * 0.001); rotateX(theta * mouseX * 0.001); rotateY(theta * mouseX * 0.001); - box(100, 100, 100); + box(80, 80, 80); pop(); - translate(50, 0, 0); + translate(250, 0, 0); push(); rotateZ(theta * mouseX * 0.001); rotateX(theta * mouseX * 0.001); rotateY(theta * mouseX * 0.001); - cylinder(100, 100); + cylinder(80, 80); pop(); - translate(50, 0, 0); + translate(250, 0, 0); push(); rotateZ(theta * mouseX * 0.001); rotateX(theta * mouseX * 0.001); rotateY(theta * mouseX * 0.001); - cone(100, 100); + cone(80, 80); pop(); - translate(50, 0, 0); + translate(250, 0, 0); push(); rotateZ(theta * mouseX * 0.001); rotateX(theta * mouseX * 0.001); rotateY(theta * mouseX * 0.001); - torus(100, 20); + torus(80, 20); pop(); - translate(50, 0, 0); + translate(250, 0, 0); push(); rotateZ(theta * mouseX * 0.001); rotateX(theta * mouseX * 0.001); rotateY(theta * mouseX * 0.001); - sphere(100, 100); + sphere(80, 80); pop(); theta += 0.05; } \ No newline at end of file diff --git a/examples/3d/light/index.html b/examples/3d/immediateMode/index.html similarity index 100% rename from examples/3d/light/index.html rename to examples/3d/immediateMode/index.html diff --git a/examples/3d/immediateMode/sketch.js b/examples/3d/immediateMode/sketch.js new file mode 100644 index 0000000000..f9844523db --- /dev/null +++ b/examples/3d/immediateMode/sketch.js @@ -0,0 +1,58 @@ +var theta = 0; + +function setup(){ + createCanvas(windowWidth, windowHeight, 'webgl'); +} + +function draw(){ + + background('white'); + colorMode(HSB); + + translate(0, 0, -1000); + + rotateY(frameCount * 0.01); + + //point + stroke(0, 200, 200); + point(0, 0, 0); + + //lines + translate(100, 0, 0); + push(); + rotateX(frameCount * 0.01); + for(var i = 0 ; i < 12; i++){ + var offset = i * PI / 6; + fill(i * 20, 100, 100); + line(0, 0, 0, 200 * sin(offset + frameCount*0.01), 200 * cos(offset + frameCount*0.01), 0); + } + pop(); + + + //triangles + translate(400, 0, 0); + push(); + for(var i = 0; i < 3; i++){ + fill(i * 30 + 200, 100, 100); + translate(100, 50, 0); + triangle( + 100, 0, 0, + 60 * sin(frameCount * 0.1 + i), 0, 0, + 0, 100, 0); + } + pop(); + + + //triangle strip + translate(200, 0, 0); + for(var i = 0; i < 30; i++){ + fill(i * 10, 120, 120); + translate(100, -50, 0); + beginShape('TRIANGLE_STRIP') + vertex(0, 0, (cos(frameCount * 0.1 + i) + 1) * 100); + vertex(0, 200, 100); + vertex(100, 100, 100); + vertex(100, 0, (sin(frameCount * 0.1 + i) + 1) * 100); + endShape(); + } +} \ No newline at end of file diff --git a/examples/3d/interaction/index.html b/examples/3d/interaction/index.html index 24ec82a07c..49e0c98ad6 100644 --- a/examples/3d/interaction/index.html +++ b/examples/3d/interaction/index.html @@ -12,10 +12,10 @@ -

Press Mouse To Toggle The World

+

Press Mouse To Toggle The World

- \ No newline at end of file + diff --git a/examples/3d/interaction/sketch.js b/examples/3d/interaction/sketch.js index 2f0c3bfa8c..16fbc18884 100644 --- a/examples/3d/interaction/sketch.js +++ b/examples/3d/interaction/sketch.js @@ -4,22 +4,27 @@ function setup(){ function draw(){ background(250, 250, 250, 255); - var radius = width / 6; - translate(-10, 0, -200); + var radius = width; + translate(0, 0, -1600); orbitControl(); if(!mouseIsPressed){ rotateY(frameCount * 0.001); } + normalMaterial(); for(var i = 0; i <= 20; i++){ for(var j = 0; j <= 20; j++){ push(); var a = j/20 * PI; var b = i/20 * PI - translate(sin(2 * a) * radius * sin(b), cos(b) * 50 , cos(2 * a) * radius * sin(b)); - if(j % 2 === 0) box(60, 60, 60); - else cone(60, 60); + translate(sin(2 * a) * radius * sin(b), cos(b) * radius / 2 , cos(2 * a) * radius * sin(b)); + if(j % 2 === 0) { + box(60, 60, 60); + } + else{ + cone(60, 60); + } pop(); } } diff --git a/examples/3d/material/index.html b/examples/3d/material/index.html new file mode 100644 index 0000000000..201710dc81 --- /dev/null +++ b/examples/3d/material/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/3d/light/sketch.js b/examples/3d/material/sketch.js similarity index 77% rename from examples/3d/light/sketch.js rename to examples/3d/material/sketch.js index 498251ca7f..455ca1ebd5 100644 --- a/examples/3d/light/sketch.js +++ b/examples/3d/material/sketch.js @@ -6,33 +6,34 @@ function setup(){ function draw(){ background(250, 250, 250, 255); - - translate(-10, 0, -100); // directionalLight(153, 153, 153, .5, 0, -1); // ambientLight(153, 102, 0); // ambient(51, 26, 0); + translate(-100, 0, -1000); push(); rotateX(theta * 0.1); rotateZ(theta); rotateY(theta * 0.1); + normalMaterial(); box(60, 60, 60); pop(); - translate(30, 0, 0); - basicMaterial(); + translate(300, 0, 0); push(); rotateX(-theta * 0.1); rotateZ(-theta); rotateY(-theta * 0.1); + normalMaterial(); sphere(60); - translate(30, 0, 0); + translate(300, 0, 0); + basicMaterial(0, 255, 0); box(60,60,60); pop(); - translate(30, 0, 0); - normalMaterial(); + translate(300, 0, 0); push(); rotateX(theta * 0.1); rotateZ(theta); rotateY(theta * 0.1); + basicMaterial(250, 0, 200); plane(60, 60); pop(); theta += 0.03; diff --git a/examples/3d/performance/index.html b/examples/3d/performance/index.html index 201710dc81..9270293780 100644 --- a/examples/3d/performance/index.html +++ b/examples/3d/performance/index.html @@ -11,6 +11,7 @@ html, body {margin:0; padding:0;} +

1000 spheres, how's the speed?

+ + + + +

[0, 0, 0] is in the top left corner now

+ + + + diff --git a/examples/3d/topleft_origin/sketch.js b/examples/3d/topleft_origin/sketch.js new file mode 100644 index 0000000000..09f3e61ef4 --- /dev/null +++ b/examples/3d/topleft_origin/sketch.js @@ -0,0 +1,30 @@ +function setup(){ + createCanvas(windowWidth, windowHeight, 'webgl'); +} + +function draw(){ + + background(255); + + translate( -width/2, -height/2, -600); + + rotateY(frameCount * 0.01); + + var gap = 200; + var w = 100; + var h = 100; + + for(var i = 0; i < 5; i++){ + for(var j = 0; j < 5; j++){ + fill( i * 40, j * 40, 0); + quad( + i * gap, j * gap, 0, + i * gap + w, j * gap, 0, + i * gap, j * gap + h, 0, + i * gap + w, j * gap + h/2 * (sin(frameCount * 0.1 + i + j) + 1), 0 + ); + } + } + + +} \ No newline at end of file diff --git a/package.json b/package.json index 216f2ea3b6..bacb07625e 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ } ], "dependencies": { + "brfs": "^1.4.0", "reqwest": "^1.1.5" }, "main": "./lib/p5.js", diff --git a/src/3d/immediateMode3D.js b/src/3d/immediateMode3D.js new file mode 100644 index 0000000000..74bf9c8cae --- /dev/null +++ b/src/3d/immediateMode3D.js @@ -0,0 +1,176 @@ +//@TODO: documentation of immediate mode + +'use strict'; + +var p5 = require('../core/core'); + +////////////////////////////////////////////// +// Primitives2D in 3D space +////////////////////////////////////////////// + +p5.Renderer3D.prototype.primitives2D = function(arr){ + + var gl = this.GL; + var shaderProgram = this.getColorVertexShader(); + + //create vertice buffer + var vertexPositionBuffer = this.verticeBuffer; + gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer); + + gl.bufferData( + gl.ARRAY_BUFFER, new Float32Array(arr), gl.STATIC_DRAW); + gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, + 3, gl.FLOAT, false, 0, 0); + + //create vertexcolor buffer + var vertexColorBuffer = this.colorBuffer; + gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer); + var color = this.getCurColor(); + var colors = []; + for(var i = 0; i < arr.length / 3; i++){ + colors = colors.concat(color); + } + + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); + gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, + 4, gl.FLOAT, false, 0, 0); + + //matrix + var mId = 'vertexColorVert|vertexColorFrag'; + this.setMatrixUniforms(mId); +}; + +//@TODO: point does not show up, gotta fix it. +p5.Renderer3D.prototype.point = function(x, y, z){ + var gl = this.GL; + this.primitives2D([x, y, z]); + gl.drawArrays(gl.POINTS, 0, 1); + return this; +}; + +p5.Renderer3D.prototype.line = function(x1, y1, z1, x2, y2, z2){ + var gl = this.GL; + this.primitives2D([x1, y1, z1, x2, y2, z2]); + gl.drawArrays(gl.LINES, 0, 2); + return this; +}; + +p5.Renderer3D.prototype.triangle = function +(x1, y1, z1, x2, y2, z2, x3, y3, z3){ + var gl = this.GL; + this.primitives2D([x1, y1, z1, x2, y2, z2, x3, y3, z3]); + this._strokeCheck(); + gl.drawArrays(gl.TRIANGLES, 0, 3); + return this; +}; + +//@TODO: how to define the order of 4 points +p5.Renderer3D.prototype.quad = function +(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4){ + var gl = this.GL; + this.primitives2D( + [x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4]); + this._strokeCheck(); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + return this; +}; + +p5.Renderer3D.prototype.beginShape = function(mode){ + this.modeStack.push(mode); + this.verticeStack = []; + return this; +}; + +p5.Renderer3D.prototype.vertex = function(x, y, z){ + this.verticeStack.push(x, y, z); + return this; +}; + +p5.Renderer3D.prototype.endShape = function(){ + var gl = this.GL; + this.primitives2D(this.verticeStack); + this.verticeStack = []; + var mode = this.modeStack.pop(); + + switch(mode){ + case 'POINTS': + gl.drawArrays(gl.POINTS, 0, 1); + break; + case 'LINES': + gl.drawArrays(gl.LINES, 0, 2); + break; + case 'TRIANGLES': + this._strokeCheck(); + gl.drawArrays(gl.TRIANGLES, 0, 3); + break; + case 'TRIANGLE_STRIP': + this._strokeCheck(); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + break; + default: + this._strokeCheck(); + gl.drawArrays(gl.TRIANGLES, 0, 3); + break; + } + return this; +}; + +//@TODO: figure out how to actually do stroke on shapes in 3D +p5.Renderer3D.prototype._strokeCheck = function(){ + var drawMode = this.drawModeStack[this.drawModeStack.length-1]; + if(drawMode === 'stroke'){ + throw new Error( + 'stroke for shapes in 3D not yet implemented, use fill for now :(' + ); + } +}; + +////////////////////////////////////////////// +// COLOR +////////////////////////////////////////////// + +p5.Renderer3D.prototype.fill = function(r, g, b, a) { + var color = this._pInst.color.apply(this._pInst, arguments); + var colorNormalized = _normalizeColor(color.rgba); + if( colorNormalized !== this.getCurColor()){ + this.colorStack.push(colorNormalized); + } + this.drawModeStack.push('fill'); + return this; +}; + +p5.Renderer3D.prototype.stroke = function(r, g, b, a) { + var color = this._pInst.color.apply(this._pInst, arguments); + var colorNormalized = _normalizeColor(color.rgba); + if( colorNormalized !== this.getCurColor()){ + this.colorStack.push(colorNormalized); + } + this.drawModeStack.push('stroke'); + return this; +}; + +p5.Renderer3D.prototype.getColorVertexShader = function(){ + var gl = this.GL; + var mId = 'vertexColorVert|vertexColorFrag'; + var shaderProgram; + if(!this.materialInHash(mId)){ + shaderProgram = + this.initShaders('vertexColorVert', 'vertexColorFrag', true); + shaderProgram.vertexColorAttribute = + gl.getAttribLocation(shaderProgram, 'aVertexColor'); + gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute); + }else{ + shaderProgram = this.mHash[mId]; + } + return shaderProgram; +}; + +function _normalizeColor(_arr){ + var arr = []; + _arr.forEach(function(val){ + arr.push(val/255); + }); + return arr; +} + +module.exports = p5.Renderer3D; \ No newline at end of file diff --git a/src/3d/interaction.js b/src/3d/interaction.js new file mode 100644 index 0000000000..27f70e8764 --- /dev/null +++ b/src/3d/interaction.js @@ -0,0 +1,14 @@ +'use strict'; + +var p5 = require('../core/core'); + +//@TODO: fix this fake orbitControl +p5.prototype.orbitControl = function(){ + if(this.mouseIsPressed){ + this.rotateX((this.mouseX - this.width / 2) / (this.width / 2)); + this.rotateY((this.mouseY - this.height / 2) / (this.width / 2)); + } + return this; +}; + +module.exports = p5; \ No newline at end of file diff --git a/src/3d/light.js b/src/3d/light.js new file mode 100644 index 0000000000..ce37eba942 --- /dev/null +++ b/src/3d/light.js @@ -0,0 +1,5 @@ +'use strict'; + +var p5 = require('../core/core'); + +module.exports = p5; diff --git a/src/3d/mat4.js b/src/3d/mat4.js deleted file mode 100644 index 61504808ba..0000000000 --- a/src/3d/mat4.js +++ /dev/null @@ -1,785 +0,0 @@ -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - -/** - * @class 4x4 Matrix - * @name mat4 - */ -var GLMAT_EPSILON = 0.000001; -var GLMAT_ARRAY_TYPE = ( - typeof Float32Array !== 'undefined') ? - Float32Array : Array; - -var mat4 = {}; - -/** - * Creates a new identity mat4 - * - * @returns {mat4} a new 4x4 matrix - */ -mat4.create = function () { - var out = new GLMAT_ARRAY_TYPE(16); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -}; - -/** - * Creates a new mat4 initialized with values from an existing matrix - * - * @param {mat4} a matrix to clone - * @returns {mat4} a new 4x4 matrix - */ -mat4.clone = function (a) { - var out = new GLMAT_ARRAY_TYPE(16); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Copy the values from one mat4 to another - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.copy = function (out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Set a mat4 to the identity matrix - * - * @param {mat4} out the receiving matrix - * @returns {mat4} out - */ -mat4.identity = function (out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -}; - -/** - * Transpose the values of a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.transpose = function (out, a) { - - if (out === a) { - var a01 = a[1], - a02 = a[2], - a03 = a[3], - a12 = a[6], - a13 = a[7], - a23 = a[11]; - - out[1] = a[4]; - out[2] = a[8]; - out[3] = a[12]; - out[4] = a01; - out[6] = a[9]; - out[7] = a[13]; - out[8] = a02; - out[9] = a12; - out[11] = a[14]; - out[12] = a03; - out[13] = a13; - out[14] = a23; - } else { - out[0] = a[0]; - out[1] = a[4]; - out[2] = a[8]; - out[3] = a[12]; - out[4] = a[1]; - out[5] = a[5]; - out[6] = a[9]; - out[7] = a[13]; - out[8] = a[2]; - out[9] = a[6]; - out[10] = a[10]; - out[11] = a[14]; - out[12] = a[3]; - out[13] = a[7]; - out[14] = a[11]; - out[15] = a[15]; - } - - return out; -}; - -/** - * Inverts a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.invert = function (out, a) { - var a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11], - a30 = a[12], - a31 = a[13], - a32 = a[14], - a33 = a[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - - // Calculate the determinant - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - - b04 * b07 + b05 * b06; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - - return out; -}; - -/** - * Calculates the adjugate of a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.adjoint = function (out, a) { - var a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11], - a30 = a[12], - a31 = a[13], - a32 = a[14], - a33 = a[15]; - - out[0] = (a11 * (a22 * a33 - a23 * a32) - - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); - out[1] = -(a01 * (a22 * a33 - a23 * a32) - - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); - out[2] = (a01 * (a12 * a33 - a13 * a32) - - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); - out[3] = -(a01 * (a12 * a23 - a13 * a22) - - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); - out[4] = -(a10 * (a22 * a33 - a23 * a32) - - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); - out[5] = (a00 * (a22 * a33 - a23 * a32) - - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); - out[6] = -(a00 * (a12 * a33 - a13 * a32) - - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); - out[7] = (a00 * (a12 * a23 - a13 * a22) - - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); - out[8] = (a10 * (a21 * a33 - a23 * a31) - - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); - out[9] = -(a00 * (a21 * a33 - a23 * a31) - - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); - out[10] = (a00 * (a11 * a33 - a13 * a31) - - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); - out[11] = -(a00 * (a11 * a23 - a13 * a21) - - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); - out[12] = -(a10 * (a21 * a32 - a22 * a31) - - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); - out[13] = (a00 * (a21 * a32 - a22 * a31) - - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); - out[14] = -(a00 * (a11 * a32 - a12 * a31) - - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); - out[15] = (a00 * (a11 * a22 - a12 * a21) - - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); - return out; -}; - -/** - * Multiplies two mat4's - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the first operand - * @param {mat4} b the second operand - * @returns {mat4} out - */ -mat4.multiply = function (out, a, b) { - var a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11], - a30 = a[12], - a31 = a[13], - a32 = a[14], - a33 = a[15]; - - // Cache only the current line of the second matrix - var b0 = b[0], - b1 = b[1], - b2 = b[2], - b3 = b[3]; - out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - - b0 = b[4]; - b1 = b[5]; - b2 = b[6]; - b3 = b[7]; - out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - - b0 = b[8]; - b1 = b[9]; - b2 = b[10]; - b3 = b[11]; - out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - - b0 = b[12]; - b1 = b[13]; - b2 = b[14]; - b3 = b[15]; - out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - return out; -}; - -/** - * Alias for {@link mat4.multiply} - */ -mat4.mul = mat4.multiply; - -/** - * Translate a mat4 by the given vector - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to translate - * @param {vec3} v vector to translate by - * @returns {mat4} out - */ -mat4.translate = function (out, a, v) { - var x = v[0], - y = v[1], - z = v[2], - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23; - - if (a === out) { - out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; - out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; - out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; - out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; - } else { - a00 = a[0]; - a01 = a[1]; - a02 = a[2]; - a03 = a[3]; - a10 = a[4]; - a11 = a[5]; - a12 = a[6]; - a13 = a[7]; - a20 = a[8]; - a21 = a[9]; - a22 = a[10]; - a23 = a[11]; - - out[0] = a00; - out[1] = a01; - out[2] = a02; - out[3] = a03; - out[4] = a10; - out[5] = a11; - out[6] = a12; - out[7] = a13; - out[8] = a20; - out[9] = a21; - out[10] = a22; - out[11] = a23; - - out[12] = a00 * x + a10 * y + a20 * z + a[12]; - out[13] = a01 * x + a11 * y + a21 * z + a[13]; - out[14] = a02 * x + a12 * y + a22 * z + a[14]; - out[15] = a03 * x + a13 * y + a23 * z + a[15]; - } - - return out; -}; - -/** - * Scales the mat4 by the dimensions in the given vec3 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to scale - * @param {vec3} v the vec3 to scale the matrix by - * @returns {mat4} out - **/ -mat4.scale = function (out, a, v) { - var x = v[0], - y = v[1], - z = v[2]; - - out[0] = a[0] * x; - out[1] = a[1] * x; - out[2] = a[2] * x; - out[3] = a[3] * x; - out[4] = a[4] * y; - out[5] = a[5] * y; - out[6] = a[6] * y; - out[7] = a[7] * y; - out[8] = a[8] * z; - out[9] = a[9] * z; - out[10] = a[10] * z; - out[11] = a[11] * z; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Rotates a mat4 by the given angle around the given axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @param {vec3} axis the axis to rotate around - * @returns {mat4} out - */ -mat4.rotate = function (out, a, rad, axis) { - var x = axis[0], - y = axis[1], - z = axis[2], - len = Math.sqrt(x * x + y * y + z * z), - s, c, t, - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23, - b00, b01, b02, - b10, b11, b12, - b20, b21, b22; - - if (Math.abs(len) < GLMAT_EPSILON) { - return null; - } - - len = 1 / len; - x *= len; - y *= len; - z *= len; - - s = Math.sin(rad); - c = Math.cos(rad); - t = 1 - c; - - a00 = a[0]; - a01 = a[1]; - a02 = a[2]; - a03 = a[3]; - a10 = a[4]; - a11 = a[5]; - a12 = a[6]; - a13 = a[7]; - a20 = a[8]; - a21 = a[9]; - a22 = a[10]; - a23 = a[11]; - - // Construct the elements of the rotation matrix - b00 = x * x * t + c; - b01 = y * x * t + z * s; - b02 = z * x * t - y * s; - b10 = x * y * t - z * s; - b11 = y * y * t + c; - b12 = z * y * t + x * s; - b20 = x * z * t + y * s; - b21 = y * z * t - x * s; - b22 = z * z * t + c; - - // Perform rotation-specific matrix multiplication - out[0] = a00 * b00 + a10 * b01 + a20 * b02; - out[1] = a01 * b00 + a11 * b01 + a21 * b02; - out[2] = a02 * b00 + a12 * b01 + a22 * b02; - out[3] = a03 * b00 + a13 * b01 + a23 * b02; - out[4] = a00 * b10 + a10 * b11 + a20 * b12; - out[5] = a01 * b10 + a11 * b11 + a21 * b12; - out[6] = a02 * b10 + a12 * b11 + a22 * b12; - out[7] = a03 * b10 + a13 * b11 + a23 * b12; - out[8] = a00 * b20 + a10 * b21 + a20 * b22; - out[9] = a01 * b20 + a11 * b21 + a21 * b22; - out[10] = a02 * b20 + a12 * b21 + a22 * b22; - out[11] = a03 * b20 + a13 * b21 + a23 * b22; - - if (a !== out) { - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - return out; -}; - -/** - * Rotates a matrix by the given angle around the X axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateX = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11]; - - if (a !== out) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[4] = a10 * c + a20 * s; - out[5] = a11 * c + a21 * s; - out[6] = a12 * c + a22 * s; - out[7] = a13 * c + a23 * s; - out[8] = a20 * c - a10 * s; - out[9] = a21 * c - a11 * s; - out[10] = a22 * c - a12 * s; - out[11] = a23 * c - a13 * s; - return out; -}; - -/** - * Rotates a matrix by the given angle around the Y axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateY = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11]; - - if (a !== out) { - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[0] = a00 * c - a20 * s; - out[1] = a01 * c - a21 * s; - out[2] = a02 * c - a22 * s; - out[3] = a03 * c - a23 * s; - out[8] = a00 * s + a20 * c; - out[9] = a01 * s + a21 * c; - out[10] = a02 * s + a22 * c; - out[11] = a03 * s + a23 * c; - return out; -}; - -/** - * Rotates a matrix by the given angle around the Z axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateZ = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7]; - - if (a !== out) { - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[0] = a00 * c + a10 * s; - out[1] = a01 * c + a11 * s; - out[2] = a02 * c + a12 * s; - out[3] = a03 * c + a13 * s; - out[4] = a10 * c - a00 * s; - out[5] = a11 * c - a01 * s; - out[6] = a12 * c - a02 * s; - out[7] = a13 * c - a03 * s; - return out; -}; - -/** - * Generates a frustum matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {Number} left Left bound of the frustum - * @param {Number} right Right bound of the frustum - * @param {Number} bottom Bottom bound of the frustum - * @param {Number} top Top bound of the frustum - * @param {Number} near Near bound of the frustum - * @param {Number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.frustum = function (out, left, right, bottom, top, near, far) { - var rl = 1 / (right - left), - tb = 1 / (top - bottom), - nf = 1 / (near - far); - out[0] = (near * 2) * rl; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = (near * 2) * tb; - out[6] = 0; - out[7] = 0; - out[8] = (right + left) * rl; - out[9] = (top + bottom) * tb; - out[10] = (far + near) * nf; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[14] = (far * near * 2) * nf; - out[15] = 0; - return out; -}; - -/** - * Generates a perspective projection matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {number} fovy Vertical field of view in radians - * @param {number} aspect Aspect ratio. typically viewport width/height - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.perspective = function (out, fovy, aspect, near, far) { - var f = 1.0 / Math.tan(fovy / 2), - nf = 1 / (near - far); - out[0] = f / aspect; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = f; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = (far + near) * nf; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[14] = (2 * far * near) * nf; - out[15] = 0; - return out; -}; - -/** - * Generates a orthogonal projection matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {number} left Left bound of the frustum - * @param {number} right Right bound of the frustum - * @param {number} bottom Bottom bound of the frustum - * @param {number} top Top bound of the frustum - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.ortho = function (out, left, right, bottom, top, near, far) { - var lr = 1 / (left - right), - bt = 1 / (bottom - top), - nf = 1 / (near - far); - out[0] = -2 * lr; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = -2 * bt; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 2 * nf; - out[11] = 0; - out[12] = (left + right) * lr; - out[13] = (top + bottom) * bt; - out[14] = (far + near) * nf; - out[15] = 1; - return out; -}; - -module.exports = mat4; diff --git a/src/3d/material.js b/src/3d/material.js index e3a4cdb05e..61adefa89c 100644 --- a/src/3d/material.js +++ b/src/3d/material.js @@ -14,7 +14,9 @@ p5.prototype.normalMaterial = function(){ this._graphics.initShaders('normalVert', 'normalFrag'); } - this._graphics.saveShaders(mId); + if(mId !== this._graphics.getCurShaderId()){ + this._graphics.saveShaders(mId); + } return this; @@ -30,29 +32,41 @@ p5.prototype.normalMaterial = function(){ */ p5.prototype.basicMaterial = function(r, g, b, a){ - r = r / 255 || 0.5; - g = g / 255 || r; - b = b / 255 || r; - a = a || 1.0; - var mId = 'normalVert|basicFrag'; + var gl = this._graphics.GL; + var shaderProgram; if(!this._graphics.materialInHash(mId)){ - //@TODO: figure out how to do this - // var sp = this._graphics.initShaders( - // shaders.normalVert, shaders.basicFrag, { - // uMaterialColor: [r, g, b, a] - // }); - // sp.uMaterialColorLoc = gl.getUniformLocation( - // shaderProgram, 'uMaterialColor' ); - // gl.uniform4f( program.uMaterialColorLoc, 1.0, 1.0, 1.0, 1.0 ); - this._graphics.initShaders('normalVert', 'basicFrag'); + shaderProgram = + this._graphics.initShaders('normalVert', 'basicFrag'); + }else{ + shaderProgram = this._graphics.mHash[mId]; } + gl.useProgram(shaderProgram); + shaderProgram.uMaterialColor = gl.getUniformLocation( + shaderProgram, 'uMaterialColor' ); + + var color = this._graphics._pInst.color.apply( + this._graphics._pInst, arguments); + var colors = _normalizeColor(color.rgba); - this._graphics.saveShaders(mId); + gl.uniform4f( shaderProgram.uMaterialColor, + colors[0], colors[1], colors[2], colors[3]); + + if(mId !== this._graphics.getCurShaderId()){ + this._graphics.saveShaders(mId); + } return this; }; -module.exports = p5; \ No newline at end of file +function _normalizeColor(_arr){ + var arr = []; + _arr.forEach(function(val){ + arr.push(val/255); + }); + return arr; +} + +module.exports = p5; diff --git a/src/3d/p5.Geometry3D.js b/src/3d/p5.Geometry3D.js index be50e68035..2b9dafc898 100755 --- a/src/3d/p5.Geometry3D.js +++ b/src/3d/p5.Geometry3D.js @@ -31,6 +31,7 @@ p5.Geometry3D = function(){ * @param {Number} offset offset of vertices index */ p5.Geometry3D.prototype.parametricGeometry = function +//@TODO: put func as the last parameters (func, detailX, detailY, offset){ var i, j, p; diff --git a/src/3d/p5.Matrix.js b/src/3d/p5.Matrix.js index a56b105be6..1af5fc0ad7 100644 --- a/src/3d/p5.Matrix.js +++ b/src/3d/p5.Matrix.js @@ -558,4 +558,50 @@ p5.Matrix.prototype.ortho = function(left,right,bottom,top,near,far){ return this; }; +/** + * PRIVATE + */ +// matrix methods adapted from: +// https://developer.mozilla.org/en-US/docs/Web/WebGL/ +// gluPerspective +// +// function _makePerspective(fovy, aspect, znear, zfar){ +// var ymax = znear * Math.tan(fovy * Math.PI / 360.0); +// var ymin = -ymax; +// var xmin = ymin * aspect; +// var xmax = ymax * aspect; +// return _makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); +// } + +//// +//// glFrustum +//// +//function _makeFrustum(left, right, bottom, top, znear, zfar){ +// var X = 2*znear/(right-left); +// var Y = 2*znear/(top-bottom); +// var A = (right+left)/(right-left); +// var B = (top+bottom)/(top-bottom); +// var C = -(zfar+znear)/(zfar-znear); +// var D = -2*zfar*znear/(zfar-znear); +// var frustrumMatrix =[ +// X, 0, A, 0, +// 0, Y, B, 0, +// 0, 0, C, D, +// 0, 0, -1, 0 +//]; +//return frustrumMatrix; +// } + +// function _setMVPMatrices(){ +////an identity matrix +////@TODO use the p5.Matrix class to abstract away our MV matrices and +///other math +//var _mvMatrix = +//[ +// 1.0,0.0,0.0,0.0, +// 0.0,1.0,0.0,0.0, +// 0.0,0.0,1.0,0.0, +// 0.0,0.0,0.0,1.0 +//]; + module.exports = p5.Matrix; \ No newline at end of file diff --git a/src/3d/p5.Renderer3D.js b/src/3d/p5.Renderer3D.js index 85df1e612d..b2b6d0176e 100755 --- a/src/3d/p5.Renderer3D.js +++ b/src/3d/p5.Renderer3D.js @@ -1,12 +1,12 @@ 'use strict'; var p5 = require('../core/core'); -var shaders = require('./shaders'); +var shader = require('./shader'); require('../core/p5.Renderer'); require('./p5.Matrix'); -var gl; var uMVMatrixStack = []; var shaderStack = []; +var RESOLUTION = 1000; //@TODO should probably implement an override for these attributes var attributes = { @@ -39,7 +39,8 @@ p5.Renderer3D = function(elt, pInst, isMainCanvas) { } this.isP3D = true; //lets us know we're in 3d mode - gl = this.drawingContext; + this.GL = this.drawingContext; + var gl = this.GL; gl.clearColor(1.0, 1.0, 1.0, 1.0); //background is initialized white gl.clearDepth(1); gl.enable(gl.DEPTH_TEST); @@ -47,8 +48,12 @@ p5.Renderer3D = function(elt, pInst, isMainCanvas) { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); //create our default matrices - this.initHash(); this.initMatrix(); + this.initHash(); + this.resetStack(); + //for immedidate mode + this.verticeBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); return this; }; @@ -73,12 +78,13 @@ p5.Renderer3D.prototype._applyDefaults = function() { * @return {[type]} [description] */ p5.Renderer3D.prototype.resize = function(w,h) { - p5.Renderer.prototype.resize.call(this, w,h); + var gl = this.GL; + p5.Renderer.prototype.resize.call(this, w, h); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); }; ////////////////////////////////////////////// -// COLOR | Setting +// BACKGROUND | Setting ////////////////////////////////////////////// /** @@ -86,6 +92,7 @@ p5.Renderer3D.prototype.resize = function(w,h) { * @return {[type]} [description] */ p5.Renderer3D.prototype.background = function() { + var gl = this.GL; var _col = this._pInst.color.apply(this._pInst, arguments); // gl.clearColor(0.0,0.0,0.0,1.0); var _r = (_col.color_array[0]) / 255; @@ -95,16 +102,22 @@ p5.Renderer3D.prototype.background = function() { gl.clearColor(_r, _g, _b, _a); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); this.resetMatrix(); - this.emptyShaderStack(); + this.resetStack(); }; -//@TODO implement this -// p5.Renderer3D.prototype.clear = function() { -//@TODO -// }; +/** + * [originMode description] + * @param {[type]} mode [description] + * @return {[type]} [description] + */ +p5.prototype.originMode = function(mode){ + if(mode === 'TOP_LEFT'){ + this._graphics.translate(-this.width/2, -this.height/2, 0); + } +}; //@TODO implement this -// p5.Renderer3D.prototype.fill = function() { +// p5.Renderer3D.prototype.clear = function() { //@TODO // }; @@ -118,14 +131,15 @@ p5.Renderer3D.prototype.background = function() { * @param {[type]} fragId [description] * @return {[type]} [description] */ -p5.Renderer3D.prototype.initShaders = function(vertId, fragId) { +p5.Renderer3D.prototype.initShaders = function(vertId, fragId, immediateMode) { + var gl = this.GL; //set up our default shaders by: // 1. create the shader, // 2. load the shader source, // 3. compile the shader var _vertShader = gl.createShader(gl.VERTEX_SHADER); //load in our default vertex shader - gl.shaderSource(_vertShader, shaders[vertId]); + gl.shaderSource(_vertShader, shader[vertId]); gl.compileShader(_vertShader); // if our vertex shader failed compilation? if (!gl.getShaderParameter(_vertShader, gl.COMPILE_STATUS)) { @@ -136,7 +150,7 @@ p5.Renderer3D.prototype.initShaders = function(vertId, fragId) { var _fragShader = gl.createShader(gl.FRAGMENT_SHADER); //load in our material frag shader - gl.shaderSource(_fragShader, shaders[fragId]); + gl.shaderSource(_fragShader, shader[fragId]); gl.compileShader(_fragShader); // if our frag shader failed compilation? if (!gl.getShaderParameter(_fragShader, gl.COMPILE_STATUS)) { @@ -155,20 +169,27 @@ p5.Renderer3D.prototype.initShaders = function(vertId, fragId) { gl.useProgram(shaderProgram); //END SHADERS SETUP - // var vertexResolution = - // gl.getUniformLocation(shaderProgram, 'u_resolution'); // @TODO replace 4th argument with far plane once we implement // a view frustrum + shaderProgram.uResolution = + gl.getUniformLocation(shaderProgram, 'uResolution'); + gl.uniform1f(shaderProgram.uResolution, RESOLUTION); //vertex position Attribute shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'position'); gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - //vertex normal Attribute - shaderProgram.vertexNormalAttribute = - gl.getAttribLocation(shaderProgram, 'normal'); - gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute); + if(immediateMode === undefined){ + //vertex normal Attribute + shaderProgram.vertexNormalAttribute = + gl.getAttribLocation(shaderProgram, 'normal'); + gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute); + + //normal Matrix uniform + shaderProgram.uNMatrixUniform = + gl.getUniformLocation(shaderProgram, 'normalMatrix'); + } //projection Matrix uniform shaderProgram.uPMatrixUniform = @@ -177,48 +198,84 @@ p5.Renderer3D.prototype.initShaders = function(vertId, fragId) { shaderProgram.uMVMatrixUniform = gl.getUniformLocation(shaderProgram, 'modelviewMatrix'); - //normal Matrix uniform - shaderProgram.uNMatrixUniform = - gl.getUniformLocation(shaderProgram, 'normalMatrix'); - this.mHash[vertId + '|' + fragId] = shaderProgram; return shaderProgram; }; /** - * [saveShaders description] - * @return {[type]} [description] + * Sets the Matrix Uniforms inside our default shader. + * @param {String} shaderKey key of current shader */ +p5.Renderer3D.prototype.setMatrixUniforms = function(shaderKey) { + var gl = this.GL; + var shaderProgram = this.mHash[shaderKey]; + + gl.useProgram(shaderProgram); + + gl.uniformMatrix4fv( + shaderProgram.uPMatrixUniform, + false, this.uPMatrix.mat4); + + gl.uniformMatrix4fv( + shaderProgram.uMVMatrixUniform, + false, this.uMVMatrix.mat4); + + this.uNMatrix = new p5.Matrix(); + this.uNMatrix.invert(this.uMVMatrix); + this.uNMatrix.transpose(this.uNMatrix); + + gl.uniformMatrix4fv( + shaderProgram.uNMatrixUniform, + false, this.uNMatrix.mat4); +}; + +////////////////////////////////////////////// +// STACK | for shader, vertex, color and mode +////////////////////////////////////////////// + p5.Renderer3D.prototype.saveShaders = function(mId){ shaderStack.push(mId); }; -/** - * [emptyShaderStack description] - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.emptyShaderStack = function(){ - shaderStack = []; +p5.Renderer3D.prototype.getCurColor = function() { + return this.colorStack[this.colorStack.length-1] || [0.5, 0.5, 0.5, 1.0]; }; -/** - * [getCurShader description] - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.getCurShaderKey = function(){ - var key = shaderStack[shaderStack.length - 1]; - if(key === undefined){ - //@TODO: make a default shader - key = 'normalVert|normalFrag'; - this.initShaders('normalVert', 'normalFrag'); - this.saveShaders(key); +p5.Renderer3D.prototype.getCurShaderId = function(){ + var mId = shaderStack[shaderStack.length - 1]; + if(mId === undefined){ + //default shader: basicMaterial + mId = 'normalVert|basicFrag'; + var gl = this.GL; + var shaderProgram = + this.initShaders('normalVert', 'basicFrag'); + shaderProgram.uMaterialColor = gl.getUniformLocation( + shaderProgram, 'uMaterialColor' ); + var colors = this.getCurColor(); + gl.uniform4f( shaderProgram.uMaterialColor, + colors[0], colors[1], colors[2], colors[3]); + this.saveShaders(mId); } - return key; + return mId; +}; + +p5.Renderer3D.prototype.resetStack = function(){ + shaderStack = []; + //holding colors declaration, like [0, 120, 0] + this.colorStack = []; + //holding mode, like TIANGLE or 'LINES' + this.modeStack = []; + //holding 'fill' or 'stroke' + this.drawModeStack = []; + //holding an array of vertex position + this.verticeStack = []; + //holding lights + this.lightStack = []; }; ////////////////////////////////////////////// -// HASH | Stroing geometriy and materil info +// HASH | for material and geometry ////////////////////////////////////////////// /** @@ -248,99 +305,6 @@ p5.Renderer3D.prototype.materialInHash = function(mId){ return this.mHash[mId] !== undefined; }; -////////////////////////////////////////////// -// BUFFER | deal with gl buffer -////////////////////////////////////////////// - -/** - * [initBuffer description] - * @param {String} gId key of the geometry object - * @param {Object} obj an object containing geometry information - */ -p5.Renderer3D.prototype.initBuffer = function(gId, obj) { - - this.gHash[gId] = {}; - this.gHash[gId].len = obj.len; - this.gHash[gId].vertexBuffer = gl.createBuffer(); - this.gHash[gId].normalBuffer = gl.createBuffer(); - this.gHash[gId].indexBuffer = gl.createBuffer(); - - var shaderProgram = this.mHash[this.getCurShaderKey()]; - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].vertexBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, new Float32Array(obj.vertices), gl.STATIC_DRAW); - gl.vertexAttribPointer( - shaderProgram.vertexPositionAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].normalBuffer); - gl.bufferData( - gl.ARRAY_BUFFER, new Float32Array(obj.vertexNormals), gl.STATIC_DRAW); - gl.vertexAttribPointer( - shaderProgram.vertexNormalAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.gHash[gId].indexBuffer); - gl.bufferData - (gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(obj.faces), gl.STATIC_DRAW); -}; - -/** - * [drawBuffer description] - * @param {String} gId key of the geometery object - */ -p5.Renderer3D.prototype.drawBuffer = function(gId) { - - var shaderKey = this.getCurShaderKey(); - var shaderProgram = this.mHash[shaderKey]; - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].vertexBuffer); - gl.vertexAttribPointer( - shaderProgram.vertexPositionAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].normalBuffer); - gl.vertexAttribPointer( - shaderProgram.vertexNormalAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.gHash[gId].indexBuffer); - - this.setMatrixUniforms(shaderKey); - - gl.drawElements( - gl.TRIANGLES, this.gHash[gId].len, - gl.UNSIGNED_SHORT, 0); -}; - -/** - * Sets the Matrix Uniforms inside our default shader. - * @param {String} shaderKey key of current shader - */ -p5.Renderer3D.prototype.setMatrixUniforms = function(shaderKey) { - - var shaderProgram = this.mHash[shaderKey]; - - gl.useProgram(shaderProgram); - - gl.uniformMatrix4fv( - shaderProgram.uPMatrixUniform, - false, this.uPMatrix.mat4); - - gl.uniformMatrix4fv( - shaderProgram.uMVMatrixUniform, - false, this.uMVMatrix.mat4); - - this.uNMatrix = new p5.Matrix(); - this.uNMatrix.invert(this.uMVMatrix); - this.uNMatrix.transpose(this.uNMatrix); - - gl.uniformMatrix4fv( - shaderProgram.uNMatrixUniform, - false, this.uNMatrix.mat4); -}; - ////////////////////////////////////////////// // MATRIX ////////////////////////////////////////////// @@ -377,9 +341,9 @@ p5.Renderer3D.prototype.resetMatrix = function() { */ p5.Renderer3D.prototype.translate = function(x, y, z) { //@TODO: figure out how to fit the resolution - x = x / 100; - y = -y / 100; - z = z / 100; + x = x / RESOLUTION; + y = -y / RESOLUTION; + z = z / RESOLUTION; this.uMVMatrix.translate([x,y,z]); return this; }; @@ -447,63 +411,4 @@ p5.Renderer3D.prototype.pop = function() { this.uMVMatrix = uMVMatrixStack.pop(); }; -/** - * [orbitControl description] - * @return {[type]} [description] - */ -//@TODO: fix this fake orbitControl -p5.prototype.orbitControl = function(){ - if(this.mouseIsPressed){ - this.rotateX((this.mouseX - this.width / 2) / (this.width / 2)); - this.rotateY((this.mouseY - this.height / 2) / (this.width / 2)); - } - return this; -}; - -/** - * PRIVATE - */ -// matrix methods adapted from: -// https://developer.mozilla.org/en-US/docs/Web/WebGL/ -// gluPerspective -// -// function _makePerspective(fovy, aspect, znear, zfar){ -// var ymax = znear * Math.tan(fovy * Math.PI / 360.0); -// var ymin = -ymax; -// var xmin = ymin * aspect; -// var xmax = ymax * aspect; -// return _makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); -// } - -//// -//// glFrustum -//// -//function _makeFrustum(left, right, bottom, top, znear, zfar){ -// var X = 2*znear/(right-left); -// var Y = 2*znear/(top-bottom); -// var A = (right+left)/(right-left); -// var B = (top+bottom)/(top-bottom); -// var C = -(zfar+znear)/(zfar-znear); -// var D = -2*zfar*znear/(zfar-znear); -// var frustrumMatrix =[ -// X, 0, A, 0, -// 0, Y, B, 0, -// 0, 0, C, D, -// 0, 0, -1, 0 -//]; -//return frustrumMatrix; -// } - -// function _setMVPMatrices(){ -////an identity matrix -////@TODO use the p5.Matrix class to abstract away our MV matrices and -///other math -//var _mvMatrix = -//[ -// 1.0,0.0,0.0,0.0, -// 0.0,1.0,0.0,0.0, -// 0.0,0.0,1.0,0.0, -// 0.0,0.0,0.0,1.0 -//]; - module.exports = p5.Renderer3D; \ No newline at end of file diff --git a/src/3d/retainedMode3D.js b/src/3d/retainedMode3D.js new file mode 100644 index 0000000000..7b3473fb9a --- /dev/null +++ b/src/3d/retainedMode3D.js @@ -0,0 +1,80 @@ +//retained mode is used by rendering 3d_primitives + +'use strict'; + +var p5 = require('../core/core'); + +/** + * [createBuffer description] + * @param {[type]} gId [description] + * @param {[type]} obj [description] + * @return {[type]} [description] + */ +p5.Renderer3D.prototype.createBuffer = function(gId, obj) { + var gl = this.GL; + this.gHash[gId] = {}; + this.gHash[gId].len = obj.len; + this.gHash[gId].vertexBuffer = gl.createBuffer(); + this.gHash[gId].normalBuffer = gl.createBuffer(); + this.gHash[gId].indexBuffer = gl.createBuffer(); +}; + +/** + * [initBuffer description] + * @param {String} gId key of the geometry object + * @param {Object} obj an object containing geometry information + */ +p5.Renderer3D.prototype.initBuffer = function(gId, obj) { + var gl = this.GL; + this.createBuffer(gId, obj); + + var shaderProgram = this.mHash[this.getCurShaderId()]; + + gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].vertexBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, new Float32Array(obj.vertices), gl.STATIC_DRAW); + gl.vertexAttribPointer( + shaderProgram.vertexPositionAttribute, + 3, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].normalBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, new Float32Array(obj.vertexNormals), gl.STATIC_DRAW); + gl.vertexAttribPointer( + shaderProgram.vertexNormalAttribute, + 3, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.gHash[gId].indexBuffer); + gl.bufferData + (gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(obj.faces), gl.STATIC_DRAW); +}; + +/** + * [drawBuffer description] + * @param {String} gId key of the geometery object + */ +p5.Renderer3D.prototype.drawBuffer = function(gId) { + var gl = this.GL; + var shaderKey = this.getCurShaderId(); + var shaderProgram = this.mHash[shaderKey]; + + gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].vertexBuffer); + gl.vertexAttribPointer( + shaderProgram.vertexPositionAttribute, + 3, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].normalBuffer); + gl.vertexAttribPointer( + shaderProgram.vertexNormalAttribute, + 3, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.gHash[gId].indexBuffer); + + this.setMatrixUniforms(shaderKey); + + gl.drawElements( + gl.TRIANGLES, this.gHash[gId].len, + gl.UNSIGNED_SHORT, 0); +}; + +module.exports = p5.Renderer3D; \ No newline at end of file diff --git a/src/3d/shader.js b/src/3d/shader.js new file mode 100644 index 0000000000..ccbb5555e1 --- /dev/null +++ b/src/3d/shader.js @@ -0,0 +1,11 @@ +var fs = require('fs'); + +module.exports = { + vertexColorVert: + fs.readFileSync(__dirname +'/shaders/vertexColor.vert', 'utf-8'), + vertexColorFrag: + fs.readFileSync(__dirname +'/shaders/vertexColor.frag', 'utf-8'), + normalVert: fs.readFileSync(__dirname +'/shaders/normal.vert', 'utf-8'), + normalFrag: fs.readFileSync(__dirname +'/shaders/normal.frag', 'utf-8'), + basicFrag: fs.readFileSync(__dirname +'/shaders/basic.frag', 'utf-8') +}; \ No newline at end of file diff --git a/src/3d/shaders.js b/src/3d/shaders.js deleted file mode 100644 index f4b089f5cb..0000000000 --- a/src/3d/shaders.js +++ /dev/null @@ -1,236 +0,0 @@ -/* -Part of the Processing project - http://processing.org - -Copyright (c) 2011-13 Ben Fry and Casey Reas - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License version 2.1 as published by the Free Software Foundation. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General -Public License along with this library; if not, write to the -Free Software Foundation, Inc., 59 Temple Place, Suite 330, -Boston, MA 02111-1307 USA - */ -/** - * @description Default full shaders for our WebGL context - */ -module.exports = { - texLightVert : [ - 'uniform mat4 modelviewMatrix;', - 'uniform mat4 transformMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform mat4 texMatrix;', - - 'uniform int lightCount;', - 'uniform vec4 lightPosition[8];', - 'uniform vec3 lightNormal[8];', - 'uniform vec3 lightAmbient[8];', - 'uniform vec3 lightDiffuse[8];', - 'uniform vec3 lightSpecular[8];', - 'uniform vec3 lightFalloff[8];', - 'uniform vec2 lightSpot[8];', - - 'attribute vec4 position;', - 'attribute vec4 color;', - 'attribute vec3 normal;', - 'attribute vec2 texCoord;', - - 'attribute vec4 ambient;', - 'attribute vec4 specular;', - 'attribute vec4 emissive;', - 'attribute float shininess;', - - 'varying vec4 vertColor;', - 'varying vec4 backVertColor;', - 'varying vec4 vertTexCoord;', - - 'const float zero_float = 0.0;', - 'const float one_float = 1.0;', - 'const vec3 zero_vec3 = vec3(0);', - - 'float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) {', - 'vec3 lpv = lightPos - vertPos;', - 'vec3 dist = vec3(one_float);', - 'dist.z = dot(lpv, lpv);', - 'dist.y = sqrt(dist.z);', - 'return one_float / dot(dist, coeff);', - '}', - - 'float spotFactor(vec3 lightPos,vec3 vertPos,', - 'vec3 lightNorm,float minCos,float spotExp) {', - 'vec3 lpv = normalize(lightPos - vertPos);', - 'vec3 nln = -one_float * lightNorm;', - 'float spotCos = dot(nln, lpv);', - 'return spotCos <= minCos ? zero_float : pow(spotCos, spotExp);', - '}', - 'float lambertFactor(vec3 lightDir, vec3 vecNormal) {', - 'return max(zero_float, dot(lightDir, vecNormal));', - '}', - - 'float blinnPhongFactor(vec3 lightDir,', - 'vec3 vertPos,vec3 vecNormal, float shine) {', - 'vec3 np = normalize(vertPos);', - 'vec3 ldp = normalize(lightDir - np);', - 'return pow(max(zero_float, dot(ldp, vecNormal)), shine);', - '}', - - 'void main() {', - // Vertex in clip coordinates - 'gl_Position = transformMatrix * position;', - - // Vertex in eye coordinates - 'vec3 ecVertex = vec3(modelviewMatrix * position);', - - // Normal vector in eye coordinates - 'vec3 ecNormal = normalize(normalMatrix * normal);', - 'vec3 ecNormalInv = ecNormal * -one_float;', - - // Light calculations - 'vec3 totalAmbient = vec3(0, 0, 0);', - - 'vec3 totalFrontDiffuse = vec3(0, 0, 0);', - 'vec3 totalFrontSpecular = vec3(0, 0, 0);', - - 'vec3 totalBackDiffuse = vec3(0, 0, 0);', - 'vec3 totalBackSpecular = vec3(0, 0, 0);', - - 'for (int i = 0; i < 8; i++) {', - 'if (lightCount == i) break;', - - 'vec3 lightPos = lightPosition[i].xyz;', - 'bool isDir = zero_float < lightPosition[i].w;', - 'float spotCos = lightSpot[i].x;', - 'float spotExp = lightSpot[i].y;', - - 'vec3 lightDir;', - 'float falloff;', - 'float spotf;', - - 'if (isDir) {', - 'falloff = one_float;', - 'lightDir = -one_float * lightNormal[i];', - '} else {', - 'falloff = falloffFactor(lightPos, ecVertex, lightFalloff[i]);', - 'lightDir = normalize(lightPos - ecVertex);', - '}', - - 'spotf=spotExp > zero_float ? spotFactor(lightPos,', - 'ecVertex,', - 'lightNormal[i],', - 'spotCos,', - 'spotExp):one_float;', - - 'if (any(greaterThan(lightAmbient[i], zero_vec3))) {', - 'totalAmbient+= lightAmbient[i] * falloff;', - '}', - - 'if (any(greaterThan(lightDiffuse[i], zero_vec3))) {', - 'totalFrontDiffuse += lightDiffuse[i] * falloff * spotf *', - 'lambertFactor(lightDir, ecNormal);', - 'totalBackDiffuse += lightDiffuse[i] * falloff * spotf *', - 'lambertFactor(lightDir, ecNormalInv);', - '}', - - 'if (any(greaterThan(lightSpecular[i], zero_vec3))) {', - 'totalFrontSpecular += lightSpecular[i] * falloff * spotf * ', - 'blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess);', - 'totalBackSpecular += lightSpecular[i] * falloff * spotf *', - 'blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess);', - '}', - '}', - - // Calculating final color as result of all lights (plus emissive term). - // Transparency is determined exclusively by the diffuse component. - 'vertColor =vec4(totalAmbient, 0) * ambient + ', - 'vec4(totalFrontDiffuse, 1) * color +' , - 'vec4(totalFrontSpecular, 0) * specular +', - 'vec4(emissive.rgb, 0);', - - 'backVertColor = vec4(totalAmbient, 0) * ambient + ', - 'vec4(totalBackDiffuse, 1) * color +', - 'vec4(totalBackSpecular, 0) * specular +', - 'vec4(emissive.rgb, 0);', - - // Calculating texture coordinates, with r and q set both to one - 'vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);', - '}' - ].join('\n'), - texLightFrag : [ - 'precision mediump float;', - 'precision mediump int;', - 'uniform sampler2D texture;', - - 'uniform vec2 texOffset;', - - 'varying vec4 vertColor;', - 'varying vec4 backVertColor;', - 'varying vec4 vertTexCoord;', - - 'void main() {', - 'gl_FragColor = texture2D(texture,vertTexCoord.st)*', - '(gl_FrontFacing ? vertColor : backVertColor);', - '}' - ].join('\n'), - normalVert: [ - 'attribute vec3 position;', - 'attribute vec3 normal;', - - 'uniform mat4 modelviewMatrix;', - 'uniform mat4 transformMatrix;', - 'uniform mat4 normalMatrix;', - - 'varying vec3 vertexNormal;', - - 'void main(void) {', - 'vec3 zeroToOne = position / 1000.0;', - 'vec4 positionVec4 = vec4(zeroToOne, 1.);', - 'gl_Position = transformMatrix * modelviewMatrix * positionVec4;', - 'vertexNormal = vec3( normalMatrix * vec4( normal, 1.0 ) );', - '}' - ].join('\n'), - normalFrag: [ - 'precision mediump float;', - 'varying vec3 vertexNormal;', - 'void main(void) {', - 'gl_FragColor = vec4(vertexNormal, 1.0);', - '}' - ].join('\n'), - basicFrag: [ - 'precision mediump float;', - 'varying vec3 vertexNormal;', - //'uniform vec3 uBasic' - 'void main(void) {', - // 'gl_FragColor = vec4(vertexNormal * uBasic, 1.0);', - 'gl_FragColor = vec4(vertexNormal * vec3(0.5, 0.5, 0.5), 1.0);', - '}' - ].join('\n'), - vertexColorVert:[ - 'attribute vec3 position;', - - 'attribute vec4 aVertexColor;', - - 'uniform mat4 modelviewMatrix;', - 'uniform mat4 transformMatrix;', - - 'varying vec4 vColor;', - 'void main(void) {', - 'vec3 zeroToOne = position / 1000.0;', - 'vec4 positionVec4 = vec4(zeroToOne, 1.);', - 'gl_Position = transformMatrix * modelviewMatrix * positionVec4;', - 'vColor = aVertexColor;', - '}' - ].join('\n'), - vertexColorFrag:[ - 'precision mediump float;', - 'varying vec4 vColor;', - 'void main(void) {', - ' gl_FragColor = vColor;', - '}' - ].join('\n') -}; \ No newline at end of file diff --git a/src/3d/shaders/basic.frag b/src/3d/shaders/basic.frag new file mode 100644 index 0000000000..f6427a8bf8 --- /dev/null +++ b/src/3d/shaders/basic.frag @@ -0,0 +1,6 @@ +precision mediump float; +varying vec3 vertexNormal; +uniform vec4 uMaterialColor; +void main(void) { + gl_FragColor = uMaterialColor; +} \ No newline at end of file diff --git a/src/3d/shaders/light.vert b/src/3d/shaders/light.vert new file mode 100644 index 0000000000..22b0cc6bd0 --- /dev/null +++ b/src/3d/shaders/light.vert @@ -0,0 +1,149 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-13 Ben Fry and Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + */ + +uniform mat4 modelviewMatrix; +uniform mat4 transformMatrix; +uniform mat3 normalMatrix; + +uniform int lightCount; +uniform vec4 lightPosition[8]; +uniform vec3 lightNormal[8]; +uniform vec3 lightAmbient[8]; +uniform vec3 lightDiffuse[8]; +uniform vec3 lightSpecular[8]; +uniform vec3 lightFalloff[8]; +uniform vec2 lightSpot[8]; + +attribute vec4 position; +attribute vec4 color; +attribute vec3 normal; + +attribute vec4 ambient; +attribute vec4 specular; +attribute vec4 emissive; +attribute float shininess; + +varying vec4 vertColor; +varying vec4 backVertColor; + +const float zero_float = 0.0; +const float one_float = 1.0; +const vec3 zero_vec3 = vec3(0); + +float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) { + vec3 lpv = lightPos - vertPos; + vec3 dist = vec3(one_float); + dist.z = dot(lpv, lpv); + dist.y = sqrt(dist.z); + return one_float / dot(dist, coeff); +} + +float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) { + vec3 lpv = normalize(lightPos - vertPos); + vec3 nln = -one_float * lightNorm; + float spotCos = dot(nln, lpv); + return spotCos <= minCos ? zero_float : pow(spotCos, spotExp); +} + +float lambertFactor(vec3 lightDir, vec3 vecNormal) { + return max(zero_float, dot(lightDir, vecNormal)); +} + +float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) { + vec3 np = normalize(vertPos); + vec3 ldp = normalize(lightDir - np); + return pow(max(zero_float, dot(ldp, vecNormal)), shine); +} + +void main() { + // Vertex in clip coordinates + gl_Position = transformMatrix * position; + + // Vertex in eye coordinates + vec3 ecVertex = vec3(modelviewMatrix * position); + + // Normal vector in eye coordinates + vec3 ecNormal = normalize(normalMatrix * normal); + vec3 ecNormalInv = ecNormal * -one_float; + + // Light calculations + vec3 totalAmbient = vec3(0, 0, 0); + + vec3 totalFrontDiffuse = vec3(0, 0, 0); + vec3 totalFrontSpecular = vec3(0, 0, 0); + + vec3 totalBackDiffuse = vec3(0, 0, 0); + vec3 totalBackSpecular = vec3(0, 0, 0); + + for (int i = 0; i < 8; i++) { + if (lightCount == i) break; + + vec3 lightPos = lightPosition[i].xyz; + bool isDir = zero_float < lightPosition[i].w; + float spotCos = lightSpot[i].x; + float spotExp = lightSpot[i].y; + + vec3 lightDir; + float falloff; + float spotf; + + if (isDir) { + falloff = one_float; + lightDir = -one_float * lightNormal[i]; + } else { + falloff = falloffFactor(lightPos, ecVertex, lightFalloff[i]); + lightDir = normalize(lightPos - ecVertex); + } + + spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i], + spotCos, spotExp) + : one_float; + + if (any(greaterThan(lightAmbient[i], zero_vec3))) { + totalAmbient += lightAmbient[i] * falloff; + } + + if (any(greaterThan(lightDiffuse[i], zero_vec3))) { + totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormal); + totalBackDiffuse += lightDiffuse[i] * falloff * spotf * + lambertFactor(lightDir, ecNormalInv); + } + + if (any(greaterThan(lightSpecular[i], zero_vec3))) { + totalFrontSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); + totalBackSpecular += lightSpecular[i] * falloff * spotf * + blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); + } + } + + // Calculating final color as result of all lights (plus emissive term). + // Transparency is determined exclusively by the diffuse component. + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalFrontDiffuse, 1) * color + + vec4(totalFrontSpecular, 0) * specular + + vec4(emissive.rgb, 0); + + backVertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalBackDiffuse, 1) * color + + vec4(totalBackSpecular, 0) * specular + + vec4(emissive.rgb, 0); +} \ No newline at end of file diff --git a/src/3d/shaders/normal.frag b/src/3d/shaders/normal.frag new file mode 100644 index 0000000000..bc38412a86 --- /dev/null +++ b/src/3d/shaders/normal.frag @@ -0,0 +1,5 @@ +precision mediump float; +varying vec3 vertexNormal; +void main(void) { + gl_FragColor = vec4(vertexNormal, 1.0); +} \ No newline at end of file diff --git a/src/3d/shaders/normal.vert b/src/3d/shaders/normal.vert new file mode 100644 index 0000000000..a1a7a428e8 --- /dev/null +++ b/src/3d/shaders/normal.vert @@ -0,0 +1,16 @@ +attribute vec3 position; +attribute vec3 normal; + +uniform mat4 modelviewMatrix; +uniform mat4 transformMatrix; +uniform mat4 normalMatrix; +uniform float uResolution; + +varying vec3 vertexNormal; + +void main(void) { + vec3 zeroToOne = position / uResolution; + vec4 positionVec4 = vec4(zeroToOne, 1.); + gl_Position = transformMatrix * modelviewMatrix * positionVec4; + vertexNormal = vec3( normalMatrix * vec4( normal, 1.0 ) ); +} \ No newline at end of file diff --git a/src/3d/shaders/vertexColor.frag b/src/3d/shaders/vertexColor.frag new file mode 100644 index 0000000000..13c20b257c --- /dev/null +++ b/src/3d/shaders/vertexColor.frag @@ -0,0 +1,5 @@ +precision mediump float; +varying vec4 vColor; +void main(void) { + gl_FragColor = vColor; +} \ No newline at end of file diff --git a/src/3d/shaders/vertexColor.vert b/src/3d/shaders/vertexColor.vert new file mode 100644 index 0000000000..eefc56689b --- /dev/null +++ b/src/3d/shaders/vertexColor.vert @@ -0,0 +1,15 @@ +attribute vec3 position; + +attribute vec4 aVertexColor; + +uniform mat4 modelviewMatrix; +uniform mat4 transformMatrix; + +varying vec4 vColor; + +void main(void) { + vec3 zeroToOne = position / 1000.0; + vec4 positionVec4 = vec4(zeroToOne * vec3(1., -1., 1.), 1.); + gl_Position = transformMatrix * modelviewMatrix * positionVec4; + vColor = aVertexColor; +} \ No newline at end of file diff --git a/src/app.js b/src/app.js index 689a9755cb..55fe358990 100644 --- a/src/app.js +++ b/src/app.js @@ -47,10 +47,13 @@ require('./typography/loading_displaying'); require('./3d/p5.Renderer3D'); require('./3d/p5.Geometry3D'); +require('./3d/retainedMode3D'); +require('./3d/immediateMode3D'); require('./3d/3d_primitives'); -require('./3d/shaders'); require('./3d/p5.Matrix'); require('./3d/material'); +require('./3d/shader'); +require('./3d/interaction'); /** * _globalInit diff --git a/src/core/2d_primitives.js b/src/core/2d_primitives.js index cd9eb73d54..9e536af3a3 100644 --- a/src/core/2d_primitives.js +++ b/src/core/2d_primitives.js @@ -209,18 +209,21 @@ p5.prototype.line = function() { } //check whether we should draw a 3d line or 2d if(this._graphics.isP3D){ - this._graphics.line(arguments[0], + this._graphics.line( + arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); } else { - this._graphics.line(arguments[0], + this._graphics.line( + arguments[0], arguments[1], arguments[2], arguments[3]); } + return this; }; /** @@ -242,17 +245,32 @@ p5.prototype.line = function() { * * */ -p5.prototype.point = function(x, y) { +p5.prototype.point = function() { this._validateParameters( 'point', arguments, - ['Number', 'Number'] + [ + ['Number', 'Number'], + ['Number', 'Number', 'Number'] + ] ); if (!this._doStroke) { return this; } - this._graphics.point(x, y); + //check whether we should draw a 3d line or 2d + if(this._graphics.isP3D){ + this._graphics.point( + arguments[0], + arguments[1], + arguments[2] + ); + } else { + this._graphics.point( + arguments[0], + arguments[1] + ); + } return this; }; @@ -281,18 +299,50 @@ p5.prototype.point = function(x, y) { * * */ -p5.prototype.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { +p5.prototype.quad = function() { this._validateParameters( 'quad', arguments, - [ 'Number', 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number', 'Number' ] + [ + [ 'Number', 'Number', 'Number', 'Number', + 'Number', 'Number', 'Number', 'Number' ], + [ 'Number', 'Number', 'Number', + 'Number', 'Number', 'Number', + 'Number', 'Number', 'Number', + 'Number', 'Number', 'Number'] + ] ); if (!this._doStroke && !this._doFill) { return this; } - this._graphics.quad(x1, y1, x2, y2, x3, y3, x4, y4); + if(this._graphics.isP3D){ + this._graphics.quad( + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4], + arguments[5], + arguments[6], + arguments[7], + arguments[8], + arguments[9], + arguments[10], + arguments[11] + ); + } else { + this._graphics.quad( + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4], + arguments[5], + arguments[6], + arguments[7] + ); + } return this; }; @@ -379,17 +429,42 @@ p5.prototype.rect = function (x, y, w, h, tl, tr, br, bl) { * * */ -p5.prototype.triangle = function(x1, y1, x2, y2, x3, y3) { +p5.prototype.triangle = function() { this._validateParameters( 'triangle', arguments, - ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'] + [ + ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'], + ['Number', 'Number', 'Number', 'Number', 'Number', 'Number', + 'Number', 'Number', 'Number'] + ] ); if (!this._doStroke && !this._doFill) { return this; } - this._graphics.triangle(x1, y1, x2, y2, x3, y3); + if(this._graphics.isP3D){ + this._graphics.triangle( + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4], + arguments[5], + arguments[6], + arguments[7], + arguments[8] + ); + } else { + this._graphics.triangle( + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4], + arguments[5] + ); + } return this; }; diff --git a/src/core/vertex.js b/src/core/vertex.js index d113f57399..4dcc81f342 100644 --- a/src/core/vertex.js +++ b/src/core/vertex.js @@ -226,19 +226,23 @@ p5.prototype.beginContour = function() { * */ p5.prototype.beginShape = function(kind) { - if (kind === constants.POINTS || - kind === constants.LINES || - kind === constants.TRIANGLES || - kind === constants.TRIANGLE_FAN || - kind === constants.TRIANGLE_STRIP || - kind === constants.QUADS || - kind === constants.QUAD_STRIP) { - shapeKind = kind; - } else { - shapeKind = null; + if(this._graphics.isP3D){ + this._graphics.beginShape(kind); + }else{ + if (kind === constants.POINTS || + kind === constants.LINES || + kind === constants.TRIANGLES || + kind === constants.TRIANGLE_FAN || + kind === constants.TRIANGLE_STRIP || + kind === constants.QUADS || + kind === constants.QUAD_STRIP) { + shapeKind = kind; + } else { + shapeKind = null; + } + vertices = []; + contourVertices = []; } - vertices = []; - contourVertices = []; return this; }; @@ -418,30 +422,34 @@ p5.prototype.endContour = function() { * */ p5.prototype.endShape = function(mode) { - if (vertices.length === 0) { return this; } - if (!this._doStroke && !this._doFill) { return this; } + if(this._graphics.isP3D){ + this._graphics.endShape(); + }else{ + if (vertices.length === 0) { return this; } + if (!this._doStroke && !this._doFill) { return this; } - var closeShape = mode === constants.CLOSE; + var closeShape = mode === constants.CLOSE; - // if the shape is closed, the first element is also the last element - if (closeShape && !isContour) { - vertices.push(vertices[0]); - } + // if the shape is closed, the first element is also the last element + if (closeShape && !isContour) { + vertices.push(vertices[0]); + } - this._graphics.endShape(mode, vertices, isCurve, isBezier, - isQuadratic, isContour, shapeKind); + this._graphics.endShape(mode, vertices, isCurve, isBezier, + isQuadratic, isContour, shapeKind); - // Reset some settings - isCurve = false; - isBezier = false; - isQuadratic = false; - isContour = false; + // Reset some settings + isCurve = false; + isBezier = false; + isQuadratic = false; + isContour = false; - // If the shape is closed, the first element was added as last element. - // We must remove it again to prevent the list of vertices from growing - // over successive calls to endShape(CLOSE) - if (closeShape) { - vertices.pop(); + // If the shape is closed, the first element was added as last element. + // We must remove it again to prevent the list of vertices from growing + // over successive calls to endShape(CLOSE) + if (closeShape) { + vertices.pop(); + } } return this; }; @@ -541,26 +549,31 @@ p5.prototype.quadraticVertex = function(cx, cy, x3, y3) { * */ p5.prototype.vertex = function(x, y, moveTo) { - var vert = []; - vert.isVert = true; - vert[0] = x; - vert[1] = y; - vert[2] = 0; - vert[3] = 0; - vert[4] = 0; - vert[5] = this._graphics._getFill(); - vert[6] = this._graphics._getStroke(); + if(this._graphics.isP3D){ + this._graphics.vertex + (arguments[0], arguments[1], arguments[2]); + }else{ + var vert = []; + vert.isVert = true; + vert[0] = x; + vert[1] = y; + vert[2] = 0; + vert[3] = 0; + vert[4] = 0; + vert[5] = this._graphics._getFill(); + vert[6] = this._graphics._getStroke(); - if (moveTo) { - vert.moveTo = moveTo; - } - if (isContour) { - if (contourVertices.length === 0) { - vert.moveTo = true; + if (moveTo) { + vert.moveTo = moveTo; + } + if (isContour) { + if (contourVertices.length === 0) { + vert.moveTo = true; + } + contourVertices.push(vert); + } else { + vertices.push(vert); } - contourVertices.push(vert); - } else { - vertices.push(vert); } return this; };