Tessellation

 Unity で距離に応じたテッセレーションを行ってみた - 凹みTips (hecomi.com)


http://tinkering.ee/unity/asset-unity-refractive-shader/


https://github.com/MaxwellGengYF/Unity-Tessellation-PBR-Shaders

Sample A

/* // // Base Classes to easy WebGL lists management // */ function myObject3D(){ var Vertices = []; var Normals = []; var Tangents = []; var TexCoords = []; var TriIndex = []; var IsEdge = []; var NbTriangles = 0; } myObject3D.prototype.Clear = function() { this.Vertices = []; this.Normals = []; this.Tangents = []; this.TexCoords = []; this.TriIndex = []; this.IsEdge = []; this.NbTriangles = 0; } myObject3D.prototype.AppendLists = function(b,lastNbOfPoints ) { for (var k=0;k<b.Vertices.length;k++){ this.Vertices.push(b.Vertices[k]); this.Normals.push(b.Normals[k]); } for (var k=0;k<b.Tangents.length;k++){ this.Tangents.push(b.Tangents[k]); } for (var k=0;k<b.TexCoords.length;k++){ this.TexCoords.push(b.TexCoords[k]); } for (var k=0;k<b.IsEdge.length;k++){ this.IsEdge.push(b.IsEdge[k]); } var nbPts = lastNbOfPoints; for (var k=0;k<b.TriIndex.length;k++){ var tmp = b.TriIndex[k]; tmp+=(nbPts); //console.log('tmp='+tmp); this.TriIndex.push(tmp); } } // look up base triangle per base triangle in uv space // among the edges and not the end of segments myObject3D.prototype.Snap = function(delta) { var TexCoord = []; for (var j=0;j<this.TexCoords.length/2;j++){ TexCoord.push(this.TexCoords[2*j]); TexCoord.push(this.TexCoords[2*j+1]); if (this.IsEdge[j]==0){ //TexCoord[2*j] = 0; //TexCoord[2*j+1] = 0; this.Vertices[3*j] = 0; this.Vertices[3*j+1] = 0; this.Vertices[3*j+2] = 0; } } /* for (var j=0;j<this.TexCoords.length/2;j++){ var vJx=this.TexCoords[2*j]; var vJy=this.TexCoords[2*j+1]; if (this.IsEdge[j]){ for (var i=0;i<this.TexCoords.length/2;i++){ var vIx=this.TexCoords[2*i]; var vIy=this.TexCoords[2*i+1]; if (this.IsEdge[i]){ //console.log('index i='+i+' index j='+j); if ( (Math.abs(vJx-vIx)<delta)&&(Math.abs(vJy-vIy)<delta) ){ var a = (this.Vertices[3*i]+this.Vertices[3*j] )/2; var b = (this.Vertices[3*i+1]+this.Vertices[3*j+1] )/2; var c = (this.Vertices[3*i+2]+this.Vertices[3*j+2] )/2; //bad this.Vertices[3*i] = a; this.Vertices[3*i+1] = b; this.Vertices[3*i+2] = c; this.Vertices[3*j] = a; this.Vertices[3*j+1] = b; this.Vertices[3*j+2] = c; this.TexCoords[2*i] = 0; this.TexCoords[2*i+1] =0; this.TexCoords[2*j] = 0; this.TexCoords[2*j+1] =0; //end bad TexCoord[2*i] = 0; TexCoord[2*i+1] = 0; TexCoord[2*j] = 0; TexCoord[2*j+1] = 0; } } } } } */ this.TexCoords = TexCoord; console.log('[DBG] snapped'); } myObject3D.prototype.ComputeTangents = function() { function assignVec3(vec,a,idx){ vec[0]=a[3*idx+0]; vec[1]=a[3*idx+1]; vec[2]=a[3*idx+2]; } function assignVec2(vec,a,idx){ vec[0]=a[2*idx+0]; vec[1]=a[2*idx+1]; } function dot(a,b){ return (a[0]*b[0]+a[1]*b[1]+a[2]*b[2]); } function cross(a,b){ var rtn=vec3.create(); rtn[0]=a[1]*b[2]-a[2]*b[1]; rtn[1]=a[2]*b[0]-a[0]*b[2]; rtn[2]=a[0]*b[1]-a[1]*b[0]; return rtn; } function Normalize(a){ //log('Norm Of:'+a[0]+' '+a[1]+' '+a[2]); var rth = vec3.create(); var no = Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]); var n; if (no == 0){ log('Norm Of:'+a[0]+' '+a[1]+' '+a[2]); //n =0; rth[0]=-1; rth[1]=0; rth[2]=0; return rth; }else{ n = 1.0/no; } //log('n:'+n); rth[0] = a[0]*n; rth[1] = a[1]*n; rth[2] = a[2]*n; //log('Norm Of:'+rth[0]+' '+rth[1]+' '+rth[2]); return rth; } var vtxCount = this.Vertices.length/3; console.log('vtxCount:'+this.Vertices.length); //vtxCount = 6; var triCount = this.TriIndex.length/3; console.log('vtxCount:'+vtxCount); console.log('triCount:'+triCount); var tan1 = []; var tan2 = []; var tangents =[]; for (var a =0; a< vtxCount;a++){ tan1[3*a]=0; tan1[3*a+1]=0; tan1[3*a+2]=0; tan2[3*a]=0; tan2[3*a+1]=0; tan2[3*a+2]=0; } for (var a =0; a< triCount;a++){ var i1 = this.TriIndex[3*a+0]; var i2 = this.TriIndex[3*a+1]; var i3 = this.TriIndex[3*a+2]; // log(' '+i1+' '+i2+' '+i3); var v1 = vec3.create(); var v2 = vec3.create(); var v3 = vec3.create(); assignVec3(v1,this.Vertices,i1); assignVec3(v2,this.Vertices,i2); assignVec3(v3,this.Vertices,i3); var w1= [],w2=[],w3=[]; assignVec2(w1,this.TexCoords,i1); assignVec2(w2,this.TexCoords,i2); assignVec2(w3,this.TexCoords,i3); // log('v1: '+v1[0]+' '+v1[1]+' '+v1[2]); // log('v2: '+v2[0]+' '+v2[1]+' '+v2[2]); // log('v3: '+v3[0]+' '+v3[1]+' '+v3[2]); //log('w1: '+w1[0]+' '+w1[1]); var x1 = v2[0]-v1[0]; var x2 = v3[0]-v1[0]; var y1 = v2[1]-v1[1]; var y2 = v3[1]-v1[1]; var z1 = v2[2]-v1[2]; var z2 = v3[2]-v1[2]; var s1 = w2[0]-w1[0]; var s2 = w3[0]-w1[0]; var t1 = w2[1]-w1[1]; var t2 = w3[1]-w1[1]; /* log('s1: '+s1+' s2: '+s2); log('t1: '+t1+' t2: '+t2); log('s1*t2: '+s1*t2); log('-s2*t1: '+s2*t1); */ var rr = (s1*t2-s2*t1); if (rr==0){ log('rr is NULL'); } var r = 1.0 / rr ; sdir = vec3.create(); tdir = vec3.create(); sdir[0]=(t2 * x1 - t1 * x2) * r; sdir[1]=(t2 * y1 - t1 * y2) * r; sdir[2]=(t2 * z1 - t1 * z2) * r; tdir[0]=(s1 * x2 - s2 * x1) * r; tdir[1]=(s1 * y2 - s2 * y1) * r; tdir[2]=(s1 * z2 - s2 * z1) * r; tan1[3*i1]+=sdir[0]; tan1[3*i1+1]+=sdir[1]; tan1[3*i1+2]+=sdir[2]; tan2[3*i1]+=tdir[0]; tan2[3*i1+1]+=tdir[1]; tan2[3*i1+2]+=tdir[2]; tan1[3*i2]+=sdir[0]; tan1[3*i2+1]+=sdir[1]; tan1[3*i2+2]+=sdir[2]; tan2[3*i2]+=tdir[0]; tan2[3*i2+1]+=tdir[1]; tan2[3*i2+2]+=tdir[2]; tan1[3*i3]+=sdir[0]; tan1[3*i3+1]+=sdir[1]; tan1[3*i3+2]+=sdir[2]; tan2[3*i3]+=tdir[0]; tan2[3*i3+1]+=tdir[1]; tan2[3*i3+2]+=tdir[2]; } for (var a =0; a< vtxCount;a++){ var n = vec3.create(); assignVec3(n,this.Normals,a); var t = vec3.create(); t[0]=tan1[3*a]; t[1]=tan1[3*a+1]; t[2]=tan1[3*a+2]; var f = dot(n,t); //u = cross(t,u); var tangent = vec3.create(); tangent[0]=t[0]-n[0]*f; tangent[1]=t[1]-n[1]*f; tangent[2]=t[2]-n[2]*f; var tan2_a = vec3.create(); tan2_a[0]=tan2[3*a]; tan2_a[1]=tan2[3*a+1]; tan2_a[2]=tan2[3*a+2]; var k = dot(cross(n,t),tan2_a); var w; if (k<0.0){ w = -1.0; }else{ w= 1.0; } //log('tangent ['+a+']: '+tangent[0]+' '+tangent[1]+' '+tangent[2]+' '+w); tangent = Normalize(tangent); //log('tangent Normed ['+a+']: '+tangent[0]+' '+tangent[1]+' '+tangent[2]+' '+w); tangents[4*a]=tangent[0]; tangents[4*a+1]=tangent[1]; tangents[4*a+2]=tangent[2]; tangents[4*a+3]=w; } this.Tangents = tangents; } myObject3D.prototype.SetListsForGL = function(gl) { // assign points triangleVertexIdxPositionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexIdxPositionBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.Vertices), gl.STATIC_DRAW); triangleVertexIdxPositionBuffer.itemSize = 3; triangleVertexIdxPositionBuffer.numItems = this.Vertices.length/3; // assign textures cords triangleVertexTextureCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexTextureCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.TexCoords), gl.STATIC_DRAW); triangleVertexTextureCoordBuffer.itemSize = 2; triangleVertexTextureCoordBuffer.numItems = this.TexCoords.length/2; // assign normals triangleVertexNormalBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexNormalBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.Normals), gl.STATIC_DRAW); triangleVertexNormalBuffer.itemSize = 3; triangleVertexNormalBuffer.numItems = this.Normals.length/3; // assign normals triangleVertexTangentBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexTangentBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.Tangents), gl.STATIC_DRAW); triangleVertexTangentBuffer.itemSize = 4; triangleVertexTangentBuffer.numItems = this.Tangents.length/4; //assign the indexed triangles triangleVertexIndexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleVertexIndexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.TriIndex), gl.STATIC_DRAW); triangleVertexIndexBuffer.itemSize = 1; triangleVertexIndexBuffer.numItems = this.TriIndex.length; //Show report //console.log(' Vertices No:'+Vertex.length/3); //console.log(' Normals No:'+obj.vertexNormals.length/3); //console.log(' Indexed Triangles No:'+indexTr.length/3); } /* // Vertex, Vertex3D,Vertex4D defined somewhere else */ function BaseTriangle2(FaceIndex,ins_obj3D) { this.Model = ins_obj3D; this.FaceIndex = FaceIndex; this.I0 = this.Model.TriIndex[FaceIndex*3]; this.I1 = this.Model.TriIndex[FaceIndex*3+1]; this.I2 = this.Model.TriIndex[FaceIndex*3+2]; // Vertex this.ST0 = this.FetchTextCoord(this.I0); this.ST1 = this.FetchTextCoord(this.I1); this.ST2 = this.FetchTextCoord(this.I2); // Vertex3D this.P0 = this.FetchPosition(this.I0); this.P1 = this.FetchPosition(this.I1); this.P2 = this.FetchPosition(this.I2); // Vertex3D this.N0 = this.FetchNormal(this.I0); this.N1 = this.FetchNormal(this.I1); this.N2 = this.FetchNormal(this.I2); // Vertex4D this.T0 = this.FetchTangent(this.I0); this.T1 = this.FetchTangent(this.I1); this.T2 = this.FetchTangent(this.I2); this.AttachedLst = []; this.AttachedLstInfo = []; } BaseTriangle2.prototype.Show = function() { // Vertex console.log('TexCoords'); this.ST0.Show(); this.ST1.Show(); this.ST2.Show(); // Vertex3D console.log('Positions'); this.P0.Show(); this.P1.Show(); this.P2.Show(); // Vertex3D console.log('Normals'); this.N0.Show(); this.N1.Show(); this.N2.Show(); // Vertex3D console.log('Tangents'); this.T0.Show(); this.T1.Show(); this.T2.Show(); } // we compute the triangle coordonates from the texture coords (core of the tessation method) BaseTriangle2.prototype.ComputeTriangleCoords = function (s,t) { var rtn = new Vertex(0,0); var A = this.ST0; var B = this.ST1; var C = this.ST2; //rejection test: var sMax = Math.max(A.s,Math.max(B.s,C.s)); var tMax = Math.max(A.t,Math.max(B.t,C.t)); var sMin = Math.min(A.s,Math.min(B.s,C.s)); var tMin = Math.min(A.t,Math.min(B.t,C.t)); /* console.log('xMax:'+xMax); console.log('xMin:'+xMin); console.log('yMax:'+yMax); console.log('yMin:'+yMin); */ /* if ( (s>sMin) && (s<sMax) && ( t>tMin) && (t<tMax) ){ //nothing }else{ return false; } */ var P = new Vertex(s,t); function dot( vA, vB){ return (vA.s*vB.s+vA.t*vB.t); } function minus( vA, vB){ return new Vertex(vA.s-vB.s,vA.t-vB.t); } // Compute vectors v0 = minus( C , A); v1 = minus( B , A); v2 = minus( P , A); // Compute dot products dot00 = dot(v0, v0); dot01 = dot(v0, v1); dot02 = dot(v0, v2); dot11 = dot(v1, v1); dot12 = dot(v1, v2); // Compute barycentric coordinates invDenom = 1 / (dot00 * dot11 - dot01 * dot01); u = (dot11 * dot02 - dot01 * dot12) * invDenom; v = (dot00 * dot12 - dot01 * dot02) * invDenom; rtn.s = u; rtn.t = v; //rtn.Show(); return rtn; } // we compute the triangle coordonates from the texture coords (core of the tessation method) BaseTriangle2.prototype.ComputeArea = function () { var A = this.ST0; var B = this.ST1; var C = this.ST2; var rtn; rtn = 0.5*Math.abs((A.s-C.s)*(B.t-A.t)-(A.s-B.s)*(C.t-A.t)); return rtn; } // 0 outside // 1 inside // 2 inside close to 1 or 2 or 3 edge BaseTriangle2.prototype.DecimateVerticesOutsideMainTriangle2 = function (x,y) { var uv = this.ComputeTriangleCoords(x,y); var u = uv.s; var v = uv.t; var EPS = 0.01; // Check if point is in triangle var test = (u >= 0) && (v >= 0) && (u + v < 1); // we add a restriction when getting close to border if ( (test)&& ( (Math.abs((u+v)-1))<EPS )) { //console.log('QUITE CLOSE TO BORDER 3 u='+u+' v='+v); return 2; } if ( (test)&& ( Math.abs(v)<EPS ) ) { //console.log('QUITE CLOSE TO BORDER 2 u='+u+' v='+v); return 2; } if ( (test)&& ( Math.abs(u)<EPS ) ) { //console.log('QUITE CLOSE TO BORDER 1 u='+u+' v='+v); return 2; } if (test) return 1; else return 0; //return test; } BaseTriangle2.prototype.FetchTextCoord = function (Id) { Vtx = new Vertex(this.Model.TexCoords[2*Id],this.Model.TexCoords[2*Id+1]); return Vtx; } BaseTriangle2.prototype.FetchPosition = function (Id) { Vtx = new Vertex3D(this.Model.Vertices[3*Id],this.Model.Vertices[3*Id+1],this.Model.Vertices[3*Id+2]); return Vtx; } BaseTriangle2.prototype.FetchNormal = function (Id) { Vtx = new Vertex3D(this.Model.Normals[3*Id],this.Model.Normals[3*Id+1],this.Model.Normals[3*Id+2]); return Vtx; } BaseTriangle2.prototype.FetchTangent = function (Id) { Vtx = new Vertex4D(this.Model.Tangents[4*Id],this.Model.Tangents[4*Id+1],this.Model.Tangents[4*Id+2],this.Model.Tangents[4*Id+3]); return Vtx; } // the vertices is the list of points's texture coordindates // 2D vertex list extrated from the algo based on normal map BaseTriangle2.prototype.Tessellate = function(myVertices) { // We know the the first triangle is the base triangle // for debug var LstTriangle2D = []; // for debug we add the Base triangle // for debug we add 1 vertex in the center /* var myVertices = []; myVertices.push(this.ST0); myVertices.push(this.ST1); myVertices.push(this.ST2); myVertices.push(this.InterpolateTexCoord(0.5,0.5)); */ LstTriangle2D = Triangulate( myVertices ); //ToDo : compute triangle index list based on vertices var idx = []; for( i in LstTriangle2D ) { var triangle = LstTriangle2D[i]; //triangle.Show(); for(var j=0;j<myVertices.length;j++ ) { vtx = myVertices[j]; //console.log('LookUp'); //triangle.v0.Show(); //console.log('value'); //vtx.Show(); if ( (Math.abs(triangle.v0.s-vtx.s)<EPSILON)&&(Math.abs(triangle.v0.t-vtx.t)<EPSILON)){ //console.log('Bingo @'); idx.push(j); break; } } for(var j=0;j<myVertices.length;j++ ) { vtx = myVertices[j]; if ( (Math.abs(triangle.v1.s-vtx.s)<EPSILON)&&(Math.abs(triangle.v1.t-vtx.t)<EPSILON)){ idx.push(j); break; } } for(var j=0;j<myVertices.length;j++ ) { vtx = myVertices[j]; if ( (Math.abs(triangle.v2.s-vtx.s)<EPSILON)&&(Math.abs(triangle.v2.t-vtx.t)<EPSILON)){ idx.push(j); break; } } } //console.log('IndexList is :'+idx) return idx; } // interpolate values BaseTriangle2.prototype.InterpolateTexCoord= function (u,v) { rtn = new Vertex( this.ST0.s+u*(this.ST2.s-this.ST0.s)+v*(this.ST1.s-this.ST0.s), this.ST0.t+u*(this.ST2.t-this.ST0.t)+v*(this.ST1.t-this.ST0.t) ); return rtn; } BaseTriangle2.prototype.InterpolatePosition = function (u,v) { rtn = new Vertex3D( this.P0.x+u*(this.P2.x-this.P0.x)+v*(this.P1.x-this.P0.x), this.P0.y+u*(this.P2.y-this.P0.y)+v*(this.P1.y-this.P0.y), this.P0.z+u*(this.P2.z-this.P0.z)+v*(this.P1.z-this.P0.z) ); return rtn; } BaseTriangle2.prototype.InterpolateNormal = function (u,v) { rtn = new Vertex3D( this.N0.x+u*(this.N2.x-this.N0.x)+v*(this.N1.x-this.N0.x), this.N0.y+u*(this.N2.y-this.N0.y)+v*(this.N1.y-this.N0.y), this.N0.z+u*(this.N2.z-this.N0.z)+v*(this.N1.z-this.N0.z) ); return rtn; } BaseTriangle2.prototype.InterpolateTangent = function (u,v) { rtn = new Vertex4D( this.T0.x+u*(this.T2.x-this.T0.x)+v*(this.T1.x-this.T0.x), this.T0.y+u*(this.T2.y-this.T0.y)+v*(this.T1.y-this.T0.y), this.T0.z+u*(this.T2.z-this.T0.z)+v*(this.T1.z-this.T0.z), this.T0.w+u*(this.T2.w-this.T0.w)+v*(this.T1.w-this.T0.w) ); return rtn; } //
/* Validated with JSLint, http://www.jslint.com */ //////////////////////////////////////////////////////////////////////////////// // // Delaunay Triangulation Code, by Joshua Bell // // Inspired by: http://www.codeguru.com/cpp/data/mfc_database/misc/article.php/c8901/ // // This work is hereby released into the Public Domain. To view a copy of the public // domain dedication, visit http://creativecommons.org/licenses/publicdomain/ or send // a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, // California, 94105, USA. // //////////////////////////////////////////////////////////////////////////////// var EPSILON = 1.0e-6; var EPSILON2 = 1.0e-12; //------------------------------------------------------------ // BaseTriangle class // the indexes are related to vertex property // list of the Model Golbals // ModelVertices = []; // ModelNormals = []; // ModelTangents = []; // ModelTexCoords = []; // ModelTriIndex = []; //------------------------------------------------------------ function BaseTriangle(FaceIndex) { this.FaceIndex = FaceIndex; this.I0 = ModelTriIndex[FaceIndex*3]; this.I1 = ModelTriIndex[FaceIndex*3+1]; this.I2 = ModelTriIndex[FaceIndex*3+2]; // Vertex this.ST0 = this.FetchTextCoord(this.I0); this.ST1 = this.FetchTextCoord(this.I1); this.ST2 = this.FetchTextCoord(this.I2); // Vertex3D this.P0 = this.FetchPosition(this.I0); this.P1 = this.FetchPosition(this.I1); this.P2 = this.FetchPosition(this.I2); // Vertex3D this.N0 = this.FetchNormal(this.I0); this.N1 = this.FetchNormal(this.I1); this.N2 = this.FetchNormal(this.I2); // Vertex4D this.T0 = this.FetchTangent(this.I0); this.T1 = this.FetchTangent(this.I1); this.T2 = this.FetchTangent(this.I2); this.AttachedLst = []; } BaseTriangle.prototype.Show = function() { // Vertex console.log('TexCoords'); this.ST0.Show(); this.ST1.Show(); this.ST2.Show(); // Vertex3D console.log('Positions'); this.P0.Show(); this.P1.Show(); this.P2.Show(); // Vertex3D console.log('Normals'); this.N0.Show(); this.N1.Show(); this.N2.Show(); // Vertex3D console.log('Tangents'); this.T0.Show(); this.T1.Show(); this.T2.Show(); } BaseTriangle.prototype.FetchTextCoord = function (Id) { Vtx = new Vertex(ModelTexCoords[2*Id],ModelTexCoords[2*Id+1]); return Vtx; } BaseTriangle.prototype.FetchPosition = function (Id) { Vtx = new Vertex3D(ModelVertices[3*Id],ModelVertices[3*Id+1],ModelVertices[3*Id+2]); return Vtx; } BaseTriangle.prototype.FetchNormal = function (Id) { Vtx = new Vertex3D(ModelNormals[3*Id],ModelNormals[3*Id+1],ModelNormals[3*Id+2]); return Vtx; } BaseTriangle.prototype.FetchTangent = function (Id) { Vtx = new Vertex4D(ModelTangents[4*Id],ModelTangents[4*Id+1],ModelTangents[4*Id+2],ModelTangents[4*Id+3]); return Vtx; } // we compute the triangle coordonates from the texture coords (core of the tessation method) BaseTriangle.prototype.ComputeArea = function () { var A = this.ST0; var B = this.ST1; var C = this.ST2; var rtn; rtn = 0.5*Math.abs((A.s-C.s)*(B.t-A.t)-(A.s-B.s)*(C.t-A.t)); return rtn; } // we compute the triangle coordonates from the texture coords (core of the tessation method) BaseTriangle.prototype.ComputeTriangleCoords = function (s,t) { var rtn = new Vertex(0,0); var A = this.ST0; var B = this.ST1; var C = this.ST2; //rejection test: var sMax = Math.max(A.s,Math.max(B.s,C.s)); var tMax = Math.max(A.t,Math.max(B.t,C.t)); var sMin = Math.min(A.s,Math.min(B.s,C.s)); var tMin = Math.min(A.t,Math.min(B.t,C.t)); /* console.log('xMax:'+xMax); console.log('xMin:'+xMin); console.log('yMax:'+yMax); console.log('yMin:'+yMin); */ /* if ( (s>sMin) && (s<sMax) && ( t>tMin) && (t<tMax) ){ //nothing }else{ return false; } */ var P = new Vertex(s,t); function dot( vA, vB){ return (vA.s*vB.s+vA.t*vB.t); } function minus( vA, vB){ return new Vertex(vA.s-vB.s,vA.t-vB.t); } // Compute vectors v0 = minus( C , A); v1 = minus( B , A); v2 = minus( P , A); // Compute dot products dot00 = dot(v0, v0); dot01 = dot(v0, v1); dot02 = dot(v0, v2); dot11 = dot(v1, v1); dot12 = dot(v1, v2); // Compute barycentric coordinates invDenom = 1 / (dot00 * dot11 - dot01 * dot01); u = (dot11 * dot02 - dot01 * dot12) * invDenom; v = (dot00 * dot12 - dot01 * dot02) * invDenom; rtn.s = u; rtn.t = v; //rtn.Show(); return rtn; } //will return a list of vertices based on the image processing BaseTriangle.prototype.createVerticesFromNormalMap = function(data,H,W){ var rtn = [] // quickly iterate over all pixels var cpt = 0; var discardRate = 0; var discardRateM = 0;//32 var IsInside = new Boolean(); // get the base triangle info height = H; width = W; var MaxRho2 = -1; for(var i = 0, n = data.length; i < n; i += 4) { var red = data[i]; var green = data[i + 1]; //var blue = data[i + 2]; //var alpha = data[i + 3]; var threshold = 0.0001; var y = Math.floor((i/4)/height); var x = (i/4)-y*width; //console.log('===x'+x+' ===y'+y); function computeVoisin(xn,yn){ var dx = 0; var dy = 0; var xp1 =0; var yp1 = 0; var xn1 =0; var yn1 = 0; if (x<(W-1)){ var xp1 = x+1; } if (y<(H-1)){ var yp1 = y+1; } if (x>1){ var xn1 = x-1; } if (y>1){ var yn1 = y-1; } var ii = 4*((yp1*width)+xp1); var redP1 = data[ii]; var greenP1 =data[ii+1]; //console.log('ii='+ii); //console.log('red='+red+' red1='+redP1); //console.log('green='+green+' greenP1='+greenP1) var XPn = 2*(redP1/255)-1.0; var YPn = 2*(greenP1/255)-1.0; //-- Other voisin var iii = 4*((yn1*width)+xn1); var redN1 = data[iii]; var greenN1 =data[iii+1]; //console.log('ii='+ii); //console.log('red='+red+' red1='+redP1); //console.log('green='+green+' greenP1='+greenP1) var XNn = 2*(redN1/255)-1.0; var YNn = 2*(greenN1/255)-1.0; dx = XPn-XNn; dy = YPn-YNn; return (dx*dx + dy*dy); //return (Xn*Xn + Yn*Yn); } var s = x/height; var t = y/width; //IsInside = this.DecimateVerticesOutsideMainTriangle(s,t); var IsInsideVal = this.DecimateVerticesOutsideMainTriangle2(s,t); //IsInside = true; if (IsInsideVal==1){ //console.log('===x'+x+' ===y'+y); //console.log('====['+i+']='+'r:'+red+'g:'+green+'b:'+blue); var Xn = 2*(red/255)-1.0; var Yn = 2*(green/255)-1.0; //var Zn = (blue-127)/127; //console.log('====['+i+']='+' Zn:'+Zn); //if ( (Math.abs(Xn)>threshold) && (Math.abs(Yn)>threshold) ){ //if ( (Math.abs(Xn)>threshold) || (Math.abs(Yn)>threshold) ){ var Rho2 = Xn*Xn + Yn*Yn; ///discardRate = discardRateM*(Rho2)*(Rho2); MaxRho2 = Math.max(MaxRho2,Rho2); //console.log('MaxRho2:'+MaxRho2); //if ( Rho2 > 0.051 ){ // 0.2 ////var Rho2V = computeVoisin(Xn,Yn); ///var diffRho2 = Math.abs(Rho2V-Rho2); var diffRho2 = computeVoisin(Xn,Yn); //console.log('diffRho2:'+diffRho2); //if ( Rho2 > 0.2001){ if (diffRho2 > 0.01){// good 0.35 //if (diffRho2 > 0.4){// good 0.35 (other method) //console.log('===x'+x+' ===y'+y); //if ( (cpt>discardRate) || (Rho2>0.8) ) if ( cpt>discardRate) { rtn.push(new Vertex(s,t)); cpt=0; } } }else if (IsInsideVal==2) { // This is solving the cracks problem but with quite a high price of extra polys //console.log('special'); rtn.push(new Vertex(s,t)); } cpt++; } return rtn; } //------------------------------------------------------------------------------ // -- old //will return a list of vertices based on the image processing BaseTriangle.prototype.createVerticesFromNormalMapOld = function(data,H,W){ var rtn = [] // quickly iterate over all pixels var cpt = 0; var discardRate = 0; var discardRateM = 2;//32 var IsInside = new Boolean(); // get the base triangle info height = H; width = W; var MaxRho2 = -1; for(var i = 0, n = data.length; i < n; i += 4) { var red = data[i]; var green = data[i + 1]; //var blue = data[i + 2]; //var alpha = data[i + 3]; var threshold = 0.0001; var y = Math.floor((i/4)/height); var x = (i/4)-y*width; //console.log('===x'+x+' ===y'+y); var s = x/height; var t = y/width; IsInside = this.DecimateVerticesOutsideMainTriangle(s,t); //IsInside = true; if (IsInside){ //console.log('===x'+x+' ===y'+y); //console.log('====['+i+']='+'r:'+red+'g:'+green+'b:'+blue); var Xn = 2*(red/255)-1.0; var Yn = 2*(green/255)-1.0; //var Zn = (blue-127)/127; //console.log('====['+i+']='+' Zn:'+Zn); //if ( (Math.abs(Xn)>threshold) && (Math.abs(Yn)>threshold) ){ //if ( (Math.abs(Xn)>threshold) || (Math.abs(Yn)>threshold) ){ var Rho2 = Xn*Xn + Yn*Yn; discardRate = discardRateM*(Rho2); MaxRho2 = Math.max(MaxRho2,Rho2); //console.log('MaxRho2:'+MaxRho2); //if ( Rho2 > 0.051 ){ // 0.2 if ( Rho2 > 0.0001){ //console.log('===x'+x+' ===y'+y); //if ( (cpt>discardRate) || (Rho2>0.8) ) if ( cpt>discardRate) { rtn.push(new Vertex(s,t)); cpt=0; } } } cpt++; } return rtn; } // interpolate values BaseTriangle.prototype.InterpolateTexCoord= function (u,v) { rtn = new Vertex( this.ST0.s+u*(this.ST2.s-this.ST0.s)+v*(this.ST1.s-this.ST0.s), this.ST0.t+u*(this.ST2.t-this.ST0.t)+v*(this.ST1.t-this.ST0.t) ); return rtn; } BaseTriangle.prototype.InterpolatePosition = function (u,v) { rtn = new Vertex3D( this.P0.x+u*(this.P2.x-this.P0.x)+v*(this.P1.x-this.P0.x), this.P0.y+u*(this.P2.y-this.P0.y)+v*(this.P1.y-this.P0.y), this.P0.z+u*(this.P2.z-this.P0.z)+v*(this.P1.z-this.P0.z) ); return rtn; } BaseTriangle.prototype.InterpolateNormal = function (u,v) { rtn = new Vertex3D( this.N0.x+u*(this.N2.x-this.N0.x)+v*(this.N1.x-this.N0.x), this.N0.y+u*(this.N2.y-this.N0.y)+v*(this.N1.y-this.N0.y), this.N0.z+u*(this.N2.z-this.N0.z)+v*(this.N1.z-this.N0.z) ); return rtn; } BaseTriangle.prototype.InterpolateTangent = function (u,v) { rtn = new Vertex4D( this.T0.x+u*(this.T2.x-this.T0.x)+v*(this.T1.x-this.T0.x), this.T0.y+u*(this.T2.y-this.T0.y)+v*(this.T1.y-this.T0.y), this.T0.z+u*(this.T2.z-this.T0.z)+v*(this.T1.z-this.T0.z), this.T0.w+u*(this.T2.w-this.T0.w)+v*(this.T1.w-this.T0.w) ); return rtn; } BaseTriangle.prototype.DecimateVerticesOutsideMainTriangle = function (x,y) { var uv = this.ComputeTriangleCoords(x,y); var u = uv.s; var v = uv.t; // we add a restriction when getting close to border // Check if point is in triangle return (u >= 0) && (v >= 0) && (u + v < 1) } // 0 outside // 1 inside // 2 inside close to 1 or 2 or 3 edge BaseTriangle.prototype.DecimateVerticesOutsideMainTriangle2 = function (x,y) { var uv = this.ComputeTriangleCoords(x,y); var u = uv.s; var v = uv.t; var EPS = 0.01; // Check if point is in triangle var test = (u >= 0) && (v >= 0) && (u + v < 1); // we add a restriction when getting close to border if ( (test)&& ( (Math.abs((u+v)-1))<EPS )) { //console.log('QUITE CLOSE TO BORDER 3 u='+u+' v='+v); return 2; } if ( (test)&& ( Math.abs(v)<EPS ) ) { //console.log('QUITE CLOSE TO BORDER 2 u='+u+' v='+v); return 2; } if ( (test)&& ( Math.abs(u)<EPS ) ) { //console.log('QUITE CLOSE TO BORDER 1 u='+u+' v='+v); return 2; } if (test) return 1; else return 0; //return test; } // the vertices is the list of points's texture coordindates // 2D vertex list extrated from the algo based on normal map BaseTriangle.prototype.Tessellate = function(myVertices) { // We know the the first triangle is the base triangle // for debug var LstTriangle2D = []; // for debug we add the Base triangle // for debug we add 1 vertex in the center /* var myVertices = []; myVertices.push(this.ST0); myVertices.push(this.ST1); myVertices.push(this.ST2); myVertices.push(this.InterpolateTexCoord(0.5,0.5)); */ LstTriangle2D = Triangulate( myVertices ); //ToDo : compute triangle index list based on vertices var idx = []; for( i in LstTriangle2D ) { var triangle = LstTriangle2D[i]; //triangle.Show(); for(var j=0;j<myVertices.length;j++ ) { vtx = myVertices[j]; //console.log('LookUp'); //triangle.v0.Show(); //console.log('value'); //vtx.Show(); if ( (Math.abs(triangle.v0.s-vtx.s)<EPSILON)&&(Math.abs(triangle.v0.t-vtx.t)<EPSILON)){ //console.log('Bingo @'); idx.push(j); break; } } for(var j=0;j<myVertices.length;j++ ) { vtx = myVertices[j]; if ( (Math.abs(triangle.v1.s-vtx.s)<EPSILON)&&(Math.abs(triangle.v1.t-vtx.t)<EPSILON)){ idx.push(j); break; } } for(var j=0;j<myVertices.length;j++ ) { vtx = myVertices[j]; if ( (Math.abs(triangle.v2.s-vtx.s)<EPSILON)&&(Math.abs(triangle.v2.t-vtx.t)<EPSILON)){ idx.push(j); break; } } } //console.log('IndexList is :'+idx) return idx; } function Vertex4D( x, y, z, w ) { this.x = x; this.y = y; this.z = z; this.w = w; } // Vertex4D Vertex4D.prototype.Show = function() { console.log('--- Verbose ---'); console.log('= x: '+this.x); console.log('= y: '+this.y); console.log('= z: '+this.z); console.log('= w: '+this.w); } function Vertex3D( x, y, z ) { this.x = x; this.y = y; this.z = z; } // Vertex3D Vertex3D.prototype.Show = function() { console.log('--- Verbose ---'); console.log('= x: '+this.x); console.log('= y: '+this.y); console.log('= z: '+this.z); } Vertex3D.prototype.Normalize= function() { var a = this.x; var b = this.y; var c = this.z; var sq = a*a+b*b+c*c; /* if ( sq <EPSILON2 ){ alert("normal TOO SMALL"); }else */ { invnorm = 1/Math.sqrt(sq); this.x = a*invnorm; this.y = b*invnorm; this.z = c*invnorm; } } //------------------------------------------------------------ // Vertex class //------------------------------------------------------------ function Vertex( s, t ) { this.s = s; this.t = t; } // Vertex /* Vertex.prototype.dot( var Vertex vA, var Vertex vB){ return (vA.x*vB.x+vA.t*vB.t); } */ Vertex.prototype.Show = function() { console.log('--- Verbose ---'); console.log('= s: '+this.s); console.log('= t: '+this.t); } //------------------------------------------------------------ // Triangle class (2D) //------------------------------------------------------------ function Triangle( v0, v1, v2 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; this.CalcCircumcircle(); } // Triangle Triangle.prototype.Show = function() { console.log('Triangle'); this.v0.Show(); this.v1.Show(); this.v2.Show(); } Triangle.prototype.CalcCircumcircle = function() { // From: http://www.exaflop.org/docs/cgafaq/cga1.html var A = this.v1.s - this.v0.s; var B = this.v1.t - this.v0.t; var C = this.v2.s - this.v0.s; var D = this.v2.t - this.v0.t; var E = A*(this.v0.s + this.v1.s) + B*(this.v0.t + this.v1.t); var F = C*(this.v0.s + this.v2.s) + D*(this.v0.t + this.v2.t); var G = 2.0*(A*(this.v2.t - this.v1.t)-B*(this.v2.s - this.v1.s)); var ds, dt; if( Math.abs(G) < EPSILON ) { // Collinear - find extremes and use the midpoint function max3( a, b, c ) { return ( a >= b && a >= c ) ? a : ( b >= a && b >= c ) ? b : c; } function min3( a, b, c ) { return ( a <= b && a <= c ) ? a : ( b <= a && b <= c ) ? b : c; } var mins = min3( this.v0.s, this.v1.s, this.v2.s ); var mint = min3( this.v0.t, this.v1.t, this.v2.t ); var maxs = max3( this.v0.s, this.v1.s, this.v2.s ); var maxt = max3( this.v0.t, this.v1.t, this.v2.t ); this.center = new Vertex( ( mins + maxs ) / 2, ( mint + maxt ) / 2 ); ds = this.center.s - mins; dt = this.center.t - mint; } else { var cs = (D*E - B*F) / G; var ct = (A*F - C*E) / G; this.center = new Vertex( cs, ct ); ds = this.center.s - this.v0.s; dt = this.center.t - this.v0.t; } this.radius_squared = ds * ds + dt * dt; this.radius = Math.sqrt( this.radius_squared ); }; // CalcCircumcircle Triangle.prototype.InCircumcircle = function( v ) { var ds = this.center.s - v.s; var dt = this.center.t - v.t; var dist_squared = ds * ds + dt * dt; return ( dist_squared <= this.radius_squared ); }; // InCircumcircle //------------------------------------------------------------ // Edge class //------------------------------------------------------------ function Edge( v0, v1 ) { this.v0 = v0; this.v1 = v1; } // Edge //------------------------------------------------------------ // Triangulate2 // // Perform the Delaunay Triangulation of a set of vertices. // // vertices: Array of Vertex objects // // returns: Array of Index //------------------------------------------------------------ // the first 3 vertices are the model triangles function Triangulate2( vertices ) { var Tri = Triangulate(vertices); } //------------------------------------------------------------ // Triangulate // // Perform the Delaunay Triangulation of a set of vertices. // // vertices: Array of Vertex objects // // returns: Array of Triangles //------------------------------------------------------------ function Triangulate( vertices ) { var triangles = []; // // First, create a "supertriangle" that bounds all vertices // var st = CreateBoundingTriangle( vertices ); triangles.push( st ); // // Next, begin the triangulation one vertex at a time // var i; for( i in vertices ) { // NOTE: This is O(n^2) - can be optimized by sorting vertices // along the x-axis and only considering triangles that have // potentially overlapping circumcircles var vertex = vertices[i]; AddVertex( vertex, triangles ); } // // Remove triangles that shared edges with "supertriangle" // for( i in triangles ) { var triangle = triangles[i]; if( triangle.v0 == st.v0 || triangle.v0 == st.v1 || triangle.v0 == st.v2 || triangle.v1 == st.v0 || triangle.v1 == st.v1 || triangle.v1 == st.v2 || triangle.v2 == st.v0 || triangle.v2 == st.v1 || triangle.v2 == st.v2 ) { delete triangles[i]; } } // loop up to provide an indexed triangle list return triangles; } // Triangulate // Internal: create a triangle that bounds the given vertices, with room to spare function CreateBoundingTriangle( vertices ) { // NOTE: There's a bit of a heuristic here. If the bounding triangle // is too large and you see overflow/underflow errors. If it is too small // you end up with a non-convex hull. var mins, mint, maxs, maxt; for( var i in vertices ) { var vertex = vertices[i]; if( mins === undefined || vertex.s < mins ) { mins = vertex.s; } if( mint === undefined || vertex.t < mint ) { mint = vertex.t; } if( maxs === undefined || vertex.s > maxs ) { maxs = vertex.s; } if( maxt === undefined || vertex.t > maxt ) { maxt = vertex.t; } } var ds = ( maxs - mins ) * 10; var dt = ( maxt - mint ) * 10; var stv0 = new Vertex( mins - ds, mint - dt*3 ); var stv1 = new Vertex( mins - ds, maxt + dt ); var stv2 = new Vertex( maxs + ds*3, maxt + dt ); return new Triangle( stv0, stv1, stv2 ); } // CreateBoundingTriangle // Internal: update triangulation with a vertex function AddVertex( vertex, triangles ) { var edges = []; // Remove triangles with circumcircles containing the vertex var i; for( i in triangles ) { var triangle = triangles[i]; if( triangle.InCircumcircle( vertex ) ) { edges.push( new Edge( triangle.v0, triangle.v1 ) ); edges.push( new Edge( triangle.v1, triangle.v2 ) ); edges.push( new Edge( triangle.v2, triangle.v0 ) ); delete triangles[i]; } } edges = UniqueEdges( edges ); // Create new triangles from the unique edges and new vertex for( i in edges ) { var edge = edges[i]; triangles.push( new Triangle( edge.v0, edge.v1, vertex ) ); } } // AddVertex // Internal: remove duplicate edges from an array function UniqueEdges( edges ) { // TODO: This is O(n^2), make it O(n) with a hash or some such var uniqueEdges = []; for( var i in edges ) { var edge1 = edges[i]; var unique = true; for( var j in edges ) { if( i != j ) { var edge2 = edges[j]; if( ( edge1.v0 == edge2.v0 && edge1.v1 == edge2.v1 ) || ( edge1.v0 == edge2.v1 && edge1.v1 == edge2.v0 ) ) { unique = false; break; } } } if( unique ) { uniqueEdges.push( edge1 ); } } return uniqueEdges; } // UniqueEdges



댓글

이 블로그의 인기 게시물

About AActor!!! "UObject" has no member "BeginPlay"

UNREAL Android build information

C++ 생성자 위임 (delegating constructor)