pbrtools
Version:
laya pbr tools
207 lines (192 loc) • 7.03 kB
text/typescript
export class geo_Vertex{
edge:number[]=[];
face:number[]=[];
}
export class geo_Edge{
v0:number;
v1:number;
}
export class MeshGeo{
vb:Float32Array;
ib:Uint16Array;
vertexnum=0;
fstride=0;
attrib:string;
//faces:geo_Face[]; face直接用ib即可
uvfoff=0;//uv在floatarray的偏移。不是byte,是float
normoff=3;
vertexes:geo_Vertex[];
edges:geo_Edge[];
tmpMem=new Float32Array(32);
tmpMem1=new Float32Array(32);
TB = new Float32Array(6);
/**
*
* @param vb
* @param ib
* @param fstride {number} vertex的float个数。即vertex的stride/4。 用来计算顶点个数和确定xyz的位置(每个点的前3个)
* @param uvoff {number} 用来取出每个点的uv
* @param attrib {string} 目前没有用上。
*/
constructor(vb:Float32Array, ib:Uint16Array, fstride:number, uvoff:number, attrib:string){
this.vb=vb;
this.ib=ib;
this.fstride=fstride;
this.attrib=attrib;
this.uvfoff=uvoff;
this.vertexnum = vb.length/fstride;
this.gatherInfo();
}
gatherInfo(){
this.vertexes = new Array<geo_Vertex>(this.vertexnum).fill(new geo_Vertex());
this.vertexes.forEach((v,i)=>{
v = this.vertexes[i]=new geo_Vertex();//每个都要是不同的实例。
var st=0;
while(true){
var vpos = this.ib.indexOf(i,st);
if(vpos>=0){
st=vpos+1;
var fid = Math.floor(vpos/3);
if(v.face.indexOf(fid)<0){
v.face.push(fid);
}
}
else{
break;
}
}
});
}
/**
*
* @param verts
* @param p0
* @param p1
* @param p2
* @param uv0 {number} uv0的起点的偏移,单位是float
* @param uv1
* @param uv2
* @param normal
* @param outverts
* @param tangent
* @param binormal
*/
_calcTangent( verts:Float32Array, p0:number, p1:number, p2:number,
uv0:number, uv1:number, uv2:number,
normal:number,
outverts:Float32Array,
tangent:number, binormal:number){
this.TB.fill(0);
var tb=this.TB;
var dx0=verts[p1]- verts[p0]; var dy0=verts[p1+1]-verts[p0+1]; var dz0 = verts[p1+2]-verts[p0+2];
var dx1=verts[p2]- verts[p0]; var dy1=verts[p2+1]-verts[p0+1]; var dz1 = verts[p2+2]-verts[p0+2];
var du0=verts[uv1]-verts[uv0]; var dv0 = verts[uv1+1]-verts[uv0+1];
var du1=verts[uv2]-verts[uv0]; var dv1 = verts[uv2+1]-verts[uv0+1];
var fenmu = du0*dv1-du1*dv0; //这个分母不能忽略,决定了正负
if(fenmu>0){
tb[0] = dx0*dv1-dx1*dv0; tb[1] = dy0*dv1-dy1*dv0; tb[2] = dz0*dv1-dz1*dv0;
tb[3] = -dx0*du1+dx1*du0; tb[4] = -dy0*du1+dy1*du0; tb[5] = -dz0*du1+dz1*du0;
}else{
tb[0] = -dx0*dv1+dx1*dv0; tb[1] = -dy0*dv1+dy1*dv0; tb[2] = -dz0*dv1+dz1*dv0;
tb[3] = dx0*du1-dx1*du0; tb[4] = dy0*du1-dy1*du0; tb[5] = dz0*du1-dz1*du0;
}
this.vec3_normalize(tb,0);
this.vec3_normalize(tb,3);
//console.log(tb[0],tb[1],tb[2]);console.log(tb[3],tb[4],tb[5]);
this.vec3_cross(tb,0,3);
var tdb = this.tmpMem[0]*verts[normal] + this.tmpMem[1]*verts[normal+1] + this.tmpMem[2]*verts[normal+2];
if(tdb<0.0){
//tb.forEach((v,i)=>{tb[i]=-tb[i];});
}
outverts[tangent]=tb[0]; outverts[tangent+1]=tb[1]; outverts[tangent+2]=tb[2];
outverts[binormal]=tb[3]; outverts[binormal+1]=tb[4]; outverts[binormal+2]=tb[5];
return true;
}
vec3_cross(vb:Float32Array, v0:number, v1:number){
var ax = vb[v0], ay=vb[v0+1], az=vb[v0+2];
var bx = vb[v1], by=vb[v1+1], bz=vb[v1+2];
this.tmpMem[0] = ay * bz - az * by;
this.tmpMem[1] = az * bx - ax * bz;
this.tmpMem[2] = ax * by - ay * bx;
}
vec3_length(vb:Float32Array, v0:number){
var x = vb[v0];
var y = vb[v0+1];
var z = vb[v0+2];
var l = x*x+y*y+z*z;
return Math.sqrt(l);
}
vec3_normalize(vb:Float32Array, v0){
var l = this.vec3_length(vb,v0);
if(l<1e-9){
vb[v0]=0;
vb[v0+1]=0;
vb[v0+2]=0;
return;
}
vb[v0]/=l;
vb[v0+1]/=l;
vb[v0+2]/=l;
}
vec3_copy(vbo:Float32Array, v1:number, vb:Float32Array, v0:number ){
vbo[v1]=vb[v0];
vbo[v1+1]=vb[v0+1];
vbo[v1+2]=vb[v0+2];
}
/**
* 返回tangent和binormal
*/
calcTangent(){
var ret={tan:new Float32Array(this.vertexnum*3), binor:new Float32Array(this.vertexnum*3)};
this.vertexes.forEach((v,i)=>{
var sum=0;
//
var outarr = new Float32Array(6).fill(0);
v.face.forEach((ef,fi)=>{
var cout = new Float32Array(6);
var v0=this.ib[ef*3];
var v1=this.ib[ef*3+1];
var v2=this.ib[ef*3+2];
/* 加上这个效果就全错了
if(v1==i){
[v0,v1]=[v1,v0];
}
else if(v2==i){
[v0,v2]=[v2,v0];
}
*/
var v0p = v0*this.fstride;
var v1p = v1*this.fstride;
var v2p = v2*this.fstride;
if(!this._calcTangent(this.vb,
v0p, v1p,v2p,
v0p+this.uvfoff, v1p+this.uvfoff,v2p+this.uvfoff,
this.normoff,cout,0,3))
return ;
var dbuff = this.tmpMem1;
dbuff[0]=this.vb[v1p ]-this.vb[v0p ];//dx
dbuff[1]=this.vb[v1p+1]-this.vb[v0p+1];//dy
dbuff[2]=this.vb[v1p+2]-this.vb[v0p+2];//dz
dbuff[3]=this.vb[v2p ]-this.vb[v0p ];//dx1
dbuff[4]=this.vb[v2p+1]-this.vb[v0p+1];//dy1
dbuff[5]=this.vb[v2p+2]-this.vb[v0p+2];//dz1
this.vec3_cross(dbuff,0,3);
var l = this.vec3_length(this.tmpMem,0);
for(var oi=0; oi<6; oi++){
outarr[oi]+=cout[oi]*l;
}
sum+=l;
});
/*
for(var oi=0; oi<6; oi++){
outarr[oi]=outarr[oi]/sum;
}
*/
this.vec3_normalize(outarr,0);
this.vec3_normalize(outarr,3);
this.vec3_copy(ret.tan,i*3, outarr,0);
this.vec3_copy(ret.binor,i*3, outarr,3);
});
return ret;
}
}