pbrtools
Version:
laya pbr tools
203 lines (202 loc) • 7.22 kB
JavaScript
"use strict";
class geo_Vertex {
constructor() {
this.edge = [];
this.face = [];
}
}
exports.geo_Vertex = geo_Vertex;
class geo_Edge {
}
exports.geo_Edge = geo_Edge;
class MeshGeo {
/**
*
* @param vb
* @param ib
* @param fstride {number} vertex的float个数。即vertex的stride/4。 用来计算顶点个数和确定xyz的位置(每个点的前3个)
* @param uvoff {number} 用来取出每个点的uv
* @param attrib {string} 目前没有用上。
*/
constructor(vb, ib, fstride, uvoff, attrib) {
this.vertexnum = 0;
this.fstride = 0;
//faces:geo_Face[]; face直接用ib即可
this.uvfoff = 0; //uv在floatarray的偏移。不是byte,是float
this.normoff = 3;
this.tmpMem = new Float32Array(32);
this.tmpMem1 = new Float32Array(32);
this.TB = new Float32Array(6);
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(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, p0, p1, p2, uv0, uv1, uv2, normal, outverts, tangent, binormal) {
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) {
}
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, v0, v1) {
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, v0) {
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, 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, v1, vb, v0) {
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;
}
}
exports.MeshGeo = MeshGeo;