diff --git a/demos/many_clouds/index.html b/demos/many_clouds/index.html index 8d577ba..5a65580 100644 --- a/demos/many_clouds/index.html +++ b/demos/many_clouds/index.html @@ -10,7 +10,7 @@ - + diff --git a/demos/many_clouds/many_clouds.js b/demos/many_clouds/js/many_clouds.js similarity index 97% rename from demos/many_clouds/many_clouds.js rename to demos/many_clouds/js/many_clouds.js index 8a06d6c..89dcf0c 100644 --- a/demos/many_clouds/many_clouds.js +++ b/demos/many_clouds/js/many_clouds.js @@ -128,9 +128,7 @@ function render() { function start(){ ps = new PointStream(); ps.setup(document.getElementById('canvas')); - ps.background([.3,.6, .9,1]); - ps.background([1,1,1,1]); - //ps.background([1,1,1,0.1]); + ps.background([1,1,1,1]); ps.onRender = render ps.onMouseScroll = zoom; diff --git a/demos/many_clouds/shaders/acorn_shader.js b/demos/many_clouds/shaders/acorn_shader.js index 8e98041..512c9bb 100644 --- a/demos/many_clouds/shaders/acorn_shader.js +++ b/demos/many_clouds/shaders/acorn_shader.js @@ -16,27 +16,17 @@ var acornVertShader = "attribute vec4 ps_Color;" + "uniform float ps_PointSize;" + -"uniform vec3 XBPS_attenuation;" + +"uniform vec3 ps_Attenuation;" + "uniform mat4 ps_ModelViewMatrix;" + "uniform mat4 ps_ProjectionMatrix;" + "uniform mat4 ps_NormalMatrix;" + -"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal, in vec3 eye ) {" + - // Get the vector from the light to the vertex -" vec3 VP = vec3(0.0, 150.0, 150.0) - ecPos;" + - -// Get the distance from the current vector to the light position -" float d = length( VP ); " + - -// Normalize the light ray so it can be used in the dot product operation. -" VP = normalize( VP );" + - -" float attenuation = 1.0 / ( 1.0 + ( d ) + ( d * d ));" + -" float nDotVP = max( 0.0, dot( vertNormal, VP ));" + -" vec3 halfVector = normalize( VP + eye );" + -" float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" + -" col += vec3(0.7, 0.7, 1.0) * nDotVP;" + +"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal) {" + +" vec3 VP = -ecPos;" + +" VP = normalize(VP);" + +" float nDotVP = max(0.0, dot(vertNormal, VP));" + +" col = vec3(1.0, 1.0, 1.0) * nDotVP;" + "}" + "void main(void) {" + @@ -44,24 +34,17 @@ var acornVertShader = " vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" + " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" + -" vec3 eye = vec3( 0.0, 0.0, 1.0 );" + -" vec3 col = vec3(0.0, 0.0, 0.0);" + -" PointLight(col, ecPos, transNorm, eye);" + +" vec3 col;" + +" PointLight(col, ecPos, transNorm);" + " frontColor = ps_Color * vec4(col, 1.0);" + -" float dist = length( ecPos4 );" + -" float attn = XBPS_attenuation[0] + " + -" (XBPS_attenuation[1] * dist) + " + -" (XBPS_attenuation[2] * dist * dist);" + - -" if(attn > 0.0){" + -" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + -" }" + -" else{" + -" gl_PointSize = 1.0;" + -" }"+ +" float dist = length(ecPos4);" + +" float attn = ps_Attenuation[0] + " + +" (ps_Attenuation[1] * dist) + " + +" (ps_Attenuation[2] * dist * dist);" + +" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + " gl_Position = ps_ProjectionMatrix * ecPos4;" + "}"; diff --git a/demos/many_clouds/shaders/mickey_shader.js b/demos/many_clouds/shaders/mickey_shader.js index 2432586..e009a41 100644 --- a/demos/many_clouds/shaders/mickey_shader.js +++ b/demos/many_clouds/shaders/mickey_shader.js @@ -17,7 +17,7 @@ var mickeyVertShader = "attribute vec4 ps_Color;" + "uniform float ps_PointSize;" + -"uniform vec3 XBPS_attenuation;" + +"uniform vec3 ps_Attenuation;" + "uniform mat4 ps_ModelViewMatrix;" + "uniform mat4 ps_ProjectionMatrix;" + @@ -36,9 +36,9 @@ var mickeyVertShader = " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" + " float dist = length( ecPos4 );" + -" float attn = XBPS_attenuation[0] + " + -" (XBPS_attenuation[1] * dist) + " + -" (XBPS_attenuation[2] * dist * dist);" + +" float attn = ps_Attenuation[0] + " + +" (ps_Attenuation[1] * dist) + " + +" (ps_Attenuation[2] * dist * dist);" + " gl_PointSize = attn > 0.0 ? ps_PointSize * sqrt(1.0/attn) : 1.0;" + diff --git a/notes.txt b/notes.txt deleted file mode 100644 index f8acf10..0000000 --- a/notes.txt +++ /dev/null @@ -1,34 +0,0 @@ -If writing a parser and using the XB PointStream built-in shader, -you must ensure the parser set the correct attribute names - -XBPS_aVertex -XBPS_aColor - - -XBPS_model -XBPS_view -XBPS_modelView -XBPS_perspective - -XBPS_pointSize - - -use XBPS shaders and parser -- Only position and colors will be available - -use XBPS parser -- You must read XBPS attribute names in your shader - -use XBPS shader -- You must write to XBPS attribute names in your parser - -use custom shader and parser -- any attribute names can be read and written to, except you must use - -XBPS_model -XBPS_view -XBPS_modelView -XBPS_normalMatrix -XBPS_perspective -XBPS_pointSize - diff --git a/psapi.js b/psapi.js index 5a8463d..8adf2a1 100644 --- a/psapi.js +++ b/psapi.js @@ -122,7 +122,7 @@ var PointStream = (function() { "attribute vec4 ps_Color;" + "uniform float ps_PointSize;" + - "uniform vec3 XBPS_attenuation;" + + "uniform vec3 ps_Attenuation;" + "uniform mat4 ps_ModelViewMatrix;" + "uniform mat4 ps_ProjectionMatrix;" + @@ -131,9 +131,9 @@ var PointStream = (function() { " frontColor = ps_Color;" + " vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" + " float dist = length(ecPos4);" + - " float attn = XBPS_attenuation[0] + " + - " (XBPS_attenuation[1] * dist) + " + - " (XBPS_attenuation[2] * dist * dist);" + + " float attn = ps_Attenuation[0] + " + + " (ps_Attenuation[1] * dist) + " + + " (ps_Attenuation[2] * dist * dist);" + " if(attn > 0.0){" + " gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + @@ -146,14 +146,14 @@ var PointStream = (function() { "}"; var fragmentShaderSource = - "#ifdef GL_ES\n" + - "precision highp float;\n" + - "#endif\n" + - - "varying vec4 frontColor;" + - "void main(void){" + - " gl_FragColor = frontColor;" + - "}"; + '#ifdef GL_ES \n\ + precision highp float; \n\ + #endif \n\ + \n\ + varying vec4 frontColor; \n\ + void main(void){ \n\ + gl_FragColor = frontColor; \n\ + }'; /** set a uniform integer @@ -788,6 +788,23 @@ var PointStream = (function() { } } + // !! fix (remove from global ns) + function getAverage(arr){ + var objCenter = [0, 0, 0]; + + for(var i = 0; i < arr.length; i += 3){ + objCenter[0] += arr[i]; + objCenter[1] += arr[i+1]; + objCenter[2] += arr[i+2]; + } + + objCenter[0] /= arr.length/3; + objCenter[1] /= arr.length/3; + objCenter[2] /= arr.length/3; + + return objCenter; + } + /** Sets variables to default values. */ @@ -1171,7 +1188,7 @@ var PointStream = (function() { */ this.setDefaultUniforms = function(){ uniformf(currProgram, "ps_PointSize", 1); - uniformf(currProgram, "XBPS_attenuation", [attn[0], attn[1], attn[2]]); + uniformf(currProgram, "ps_Attenuation", [attn[0], attn[1], attn[2]]); uniformMatrix(currProgram, "ps_ProjectionMatrix", false, projectionMatrix); }; @@ -1262,7 +1279,7 @@ var PointStream = (function() { @param {Number} quadratic - */ this.attenuation = function(constant, linear, quadratic){ - uniformf(currProgram, "attenuation", [constant, linear, quadratic]); + uniformf(currProgram, "ps_Attenuation", [constant, linear, quadratic]); }; /** @@ -1338,20 +1355,3 @@ var PointStream = (function() { return PointStream; }()); - -// !! fix (remove from global ns) -var getAverage = function(arr){ - var objCenter = [0, 0, 0]; - - for(var i = 0; i < arr.length; i += 3){ - objCenter[0] += arr[i]; - objCenter[1] += arr[i+1]; - objCenter[2] += arr[i+2]; - } - - objCenter[0] /= arr.length/3; - objCenter[1] /= arr.length/3; - objCenter[2] /= arr.length/3; - - return objCenter; -} diff --git a/tests/user_parser/user_asc_parser.js b/tests/user_parser/user_asc_parser.js index c1578cf..affd649 100644 --- a/tests/user_parser/user_asc_parser.js +++ b/tests/user_parser/user_asc_parser.js @@ -10,7 +10,12 @@ Notes: This parser parses .ASC filetypes. These files are ASCII files which have their data stored in one of the following ways: - + + This particular parser is meant to be used with the built-in XB + PointStream shader, therefore it only reads in vertex positions + and colors. + + .ASC structure can be one of: X, Y, Z X, Y, Z, R, G, B X, Y, Z, I, J, K @@ -53,12 +58,7 @@ var User_ASC_Parser = (function() { var normalsPresent = false; var colorsPresent = false; var layoutCode = UNKNOWN; - - // - var parsedVerts = []; - var parsedCols = []; - var parsedNorms = []; - + // keep track if onprogress event handler was called to // handle Chrome/WebKit vs. Minefield differences. // @@ -79,9 +79,9 @@ var User_ASC_Parser = (function() { ASC files can either contain X, Y, Z - X, Y, Z, R, G, B - X, Y, Z, NX, NY, NZ - X, Y, Z, R, G, B, NX, NY, NZ + X, Y, Z, R, G, B + X, Y, Z, I, J, K + X, Y, Z, R, G, B, I, J, K @returns {Number} 0 first case @@ -299,16 +299,15 @@ var User_ASC_Parser = (function() { var verts = new Float32Array(numVerts * 3); var cols = colorsPresent ? new Float32Array(numVerts * 3) : null; - var norms = normalsPresent ? new Float32Array(numVerts * 3) : null; - // depending if there are colors, + // depending if there are colors, // we'll need to read different indices. // if there aren't: - // x y z r g b nx ny nz + // x y z r g b i j k // 0 1 2 3 4 5 6 7 8 <- normals start at index 6 // // if there are: - // x y z nx ny nz + // x y z i j k // 0 1 2 3 4 5 <- normals start at index 3 var valueOffset = 0; if(colorsPresent){ @@ -327,31 +326,15 @@ var User_ASC_Parser = (function() { cols[j+1] = parseInt(chunk[i+4])/255; cols[j+2] = parseInt(chunk[i+5])/255; } - - if(norms){ - norms[j] = parseFloat(chunk[i + 3 + valueOffset]); - norms[j+1] = parseFloat(chunk[i + 4 + valueOffset]); - norms[j+2] = parseFloat(chunk[i + 5 + valueOffset]); - } } - - // !! pushing on null? - parsedVerts.push(verts); - parsedCols.push(cols); - parsedNorms.push(norms); - + // XB PointStream expects an object with named/value pairs // which contain the attribute arrays. These must match attribute // names found in the shader - // attributes { - // "VERTEX" : [...], - // "COLOR" : [...] - // } var attributes = {}; if(verts){attributes["ps_Vertex"] = verts;} if(cols){attributes["ps_Color"] = cols;} - if(norms){attributes["ps_Normal"] = norms;} parse(AJAX.parser, attributes); } diff --git a/tests/user_parser/user_parser.js b/tests/user_parser/user_parser.js index aeb6dea..014f276 100644 --- a/tests/user_parser/user_parser.js +++ b/tests/user_parser/user_parser.js @@ -18,12 +18,11 @@ function render() { function start(){ ps = new PointStream(); ps.setup(document.getElementById('canvas')); + ps.registerParser("asc", User_ASC_Parser); ps.onRender = render; ps.background([1, 1, 1, 1]); ps.pointSize(5); - - ps.registerParser("asc", User_ASC_Parser); acorn = ps.load("../../clouds/acorn.asc"); } diff --git a/tests/user_parser_and_shader/index.html b/tests/user_parser_and_shader/index.html new file mode 100644 index 0000000..9e0822c --- /dev/null +++ b/tests/user_parser_and_shader/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + +

XB PointStream User-defined Parser

+ +

+ This test makes sure the user can specify their own parser and hook it into + the library. +
+
+
+

+ + + diff --git a/tests/user_parser_and_shader/user_asc_parser.js b/tests/user_parser_and_shader/user_asc_parser.js new file mode 100644 index 0000000..affd649 --- /dev/null +++ b/tests/user_parser_and_shader/user_asc_parser.js @@ -0,0 +1,402 @@ +/* + Copyright (c) 2010 Seneca College + MIT LICENSE + + Version: 0.1 + Author: Andor Salga + asalga.wordpress.com + Date: November 16, 2010 + + Notes: + This parser parses .ASC filetypes. These files are ASCII + files which have their data stored in one of the following ways: + + This particular parser is meant to be used with the built-in XB + PointStream shader, therefore it only reads in vertex positions + and colors. + + .ASC structure can be one of: + X, Y, Z + X, Y, Z, R, G, B + X, Y, Z, I, J, K + X, Y, Z, R, G, B, I, J, K +*/ + +var User_ASC_Parser = (function() { + + /** + Constructor + */ + function User_ASC_Parser(config) { + + var undef; + + // defined once to reduce number of empty functions + var __empty_func = function(){}; + + var start = config.start || __empty_func; + var parse = config.parse || __empty_func; + var end = config.end || __empty_func; + + var version = "0.1"; + + const UNKNOWN = -1; + + const XHR_DONE = 4; + const STARTED = 1; + + var pathToFile = null; + var fileSizeInBytes = 0; + + // + var numParsedPoints = 0; + var numTotalPoints = 0; + var progress = 0; + + // + var numValuesPerLine = -1; + var normalsPresent = false; + var colorsPresent = false; + var layoutCode = UNKNOWN; + + // keep track if onprogress event handler was called to + // handle Chrome/WebKit vs. Minefield differences. + // + // Minefield will call onprogress zero or many times + // Chrome/WebKit will call onprogress one or many times + var onProgressCalled = false; + var AJAX = null; + + // WebGL compatibility wrapper + try{ + Float32Array; + }catch(ex){ + Float32Array = WebGLFloatArray; + } + + /** + @private + + ASC files can either contain + X, Y, Z + X, Y, Z, R, G, B + X, Y, Z, I, J, K + X, Y, Z, R, G, B, I, J, K + + @returns {Number} + 0 first case + 1 second case + 2 third case + 3 fourth case + */ + var getDataLayout = function(values){ + var normalsPresent = false; + var colorsPresent = false; + + var VERTS = 0; + var VERTS_COLS = 1; + var VERTS_NORMS = 2; + var VERTS_COLS_NORMS = 3; + + // first check if there are 9 values, which would mean we have + // xyz rgb and normals + + // We can do this by counting the number of whitespace on the first line + var i = 0; + var numSpaces = 0; + do{ + i++; + if(values[i] == " "){ + numSpaces++; + } + }while(values[i] != '\n'); + + // Vertices, Colors, Normals: + // 1.916 -2.421 -4.0 64 32 16 -0.3727 -0.2476 -0.8942 + if(numSpaces === 8){ + return VERTS_COLS_NORMS; + } + + // Just vertices: + // 1.916 -2.421 -4.0339 + if(numSpaces == 2){ + return VERTS; + } + + var str = ""; + + // + // !! fix me + for(i = 0; i < 500; i++){ + str += values[i]; + } + + var str_split = str.split(/\s+/); + var data = []; + + for(var i = 3; i < str_split.length;){ + data.push(str_split[i++]); + data.push(str_split[i++]); + data.push(str_split[i++]); + i += 3; + } + + for(var i = 0; i < data.length; i++){ + if(data[i] < 0 || data[i] > 255){ + normalsPresent = true; + return VERTS_NORMS; + } + } + + // Vertices and Normals: + // 1.916 -2.421 -4.0 -0.3727 -0.2476 -0.8942 + return VERTS_COLS; + }; + + /* + Returns the version of this parser. + + @returns {String} parser version. + */ + this.__defineGetter__("version", function(){ + return version; + }); + + /* + Get the number of parsed points so far. + + @returns {Number} number of points parsed. + */ + this.__defineGetter__("numParsedPoints", function(){ + return numParsedPoints; + }); + + /* + Get the total number of points in the point cloud. + + @returns {Number} + */ + this.__defineGetter__("numTotalPoints", function(){ + return numTotalPoints; + }); + + /** + Returns the progress of downloading the point cloud between zero and one. + + @returns {Number} value from zero to one or -1 if unknown. + */ + this.__defineGetter__("progress", function(){ + return progress; + }); + + /** + Returns the file size of the resource in bytes. + + @returns {Number} size of resource in bytes. + */ + this.__defineGetter__("fileSize", function(){ + return fileSizeInBytes; + }); + + /** + @param path Path to the resource + */ + this.load = function(path){ + pathToFile = path; + + AJAX = new XMLHttpRequest(); + + // put a reference to the parser in the AJAX object + // so we can give the library a reference to the + // parser within the AJAX event handler scope. + // !! eventually need to fix this + AJAX.parser = this; + + /** + occurs exactly once when the resource begins + to be downloaded + */ + AJAX.onloadstart = function(evt){ + start(AJAX.parser); + }; + + /* + occurs exactly once, when the file is done + being downloaded + */ + AJAX.onload = function(evt){ + + var ascData = AJAX.responseText; + var chunk = null; + + // if the onprogress event didn't get called--we simply got + // the file in one go, we can parse from start to finish. + if(onProgressCalled === false){ + chunk = ascData; + } + // otherwise the onprogress event was called at least once, + // that means we need to get the data from a specific point to the end. + else if(ascData.length - AJAX.lastNewLineIndex > 1){ + chunk = ascData.substring(AJAX.lastNewLineIndex, ascData.length); + } + + // if the last chunk doesn't have any digits (just spaces) + // don't parse it. + if(chunk && chunk.match(/[0-9]/)){ + AJAX.parseChunk(chunk); + } + + numTotalPoints = numParsedPoints; + + progress = 1; + + end(AJAX.parser); + } + + /** + !! fix me + */ + AJAX.parseChunk = function(chunkData){ + var chunk = chunkData; + + // !! fix this + // this occurs over network connections, but not locally. + if(chunk !== ""){ + + // !! fix this + if(layoutCode === UNKNOWN){ + layoutCode = getDataLayout(chunk); + numValuesPerLine = -1; + + switch(layoutCode){ + case 0: numValuesPerLine = 3; + break; + case 1: numValuesPerLine = 6; + colorsPresent = true; + break; + case 2: numValuesPerLine = 6; + normalsPresent = true; + break; + case 3: numValuesPerLine = 9; + normalsPresent = true; + colorsPresent = true; + break; + } + gotLayout = true; + } + + // trim trailing spaces + chunk = chunk.replace(/\s+$/,""); + + // trim leading spaces + chunk = chunk.replace(/^\s+/,""); + + // split on white space + chunk = chunk.split(/\s+/); + + var numVerts = chunk.length/numValuesPerLine; + numParsedPoints += numVerts; + + var verts = new Float32Array(numVerts * 3); + var cols = colorsPresent ? new Float32Array(numVerts * 3) : null; + + // depending if there are colors, + // we'll need to read different indices. + // if there aren't: + // x y z r g b i j k + // 0 1 2 3 4 5 6 7 8 <- normals start at index 6 + // + // if there are: + // x y z i j k + // 0 1 2 3 4 5 <- normals start at index 3 + var valueOffset = 0; + if(colorsPresent){ + valueOffset = 3; + } + + // xyz rgb normals + for(var i = 0, j = 0, len = chunk.length; i < len; i += numValuesPerLine, j += 3){ + verts[j] = parseFloat(chunk[i]); + verts[j+1] = parseFloat(chunk[i+1]); + verts[j+2] = parseFloat(chunk[i+2]); + + // XBPS spec for parsers requires colors to be normalized + if(cols){ + cols[j] = parseInt(chunk[i+3])/255; + cols[j+1] = parseInt(chunk[i+4])/255; + cols[j+2] = parseInt(chunk[i+5])/255; + } + } + + // XB PointStream expects an object with named/value pairs + // which contain the attribute arrays. These must match attribute + // names found in the shader + + var attributes = {}; + if(verts){attributes["ps_Vertex"] = verts;} + if(cols){attributes["ps_Color"] = cols;} + + parse(AJAX.parser, attributes); + } + }; + + /** + On Minefield, this will occur zero or many times + On Chrome/WebKit this will occur one or many times + */ + AJAX.onprogress = function(evt){ + + if(evt.lengthComputable){ + fileSizeInBytes = evt.total; + progress = evt.loaded/evt.total; + } + + onProgressCalled = true; + + // if we have something to actually parse + if(AJAX.responseText){ + var ascData = AJAX.responseText; + + // we likely stopped getting data somewhere in the middle of + // a line in the ASC file + + // 5.813 2.352 6.500 0 0 0 2.646 3.577 2.516\n + // 1.079 1.296 9.360 0 0 0 4.307 1.181 5.208\n + // 3.163 2.225 6.139 0 0 0 0.6<-- stopped here + + // So find the last known newline. Everything from the last + // request to this last newline can be placed in a buffer. + var lastNewLineIndex = ascData.lastIndexOf("\n"); + AJAX.lastNewLineIndex = lastNewLineIndex; + + // if the status just changed and we finished downloading the + // file, grab everyting until the end. If there is only a bunch + // of whitespace, make a note of that and don't bother parsing. + if(AJAX.readyState === XHR_DONE){ + var chunk = ascData.substring(AJAX.startOfNextChunk, ascData.length); + // If the last chunk doesn't have any digits (just spaces) + // don't parse it. + if(chunk.match(/[0-9]/)){ + AJAX.parseChunk(chunk); + } + } + // if we still have more data to go + else{ + // Start of the next chunk starts after the newline. + var chunk = ascData.substring(AJAX.startOfNextChunk, lastNewLineIndex + 1); + AJAX.startOfNextChunk = lastNewLineIndex + 1; + AJAX.parseChunk(chunk); + } + } + };//onprogress + + // open an asynchronous request to the path + if(AJAX.overrideMimeType){ + AJAX.overrideMimeType("application/json"); + } + AJAX.open("GET", path, true); + AJAX.send(null); + };// load + }//ctor + return User_ASC_Parser; +}()); diff --git a/tests/user_parser_and_shader/user_parser.js b/tests/user_parser_and_shader/user_parser.js new file mode 100644 index 0000000..014f276 --- /dev/null +++ b/tests/user_parser_and_shader/user_parser.js @@ -0,0 +1,28 @@ +var ps, acorn; +var i = 0.0; +var j = 5.0; + +function render() { + + ps.translate(0, 0, -20); + ps.rotateY(i += 0.0011); + ps.rotateZ(j += 0.0015); + + var c = acorn.getCenter(); + ps.translate(-c[0], -c[1], -c[2]); + + ps.clear(); + ps.render(acorn); +} + +function start(){ + ps = new PointStream(); + ps.setup(document.getElementById('canvas')); + ps.registerParser("asc", User_ASC_Parser); + ps.onRender = render; + + ps.background([1, 1, 1, 1]); + ps.pointSize(5); + + acorn = ps.load("../../clouds/acorn.asc"); +} diff --git a/tests/user_shader/shaders.js b/tests/user_shader/shaders.js index cd04016..4203bdc 100644 --- a/tests/user_shader/shaders.js +++ b/tests/user_shader/shaders.js @@ -6,7 +6,7 @@ var vertShader = "attribute vec4 ps_Color;" + "uniform float ps_PointSize;" + -"uniform vec3 XBPS_attenuation;" + +"uniform vec3 ps_Attenuation;" + "uniform vec3 lightPos;" + "uniform bool reflection;"+ @@ -15,25 +15,10 @@ var vertShader = "uniform mat4 ps_ProjectionMatrix;" + "uniform mat4 ps_NormalMatrix;" + -"float dirLight(in vec3 norm){" + -" vec3 light = vec3(0.0, 1.0, 0.0);" + -" return max(dot(light, norm), 0.0);" + -"}" + - -"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal, in vec3 eye ) {" + - // Get the vector from the light to the vertex +"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal) {" + " vec3 VP = lightPos - ecPos;" + - -// Get the distance from the current vector to the light position -" float d = length( VP ); " + - -// Normalize the light ray so it can be used in the dot product operation. " VP = normalize( VP );" + - -" float attenuation = 1.0 / ( 1.0 + ( d ) + ( d * d ));" + " float nDotVP = max( 0.0, dot( vertNormal, VP ));" + -" vec3 halfVector = normalize( VP + eye );" + -" float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" + " col += vec3(1.0, 1.0, 1.0) * nDotVP;" + "}" + @@ -42,10 +27,9 @@ var vertShader = " vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" + " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" + -" vec3 eye = vec3( 0.0, 0.0, 1.0 );" + " vec3 col = vec3(0.0, 0.0, 0.0);" + -" PointLight(col, ecPos, transNorm, eye);" + +" PointLight(col, ecPos, transNorm);" + " frontColor = ps_Color * vec4(col, 1.0);" + @@ -57,17 +41,11 @@ var vertShader = " }" + " float dist = length( ecPos4 );" + -" float attn = XBPS_attenuation[0] + " + -" (XBPS_attenuation[1] * dist) + " + -" (XBPS_attenuation[2] * dist * dist);" + - -" if(attn > 0.0){" + -" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + -" }" + -" else{" + -" gl_PointSize = 1.0;" + -" }"+ +" float attn = ps_Attenuation[0] + " + +" (ps_Attenuation[1] * dist) + " + +" (ps_Attenuation[2] * dist * dist);" + +" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + " gl_Position = ps_ProjectionMatrix * ecPos4;" + "}"; diff --git a/tests/user_shader/user_shader.js b/tests/user_shader/user_shader.js index b18b928..5f7433f 100644 --- a/tests/user_shader/user_shader.js +++ b/tests/user_shader/user_shader.js @@ -1,63 +1,54 @@ -var mickey = null; -var ps = null; -var i = 0.0; +var ps, mickey; +var rotY = 0.0; +var rotX = 0.3; -var reflectionShader; -var objectShader; -var toggle = false; - -function keyDown(){ -} +var progObj; +var fps_label; function render() { ps.clear(); - var center = [-1.1931838002830566,0.2915859633078008,-0.6363419673371361]; - - i += 0.05; + // spin object + rotY += 0.01; // Draw reflection ps.uniformi("reflection", true); ps.uniformf("lightPos", [0, -50, 10]); ps.uniformf("uReflection", [.15, .15, .3, .8]); ps.pushMatrix(); - ps.translate(0, 20, -80); - ps.rotateX(1.0); + ps.translate(0, 10, -80); + ps.rotateX(rotX); ps.translate(0, -55, 0); ps.scale(1, -1, 1); - ps.rotateY(i); + ps.rotateY(rotY); ps.render(mickey); ps.popMatrix(); // Draw object ps.uniformi("reflection", false); ps.uniformf("lightPos", [0, 50, 10]); - ps.uniformf("uReflection", [1,1,1,1]); + ps.uniformf("uReflection", [1, 1, 1, 1]); ps.pushMatrix(); - ps.translate(0, 20, -80); - ps.rotateX(1.0); - ps.rotateY(i); + ps.translate(0, 10, -80); + ps.rotateX(rotX); + ps.rotateY(rotY); ps.render(mickey); ps.popMatrix(); - var fps = Math.floor(ps.frameRate); - var fps_label = document.getElementById("fps"); - fps_label.innerHTML = fps + " FPS"; + fps_label.innerHTML = Math.floor(ps.frameRate) + " FPS"; } function start(){ + fps_label = document.getElementById("fps"); + ps = new PointStream(); ps.setup(document.getElementById('canvas')); - objectShader = ps.createProgram(vertShader, fragShader); - ps.useProgram(objectShader); - ps.pointSize(10); - ps.onRender = render; - ps.onKeyDown = keyDown; - - //ps.background([0, 0, 0, 0.7]); - //ps.background([0.5, 0.5, 0.5, 1.0]); - ps.background([1.0, 1.0, 1.0, 1.0]); + ps.background([1, 1, 1, 1]); + progObj = ps.createProgram(vertShader, fragShader); + ps.useProgram(progObj); + ps.pointSize(10); + mickey = ps.load("../../clouds/mickey.asc"); } diff --git a/tests/user_shader_2/shaders.js b/tests/user_shader_2/shaders.js index 41fb99c..61d5f07 100644 --- a/tests/user_shader_2/shaders.js +++ b/tests/user_shader_2/shaders.js @@ -16,7 +16,7 @@ var cel_vertShader = "attribute vec4 ps_Color;" + "uniform float ps_PointSize;" + -"uniform vec3 XBPS_attenuation;" + +"uniform vec3 ps_Attenuation;" + "uniform mat4 ps_ModelViewMatrix;" + "uniform mat4 ps_ProjectionMatrix;" + @@ -35,24 +35,18 @@ var cel_vertShader = " float intensity;" + " PointLight(intensity, vec3(ecPos4), transNorm);" + -" if(intensity <= 0.6){ intensity = 0.5;}" + +" if (intensity <= 0.6){ intensity = 0.6;}" + " else if(intensity <= 0.8){ intensity = 0.8;}" + " else if(intensity <= 1.0){ intensity = 1.0;}" + " frontColor = ps_Color * vec4(intensity, intensity, intensity, 1.0);" + " float dist = length( ecPos4 );" + -" float attn = XBPS_attenuation[0] + " + -" (XBPS_attenuation[1] * dist) + " + -" (XBPS_attenuation[2] * dist * dist);" + - -" if(attn > 0.0){" + -" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + -" }" + -" else{" + -" gl_PointSize = 1.0;" + -" }"+ +" float attn = ps_Attenuation[0] + " + +" (ps_Attenuation[1] * dist) + " + +" (ps_Attenuation[2] * dist * dist);" + +" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + " gl_Position = ps_ProjectionMatrix * ecPos4;" + "}"; @@ -74,7 +68,7 @@ var scan_vertShader = "attribute vec4 ps_Color;" + "uniform float ps_PointSize;" + -"uniform vec3 XBPS_attenuation;" + +"uniform vec3 ps_Attenuation;" + "uniform mat4 ps_ModelViewMatrix;" + "uniform mat4 ps_ProjectionMatrix;" + @@ -85,16 +79,10 @@ var scan_vertShader = " vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" + " float dist = length( ecPos4 );" + -" float attn = XBPS_attenuation[0] + " + -" (XBPS_attenuation[1] * dist) + " + -" (XBPS_attenuation[2] * dist * dist);" + - -" if(attn > 0.0){" + -" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + -" }" + -" else{" + -" gl_PointSize = 1.0;" + -" }"+ +" float attn = ps_Attenuation[0] + " + +" (ps_Attenuation[1] * dist) + " + +" (ps_Attenuation[2] * dist * dist);" + +" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" + " gl_Position = ps_ProjectionMatrix * ecPos4;" + "}"; diff --git a/tests/verts_cols/verts_colors.js b/tests/verts_cols/verts_colors.js index 172a92c..c92e195 100644 --- a/tests/verts_cols/verts_colors.js +++ b/tests/verts_cols/verts_colors.js @@ -1,13 +1,12 @@ var ps, pointCloud; function render() { - ps.translate(0, 0, -30); - var c = pointCloud.getCenter(); - ps.translate(-c[0], -c[1], -c[2]); + ps.translate(-c[0], -c[1], -30-c[2]); ps.clear(); ps.render(pointCloud); + if(pointCloud.getStatus() === 3){ ps.onRender = function(){}; } @@ -16,8 +15,10 @@ function render() { function start(){ ps = new PointStream(); ps.setup(document.getElementById('canvas')); + ps.onRender = render; + ps.background([0, 0, 0, 0.5]); ps.pointSize(5); - ps.onRender = render; + pointCloud = ps.load("../../clouds/mickey_verts_cols.asc"); } diff --git a/tests/verts_norms/verts_norms.js b/tests/verts_norms/verts_norms.js index 7123447..d9ee6be 100644 --- a/tests/verts_norms/verts_norms.js +++ b/tests/verts_norms/verts_norms.js @@ -1,10 +1,8 @@ var ps, acorn; function render() { - ps.translate(0, 0, -20); - var c = acorn.getCenter(); - ps.translate(-c[0], -c[1], -c[2]); + ps.translate(-c[0], -c[1], -20-c[2]); ps.clear(); ps.render(acorn); @@ -17,10 +15,10 @@ function render() { function start(){ ps = new PointStream(); ps.setup(document.getElementById('canvas')); + ps.onRender = render; ps.background([0, 0, 0, 0.5]); ps.pointSize(5); - ps.onRender = render; acorn = ps.load("../../clouds/acorn_verts_norms.asc"); } diff --git a/tests/xhr_timing_test/mickey.js b/tests/xhr_timing_test/mickey.js index ae5792c..af3418c 100644 --- a/tests/xhr_timing_test/mickey.js +++ b/tests/xhr_timing_test/mickey.js @@ -3,28 +3,6 @@ var ps, mickey; var XHR_Timer; var XHR_TimerDone = false; -var buttonDown = false; -var zoomed = -50; -var rot =[0,0]; -var curCoords = [0,0]; - -var size = 500; - -function zoom(amt){ - zoomed += amt * 2; - size += amt * 10; -} - -function mousePressed(){ - curCoords[0] = ps.mouseX; - curCoords[1] = ps.mouseY; - buttonDown = true; -} - -function mouseReleased(){ - buttonDown = false; -} - function render() { if(mickey.status === 3){ @@ -32,46 +10,25 @@ function render() { if(XHR_TimerDone === false){ document.getElementById('XHR_Timer').innerHTML = (new Date() - XHR_Timer)/1000 + " seconds"; XHR_TimerDone = true; + ps.onRender = function(){}; } - var deltaX = ps.mouseX - curCoords[0]; - var deltaY = ps.mouseY - curCoords[1]; - - if(buttonDown){ - rot[0] += deltaX / 250; - rot[1] += deltaY / 250; - curCoords[0] = ps.mouseX; - curCoords[1] = ps.mouseY; - } - - // transform point cloud - ps.translate(0, 0, zoomed); - - ps.rotateY(rot[0]); - ps.rotateX(rot[1]); - var c = mickey.getCenter(); - - ps.translate(-c[0], -c[1], -c[2]); - - ps.clear(); + ps.translate(-c[0], -c[1], -50-c[2]); + ps.render(mickey); } } function start(){ ps = new PointStream(); - ps.setup(document.getElementById('canvas')); + ps.onRender = render; ps.pointSize(5); ps.background([.5, .5, .5, 1]); + ps.clear(); - ps.onRender = render; - ps.onMouseScroll = zoom; - ps.onMousePressed = mousePressed; - ps.onMouseReleased = mouseReleased; - XHR_Timer = new Date(); mickey = ps.load("../../clouds/mickey.asc"); } \ No newline at end of file diff --git a/tutorial/notes.txt b/tutorial/notes.txt new file mode 100644 index 0000000..ed4445f --- /dev/null +++ b/tutorial/notes.txt @@ -0,0 +1,44 @@ +Using the internal XB PointStream parser and shader + +If you decide to use the internal XB PointStream parser and shader, you can have a script displaying your point cloud in about 10 lines of JavaScript. However, you will be required to send in your point cloud as an .ASC file. Also, the built-in shader will only draw the minimum necessary for you point cloud, that is, it will only render vertex positions and colors. + + + + +Using the internal XB PointStream parser with a custom shader + +If you decide to use the internal .ASC parser and write a custom shader, you'll need to ensure your vertex shader uses the correct uniform and attribute variable names which XB PointStream refers to. + +The built-in .ASC parser only reads in vertex position and colors, so you must use the following names to refer to those attributes: + +vec3 ps_Vertex +vec4 ps_Color + +XB PointStream will refer to the following uniforms: + +For transformations: +mat4 ps_ModelViewMatrix +mat4 ps_ProjectionMatrix + +For point size: +float ps_PointSize +vec3 ps_Attenuation + + + + + +Using the internal XB PointStream shader with a custom parser + +If your point cloud is in a format other than .ASC, but you want to use the built-in shader, you'll need to make sure your parser writes to the correct attribute names +*insert URL to example* + +"ps_Vertex" +"ps_Color" + +Your script must also register your parser with XB PointStream with: +ps.registerParser("XYZ", Your_XYZ_Parser_Name); + + + +Using a custom shader and parser \ No newline at end of file diff --git a/tutorial/parser_template.js b/tutorial/parser_template.js new file mode 100644 index 0000000..6b7fabe --- /dev/null +++ b/tutorial/parser_template.js @@ -0,0 +1,63 @@ +/* +*/ + +var Your_Parser_Name = (function() { + + function Your_Parser_Name(config) { + + this.__defineGetter__("version", function(){ + return /* !! */; + }); + + this.__defineGetter__("numParsedPoints", function(){ + return /* !! */; + }); + + this.__defineGetter__("numTotalPoints", function(){ + return /* !! */; + }); + + this.__defineGetter__("progress", function(){ + return /* !! */; + }); + + this.__defineGetter__("fileSize", function(){ + return /* !! */; + }); + + /** + @param path Path to the resource + */ + this.load = function(path){ + pathToFile = path; + + AJAX = new XMLHttpRequest(); + + AJAX.parser = this; + + AJAX.onloadstart = function(evt){ + start(AJAX.parser); + }; + + AJAX.onload = function(evt){ + end(AJAX.parser); + } + + AJAX.parseChunk = function(chunkData){ + var attributes = {}; + attributes["ps_Vertex"] = /* !! */; + attributes["ps_Color"] = /* !! */; + + parse(AJAX.parser, attributes); + }; + + AJAX.onprogress = function(evt){ + }; + + // open an asynchronous request to the path + AJAX.open("GET", path, true); + AJAX.send(null); + }; + } + return Your_Parser_Name; +}());