From 0f31002ca696c1ef303d2926a504afd27305e94f Mon Sep 17 00:00:00 2001 From: hwc487 Date: Wed, 4 Apr 2012 05:52:54 -0700 Subject: Added Flag material --- assets/shaders/Flag.vert.glsl | 19 +- js/lib/geom/rectangle.js | 46 +-- js/lib/geom/shape-primitive.js | 130 +++++++ js/lib/rdge/materials/flag-material.js | 6 + js/lib/rdge/materials/material.js | 5 + js/lib/rdge/materials/twist-vert-material.js | 1 + js/lib/rdge/texture.js | 527 +++++++++++++-------------- js/models/materials-model.js | 4 +- 8 files changed, 437 insertions(+), 301 deletions(-) diff --git a/assets/shaders/Flag.vert.glsl b/assets/shaders/Flag.vert.glsl index 9da0ee1c..a5e8b2f7 100644 --- a/assets/shaders/Flag.vert.glsl +++ b/assets/shaders/Flag.vert.glsl @@ -27,22 +27,21 @@ uniform mat4 u_worldMatrix; // varying variables varying vec2 v_uv; + void main() { - float pi = 3.14159; - float angle = mod(u_time, pi)*2.0; + float pi = 3.14159; + float angle = u_time; - vec3 v = a_pos; v_uv = texcoord; - vec2 pos = texcoord; - float tmp = pos.x; pos.x = pos.y; pos.y = tmp; - pos.x = pos.x * 1.0*pi * u_waveWidth; - pos.y = pos.y * 1.0*pi * u_waveWidth; + float x = 2.0*pi*texcoord.x/u_waveWidth; + float y = 2.0*pi*texcoord.y; - v.z = sin( pos.x + angle); - v.z += sin( pos.y/2.0 + angle); - v.z *= v.y * 0.09 * u_waveHeight; + vec3 v = a_pos; + v.z = sin( x + angle ) - 2.0*u_waveHeight; + v.z += sin( 0.2*y + angle); + v.z *= x * 0.09 * u_waveHeight; gl_Position = u_projMatrix * u_mvMatrix * vec4(v,1.0) ; } diff --git a/js/lib/geom/rectangle.js b/js/lib/geom/rectangle.js index e511d5f4..51947ff1 100755 --- a/js/lib/geom/rectangle.js +++ b/js/lib/geom/rectangle.js @@ -943,13 +943,13 @@ RectangleFill.create = function( rectCtr, width, height, tlRad, blRad, brRad, } //refine the mesh for vertex deformations -// if (material) { -// if (material.hasVertexDeformation()) { -// var paramRange = material.getVertexDeformationRange(); -// var tolerance = material.getVertexDeformationTolerance(); -// nVertices = ShapePrimitive.refineMesh( this.vertices, this.normals, this.uvs, this.indices, nVertices, paramRange, tolerance ); -// } -// } + if (material) { + if (material.hasVertexDeformation()) { + var paramRange = material.getVertexDeformationRange(); + var tolerance = material.getVertexDeformationTolerance(); + nVertices = ShapePrimitive.refineMesh( this.vertices, this.normals, this.uvs, this.indices, nVertices, paramRange, tolerance ); + } + } // create the RDGE primitive return ShapePrimitive.create(this.vertices, this.normals, this.uvs, this.indices, g_Engine.getContext().renderer.TRIANGLES, nVertices); @@ -1175,13 +1175,13 @@ RectangleStroke.create = function( rectCtr, width, height, strokeWidth, tlRad, } //refine the mesh for vertex deformations -// if (material) { -// if (material.hasVertexDeformation()) { -// var paramRange = material.getVertexDeformationRange(); -// var tolerance = material.getVertexDeformationTolerance(); -// nVertices = ShapePrimitive.refineMesh( this.vertices, this.normals, this.uvs, this.indices, nVertices, paramRange, tolerance ); -// } -// } + if (material) { + if (material.hasVertexDeformation()) { + var paramRange = material.getVertexDeformationRange(); + var tolerance = material.getVertexDeformationTolerance(); + nVertices = ShapePrimitive.refineMesh( this.vertices, this.normals, this.uvs, this.indices, nVertices, paramRange, tolerance ); + } + } // create the RDGE primitive return ShapePrimitive.create(this.vertices, this.normals, this.uvs, this.indices, g_Engine.getContext().renderer.TRIANGLES, nVertices); @@ -1259,15 +1259,15 @@ RectangleGeometry.create = function( ctr, width, height, material ) { RectangleGeometry.pushIndices( 0, 3, 2 ); //refine the mesh for vertex deformations -// if (material) -// { -// if (material.hasVertexDeformation()) -// { -// var paramRange = material.getVertexDeformationRange(); -// var tolerance = material.getVertexDeformationTolerance(); -// nVertices = ShapePrimitive.refineMesh( this.vertices, this.normals, this.uvs, this.indices, nVertices, paramRange, tolerance ); -// } -// } + if (material) + { + if (material.hasVertexDeformation()) + { + var paramRange = material.getVertexDeformationRange(); + var tolerance = material.getVertexDeformationTolerance(); + nVertices = ShapePrimitive.refineMesh( this.vertices, this.normals, this.uvs, this.indices, nVertices, paramRange, tolerance ); + } + } // create the RDGE primitive return ShapePrimitive.create(this.vertices, this.normals, this.uvs, this.indices, g_Engine.getContext().renderer.TRIANGLES, nVertices); diff --git a/js/lib/geom/shape-primitive.js b/js/lib/geom/shape-primitive.js index bf0087b2..44a7aa52 100644 --- a/js/lib/geom/shape-primitive.js +++ b/js/lib/geom/shape-primitive.js @@ -49,6 +49,136 @@ ShapePrimitive.create = function(coords, normals, uvs, indices, primType, ver return prim; }; +ShapePrimitive.getMeshBounds = function( verts, nVerts ) +{ + if (!verts || (nVerts <= 0)) return null; + + var bounds = [verts[0], verts[1], verts[2], verts[0], verts[1], verts[2]]; + var index = 3; + for (var i=1; i bounds[3]) bounds[3] = x; + if (y < bounds[1]) bounds[1] = y; + else if (y > bounds[4]) bounds[4] = y; + if (z < bounds[2]) bounds[2] = z; + else if (z > bounds[5]) bounds[5] = z; + } + + return bounds; +}; + +ShapePrimitive.refineMesh = function( verts, norms, uvs, indices, nVertices, paramRange, tolerance ) +{ + var oldVrtCount = nVertices; + + // get the param range + var pUMin = paramRange[0], pVMin = paramRange[1], + pUMax = paramRange[2], pVMax = paramRange[3]; + var iTriangle = 0; + var nTriangles = indices.length/3; + var index = 0; + while (iTriangle < nTriangles) + { + // get the indices of the 3 vertices + var i0 = indices[index], + i1 = indices[index+1], + i2 = indices[index+2]; + + // get the uv values + //var vrtIndex = 3*iTriangle; + var iuv0 = 2 * i0, + iuv1 = 2 * i1, + iuv2 = 2 * i2; + var u0 = uvs[iuv0], v0 = uvs[iuv0+1], + u1 = uvs[iuv1], v1 = uvs[iuv1+1], + u2 = uvs[iuv2], v2 = uvs[iuv2+1]; + + // find the u and v range + var uMin = u0, vMin = v0; + if (u1 < uMin) uMin = u1; if (v1 < vMin) vMin = v1; + if (u2 < uMin) uMin = u2; if (v2 < vMin) vMin = v2; + var uMax = u0, vMax = v0; + if (u1 > uMax) uMax = u1; if (v1 > vMax) vMax = v1; + if (u2 > uMax) uMax = u2; if (v2 > vMax) vMax = v2; + + // if the parameter range of the triangle is outside the + // desired parameter range, advance to the next polygon and continue + if ((uMin > pUMax) || (uMax < pUMin) || (vMin > pVMax) || (vMax < pVMin)) + { + // go to the next triangle + iTriangle++; + index += 3; + } + else + { + // check thesize of the triangle in uv space. If small enough, advance + // to the next triangle. If not small enough, split the triangle into 3; + var du = uMax - uMin, dv = vMax - vMin; + if ((du < tolerance) && (dv < tolerance)) + { + iTriangle++; + index += 3; + } + else // split the triangle into 4 parts + { + //calculate the position of the new vertex + var iPt0 = 3 * i0, + iPt1 = 3 * i1, + iPt2 = 3 * i2; + var x0 = verts[iPt0], y0 = verts[iPt0+1], z0 = verts[iPt0+2], + x1 = verts[iPt1], y1 = verts[iPt1+1], z1 = verts[iPt1+2], + x2 = verts[iPt2], y2 = verts[iPt2+1], z2 = verts[iPt2+2]; + + // calculate the midpoints of the edges + var xA = (x0 + x1)/2.0, yA = (y0 + y1)/2.0, zA = (z0 + z1)/2.0, + xB = (x1 + x2)/2.0, yB = (y1 + y2)/2.0, zB = (z1 + z2)/2.0, + xC = (x2 + x0)/2.0, yC = (y2 + y0)/2.0, zC = (z2 + z0)/2.0; + + // calculate the uv values of the new coordinates + var uA = (u0 + u1)/2.0, vA = (v0 + v1)/2.0, + uB = (u1 + u2)/2.0, vB = (v1 + v2)/2.0, + uC = (u2 + u0)/2.0, vC = (v2 + v0)/2.0; + + // calculate the normals for the new points + var nx0 = norms[iPt0], ny0 = norms[iPt0+1], nz0 = norms[iPt0+2], + nx1 = norms[iPt1], ny1 = norms[iPt1+1], nz1 = norms[iPt1+2], + nx2 = norms[iPt2], ny2 = norms[iPt2+1], nz2 = norms[iPt2+2]; + var nxA = (nx0 + nx1), nyA = (ny0 + ny1), nzA = (nz0 + nz1); var nrmA = VecUtils.vecNormalize(3, [nxA, nyA, nzA], 1.0 ), + nxB = (nx1 + nx2), nyB = (ny1 + ny2), nzB = (nz1 + nz2); var nrmB = VecUtils.vecNormalize(3, [nxB, nyB, nzB], 1.0 ), + nxC = (nx2 + nx0), nyC = (ny2 + ny0), nzC = (nz2 + nz0); var nrmC = VecUtils.vecNormalize(3, [nxC, nyC, nzC], 1.0 ); + + // push everything + verts.push(xA); verts.push(yA); verts.push(zA); + verts.push(xB); verts.push(yB); verts.push(zB); + verts.push(xC); verts.push(yC); verts.push(zC); + uvs.push(uA), uvs.push(vA); + uvs.push(uB), uvs.push(vB); + uvs.push(uC), uvs.push(vC); + norms.push(nrmA[0]); norms.push(nrmA[1]); norms.push(nrmA[2]); + norms.push(nrmB[0]); norms.push(nrmB[1]); norms.push(nrmB[2]); + norms.push(nrmC[0]); norms.push(nrmC[1]); norms.push(nrmC[2]); + + // split the current triangle into 4 + indices[index+1] = nVertices; indices[index+2] = nVertices+2; + indices.push(nVertices); indices.push(i1); indices.push(nVertices+1); nTriangles++; + indices.push(nVertices+1); indices.push(i2); indices.push(nVertices+2); nTriangles++; + indices.push(nVertices); indices.push(nVertices+1); indices.push(nVertices+2); nTriangles++; + nVertices += 3; + + // by not advancing 'index', we examine the first of the 3 triangles generated above + } + } + } + + console.log( "refine mesh vertex count " + oldVrtCount + " => " + nVertices ); + return nVertices; +}; + + if (typeof exports === "object") { exports.ShapePrimitive = ShapePrimitive; } \ No newline at end of file diff --git a/js/lib/rdge/materials/flag-material.js b/js/lib/rdge/materials/flag-material.js index 77991a8c..8d4d1ee3 100644 --- a/js/lib/rdge/materials/flag-material.js +++ b/js/lib/rdge/materials/flag-material.js @@ -23,6 +23,8 @@ var FlagMaterial = function FlagMaterial() { this._defaultWaveWidth = 1.0; this._defaultWaveHeight = 1.0; + this._hasVertexDeformation = true; + /////////////////////////////////////////////////////////////////////// // Properties /////////////////////////////////////////////////////////////////////// @@ -37,6 +39,10 @@ var FlagMaterial = function FlagMaterial() { this._propValues[ this._propNames[1] ] = this._defaultWaveWidth; this._propValues[ this._propNames[2] ] = this._defaultWaveHeight; + // a material can be animated or not. default is not. + // Any material needing continuous rendering should override this method + this.isAnimated = function() { return true; }; + /////////////////////////////////////////////////////////////////////// // Methods /////////////////////////////////////////////////////////////////////// diff --git a/js/lib/rdge/materials/material.js b/js/lib/rdge/materials/material.js index 13251ce8..a81ca18f 100755 --- a/js/lib/rdge/materials/material.js +++ b/js/lib/rdge/materials/material.js @@ -38,6 +38,11 @@ var Material = function GLMaterial( world ) { this._shader = null; this._materialNode = null; + // vertex deformation variables + this._hasVertexDeformation = false; + this._vertexDeformationRange = [0, 0, 1, 1]; // (xMin, yMin, xMax, yMax) + this._vertexDeformationTolerance = 0.02; + /////////////////////////////////////////////////////////////////////// // Property Accessors /////////////////////////////////////////////////////////////////////// diff --git a/js/lib/rdge/materials/twist-vert-material.js b/js/lib/rdge/materials/twist-vert-material.js index 2d2cdcc5..802690a2 100644 --- a/js/lib/rdge/materials/twist-vert-material.js +++ b/js/lib/rdge/materials/twist-vert-material.js @@ -36,6 +36,7 @@ function TwistVertMaterial() this.getShaderName = function() { return this._shaderName; } this.isAnimated = function() { return true; } + this.hasVertexDeformation = function() { return this._hasVertexDeformation; } this._hasVertexDeformation = true; this._vertexDeformationTolerance = 0.02; // should be a property diff --git a/js/lib/rdge/texture.js b/js/lib/rdge/texture.js index 83509f80..2e76f2c0 100644 --- a/js/lib/rdge/texture.js +++ b/js/lib/rdge/texture.js @@ -12,264 +12,259 @@ var Material = require("js/lib/rdge/materials/material").Material; /////////////////////////////////////////////////////////////////////// function Texture( dstWorld, texMapName, wrap, mips ) { - /////////////////////////////////////////////////////////////////////// - // Instance variables - /////////////////////////////////////////////////////////////////////// - this._texture; - - // texture attributes - this._texMapName = texMapName.slice(); - - // set default values for wrap and mips - if (wrap === undefined) - wrap = "REPEAT"; - if (mips === undefined) - mips = true; - this._wrap = wrap; - this._mips = mips; + /////////////////////////////////////////////////////////////////////// + // Instance variables + /////////////////////////////////////////////////////////////////////// + this._texture; + + // texture attributes + this._texMapName = texMapName.slice(); + + // set default values for wrap and mips + if (wrap === undefined) + wrap = "REPEAT"; + if (mips === undefined) + mips = true; + this._wrap = wrap; + this._mips = mips; // the canvas generating the texture map (if there is one) - this._srcCanvas; - this._srcWorld; - - // cache whether or not the source is animated - this._isAnimated = false; - - // the destination world that will use the texture map - this._dstWorld = dstWorld; - - /////////////////////////////////////////////////////////////////////// - // Property Accessors - /////////////////////////////////////////////////////////////////////// - this.getTexture = function() { return this._texture; } - - this.setSrcWorld = function(w) { this._srcWorld = w; } - this.getSrcWorld = function() { return this._srcWorld; } - - this.setDstWorld = function(w) { this._dstWorld = w; } - this.getDstWorld = function() { return this._dstWorld; } - - this.isAnimated = function() { return this._isAnimated; } - - /////////////////////////////////////////////////////////////////////// - // Methods - /////////////////////////////////////////////////////////////////////// - - this.init = function() - { - // determine if the source is a canvas or an image file - var viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils; - var root = viewUtils.application.ninja.currentDocument.documentRoot; - var srcCanvas = this.findCanvas( this._texMapName, root ); - if (srcCanvas) - { - this._srcCanvas = srcCanvas; - if (srcCanvas.elementModel && srcCanvas.elementModel.shapeModel && srcCanvas.elementModel.shapeModel.GLWorld) - { - this._srcWorld = srcCanvas.elementModel.shapeModel.GLWorld; - - // add a notifier to the world - this._srcWorld.addListener( this, this.worldCallback, { srcWorld: this._srcWorld } ); - - // check if the source is animated - if (srcCanvas.elementModel && srcCanvas.elementModel.shapeModel && srcCanvas.elementModel.shapeModel.GLWorld) - this._isAnimated = this._srcWorld._hasAnimatedMaterials; - } - - this.loadFromCanvas(); - } - else - { - this.loadFromFile(); - } - } - - this.worldCallback = function( type, callbackObj, calleeData, callerData ) - { - console.log( "texture callback, type: " + type ); - if (calleeData.srcWorld) - { - var srcWorld = calleeData.srcWorld; - var notifier = srcWorld._notifier; - var texture = this.callbackObj; - if (texture) - { - switch (type) - { - case notifier.OBJECT_DELETE: - break; - - case notifier.OBJECT_REINSTANTIATE: - break; - - case notifier.OBJECT_CHANGE: - if (!texture.isAnimated()) - texture.rerender(); - texture.getDstWorld().restartRenderLoop(); - break; - - default: - throw new Exception( "unrecognized texture callback type: " + type ); - break; - } - } - } - } - - this.loadFromFile = function() - { - var tex = this._texture; - this._srcCanvas = null; - - // only load if something has changed - if (this._texMapName !== texMapName) // does RDGE allow us to change wrap or mips? - { - var texMapName = this._texMapName; - var wrap = this._wrap; - var mips = this._mips; - - var dstWorld = this.getDstWorld(); - if (dstWorld) - { - var renderer = dstWorld.getRenderer(); - tex = renderer.getTextureByName(texMapName, wrap, mips ); - this._texture = tex; - dstWorld.textureToLoad( tex ); - } - } - - return tex; - } - - var __texCounter = 0; - this.loadFromCanvas = function() - { - var srcCanvas = this._srcCanvas; - var wrap = this._wrap; - var mips = this._mips; - - this._texMapName = "GLTexture_" + __texCounter; - __texCounter++; - - // create the texture - var world = this.getDstWorld(); - tex = world.getGLContext().createTexture(); - this._texture = tex; - tex.texparams = new _texparams(wrap, mips); // defined in renderer.js - tex.image = new Image; - - // create the canvas and context to render into - var doc = srcCanvas.ownerDocument; - this._renderCanvas = doc.createElement("canvas"); - - // cache whether this is a 2D canvas or 3D canvas - var srcCtx = srcCanvas.getContext("2d"); - this._is3D = false; - if (!srcCtx) this._is3D = true; - - this.rerender(); - - return tex; - } - - this.rerender = function() - { - if (!this._srcCanvas) - { - console.log( " no source canvas in GLTexture.rerender" ); - return; - } - var srcCanvas = this._srcCanvas; - - var world = this.getDstWorld(); - if (!world) - { - console.log( "no world in GLTexture.rerender" ); - return; - } - var renderer = world.getRenderer(); - - var imageData; - var width = srcCanvas.width, height = srcCanvas.height; - if (!this.isPowerOfTwo(width) || !this.isPowerOfTwo(height)) - { - width = this.nextLowerPowerOfTwo( width ); - height = this.nextLowerPowerOfTwo( height ); - } - - // create a canvas to be used as the image for the texture map - var renderCanvas = this._renderCanvas; - if (!renderCanvas) - { - console.log( "no render canvas in GLTexture.rerender" ); - return; - } - renderCanvas.width = width; - renderCanvas.height = height; - var renderCtx = renderCanvas.getContext("2d"); - - // create the texture - var tex = this._texture; - if (!tex) - { - console.log( "no texture in GLTexture.rerender" ); - return; - } - - var srcCtx; - if (!this._is3D) - { - srcCtx = srcCanvas.getContext("2d"); - imageData = srcCtx.getImageData( 0, 0, width, height ); - renderCtx.putImageData( imageData, 0, 0 ); - } - else - { - srcCtx = srcCanvas.getContext("experimental-webgl"); - if (srcCtx) - { - renderCtx.drawImage(srcCanvas, 0, 0); -// var data = new Uint8Array(width * height * 4); -// srcCtx.readPixels(0, 0, width, height, srcCtx.RGBA, srcCtx.UNSIGNED_BYTE, data); -// imageData = renderCtx.createImageData(width, height); -// var nBytes = width*height*4; -// for (var i=0; i> i; - } - return x + 1; - } + this.nextHighestPowerOfTwo = function(x) + { + --x; + for (var i = 1; i < 32; i <<= 1) { + x = x | x >> i; + } + return x + 1; + } - this.nextLowerPowerOfTwo = function(x) - { - return this.nextHighestPowerOfTwo(x) >> 1; - } - - this.findCanvas = function( id, elt ) - { - if (elt.id && elt.id === id) - return elt; + this.nextLowerPowerOfTwo = function(x) + { + return this.nextHighestPowerOfTwo(x) >> 1; + } + + this.findCanvas = function( id, elt ) + { + if (elt.id && elt.id === id) + return elt; if (elt.children) { @@ -278,22 +273,22 @@ function Texture( dstWorld, texMapName, wrap, mips ) { var child = elt.children[i]; var canvas = this.findCanvas( id, child ); - if (canvas) return canvas; + if (canvas) return canvas; } } } - /* - this.findWorld = function( id, elt ) - { - if (elt.id && elt.id === id) - { - if (elt.elementModel && elt.elementModel.shapeModel && elt.elementModel.shapeModel.GLWorld) - { - var world = elt.elementModel.shapeModel.GLWorld; - return world; - } - } + /* + this.findWorld = function( id, elt ) + { + if (elt.id && elt.id === id) + { + if (elt.elementModel && elt.elementModel.shapeModel && elt.elementModel.shapeModel.GLWorld) + { + var world = elt.elementModel.shapeModel.GLWorld; + return world; + } + } if (elt.children) { @@ -302,7 +297,7 @@ function Texture( dstWorld, texMapName, wrap, mips ) { var child = elt.children[i]; var world = this.findWorld( id, child ); - if (world) return world; + if (world) return world; } } } @@ -313,7 +308,7 @@ function Texture( dstWorld, texMapName, wrap, mips ) } if (typeof exports === "object") { - exports.Texture = Texture; + exports.Texture = Texture; } diff --git a/js/models/materials-model.js b/js/models/materials-model.js index 97a48f5a..b4595bd6 100755 --- a/js/models/materials-model.js +++ b/js/models/materials-model.js @@ -118,7 +118,7 @@ exports.MaterialsModel = Montage.create(Component, { value: function (materialName) { var index = this.getIndexOfMaterial(materialName); if(index !== -1) { - return this._materials[index].dup(); + return this._materials[index]; } } }, @@ -129,7 +129,7 @@ exports.MaterialsModel = Montage.create(Component, { { var index = this.getIndexOfMaterialByShader( shaderName ); if (index >= 0) - return this._materials[index].dup(); + return this._materials[index]; } }, -- cgit v1.2.3